From 0facb885101e37e5cbb07221f7a1a3e27633e42f Mon Sep 17 00:00:00 2001 From: ghorbani Date: Sat, 1 Aug 2026 15:41:10 +0330 Subject: [PATCH] feat: implement core marriage matching application architecture including UI components, question workflows, and multi-language support. --- next.config.ts | 8 +- public/openapi.json | 22668 +++++++++++++++- src/app/[lang]/layout.tsx | 4 +- src/app/[lang]/questions-list/[slug]/page.tsx | 2 +- src/app/[lang]/test-webview/page.tsx | 14 +- src/app/api/dev-storage/route.ts | 7 +- src/app/api/open-in-ide/route.ts | 10 +- src/app/api/proxy/route.ts | 2 - src/app/api/remote-logs/route.ts | 6 +- src/app/api/remote-network/route.ts | 29 +- src/app/candidate-contact/page.tsx | 2 +- src/app/finding-match/page.tsx | 8 +- src/app/globals.css | 21 +- src/app/intro/page.tsx | 21 +- src/app/layout.tsx | 5 +- src/app/new-match/page.tsx | 57 +- src/app/new-match/profile/page.tsx | 10 +- src/app/providers.tsx | 16 +- .../[slug]/answer-pace-sheet.tsx | 5 +- .../[slug]/question-detail-client.tsx | 54 +- .../[slug]/test-intro-client.tsx | 2 +- src/app/questions-list/page.tsx | 29 +- src/app/request-accepted/page.tsx | 59 +- src/app/request-sent/page.tsx | 23 +- src/components/dev/dev-click-to-component.tsx | 199 +- src/components/questions/progress-helper.ts | 74 +- .../questions/question-answer-storage.tsx | 24 +- .../questions/question-birthplace.tsx | 716 + src/components/questions/question-card.tsx | 2 +- src/components/questions/question-date.tsx | 25 +- .../questions/question-dropdown.tsx | 69 +- .../question-exit-navigation-button.tsx | 2 +- src/components/questions/question-file.tsx | 18 +- src/components/questions/question-number.tsx | 33 +- src/components/questions/question-phone.tsx | 352 +- src/components/questions/question-photo.tsx | 22 +- .../questions/question-progress-tracker.tsx | 2 +- .../questions/question-section-flow.tsx | 11 +- src/components/questions/question-slider.tsx | 8 +- .../questions/question-snap-list.tsx | 39 +- src/components/questions/question-text.tsx | 11 +- src/components/questions/question-title.tsx | 15 +- .../questions/required-steps-card.tsx | 19 +- .../questions/test-loading-screen.tsx | 36 +- .../questions/test-questions-flow.tsx | 16 +- src/components/sliders/slider-page.tsx | 2 +- src/components/sliders/slider-slide-four.tsx | 8 +- src/components/sliders/slider-slide-one.tsx | 24 +- src/components/sliders/slider-slide-two.tsx | 4 +- src/components/ui/button.tsx | 4 +- src/components/ui/female-consent-sheet.tsx | 9 +- src/components/ui/help-modal.tsx | 15 +- src/components/ui/navigation-button.tsx | 8 +- src/components/ui/report-actions-sheet.tsx | 45 +- src/components/ui/token-switcher.tsx | 4 +- .../utils/dev-click-to-component.tsx | 5 +- src/components/utils/fixed-bottom.tsx | 5 +- src/data/cattell-fallback.ts | 2024 +- src/data/countries.ts | 401 + src/data/glasser-fallback.ts | 72 +- src/data/languages.ts | 157 + src/data/nationalities.ts | 283 + src/data/question-data.ts | 10 +- src/data/questions/en.json | 660 +- src/data/questions/fa.json | 660 +- src/hooks/marriage/query-keys.ts | 14 +- src/hooks/marriage/types.ts | 10 +- src/hooks/marriage/use-section-data.ts | 3 +- src/hooks/use-close-service-on-back.ts | 6 +- src/hooks/useFlutterBridge.ts | 114 +- src/lib/auth-bridge.ts | 17 +- src/lib/http.ts | 6 +- src/lib/performance.ts | 24 +- src/lib/view-paddings.ts | 26 +- src/plugins/jsx-locator-loader.cjs | 4 +- src/translations/dictionaries.ts | 5 +- src/translations/locales/ar.json | 4 +- src/translations/locales/az.json | 4 +- src/translations/locales/bn.json | 4 +- src/translations/locales/da.json | 4 +- src/translations/locales/de.json | 4 +- src/translations/locales/en.json | 4 +- src/translations/locales/es.json | 4 +- src/translations/locales/fa.json | 4 +- src/translations/locales/fr.json | 4 +- src/translations/locales/gu.json | 4 +- src/translations/locales/ha.json | 4 +- src/translations/locales/he.json | 4 +- src/translations/locales/hi.json | 4 +- src/translations/locales/id.json | 4 +- src/translations/locales/ks.json | 4 +- src/translations/locales/pt.json | 4 +- src/translations/locales/ru.json | 4 +- src/translations/locales/sw.json | 4 +- src/translations/locales/tg.json | 4 +- src/translations/locales/tr.json | 4 +- src/translations/locales/ul.json | 4 +- src/translations/locales/ur.json | 4 +- src/translations/locales/uz.json | 4 +- src/translations/locales/zh.json | 4 +- src/translations/provider.tsx | 6 +- src/view-paddings.ts | 2 +- 102 files changed, 26606 insertions(+), 2882 deletions(-) create mode 100644 src/components/questions/question-birthplace.tsx create mode 100644 src/data/countries.ts create mode 100644 src/data/languages.ts create mode 100644 src/data/nationalities.ts diff --git a/next.config.ts b/next.config.ts index e74a59d..905b4b6 100644 --- a/next.config.ts +++ b/next.config.ts @@ -28,7 +28,10 @@ const nextConfig: NextConfig = { exclude: /node_modules/, use: [ { - loader: path.resolve(__dirname, "src/plugins/jsx-locator-loader.cjs"), + loader: path.resolve( + __dirname, + "src/plugins/jsx-locator-loader.cjs", + ), }, ], }); @@ -45,7 +48,8 @@ const nextConfig: NextConfig = { headers: [ { key: "Cache-Control", - value: "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0", + value: + "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0", }, { key: "Pragma", diff --git a/public/openapi.json b/public/openapi.json index 92c6935..1a1bead 100644 --- a/public/openapi.json +++ b/public/openapi.json @@ -1 +1,22667 @@ -{"swagger": "2.0", "info": {"title": "Snippets API", "description": "Project API Documentation", "termsOfService": "https://www.google.com/policies/terms/", "contact": {"email": "nwhco.com"}, "license": {"name": "BSD License"}, "version": "v1"}, "host": "habibapp.com", "schemes": ["https"], "basePath": "/", "consumes": ["application/json"], "produces": ["application/json"], "securityDefinitions": {"Basic": {"type": "basic"}}, "security": [{"Basic": []}], "paths": {"/about-service/": {"get": {"operationId": "about-service_list", "description": "-- params: service", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "service", "in": "query", "description": "Service type to filter by", "type": "string", "enum": ["main", "hussainiyah", "quran", "mafatih", "qiblah", "ahkam", "calendar", "talk", "meet", "library", "hadis", "account"]}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/AboutService"}}}}}}, "tags": ["about-service"]}, "parameters": []}, "/account/activity/create/": {"post": {"operationId": "account_activity_create_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Activity"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Activity"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/apple/": {"post": {"operationId": "account_auth_apple_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/AppleAuth"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/AppleAuth"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/google/": {"post": {"operationId": "account_auth_google_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GoogleAuth"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/GoogleAuth"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/guest/": {"post": {"operationId": "account_auth_guest_create", "description": "\n### Guest Authentication API\n\nThis API is invoked during the app's intro phase to authenticate guest users. It collects device information\nand performs authentication based on the provided data. \n\n| **Field** | **Type** | **Required** | **Description** |\n|---------------------|------------|--------------|----------------------------------------|\n| `auth_method` | String | No | phone or third_party |\n| `country_code` | int | No | phone country code |\n\n#### Response:\n- **200 OK**: Returns `token`, `auth_method`, and `country_code`.\n- **400 Bad Request**: Input validation failed.\n- **500 Internal Server Error**: Unexpected error.\n\n#### Example Response:\n\n```json\n{\n \"token\": \"1e126d575f3e37d5f8f0fd5a893fae90a7511c25\",\n \"auth_method\": \"phone\",\n \"country_code\": 964\n},\n{\n \"token\": \"1e126d575f3e37d5f8f0fd5a893fae90a7511c25\",\n \"auth_method\": \"third_party\",\n \"country_code\": 964\n}\n```\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GuestUser"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/GuestUser"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/logout/": {"post": {"operationId": "account_auth_logout_create", "description": "\n### User Logout API\n\nThis API endpoint allows authenticated users to securely log out from the application. The logout process\nclears the user's FCM (Firebase Cloud Messaging) token to ensure they no longer receive push notifications\non the logged-out device.\n\n#### Key Features:\n- **Authentication Required**: Only authenticated users can access this endpoint\n- **FCM Token Clearing**: Automatically clears the user's FCM token to stop push notifications\n- **Secure Logout**: Provides a clean logout process following REST API best practices\n- **Error Handling**: Comprehensive error handling with appropriate HTTP status codes\n\n#### Business Logic:\n1. **Authentication Check**: Verifies that the user is properly authenticated via token\n2. **FCM Token Cleanup**: Sets the user's FCM token field to null/empty\n3. **Database Update**: Saves the user record with the cleared FCM token\n4. **Response Generation**: Returns appropriate success or error response\n\n#### Authentication:\n- **Required**: Yes\n- **Method**: Token-based authentication\n- **Header**: `Authorization: Token `\n\n#### HTTP Method:\n- **POST**: Used for logout action (following REST conventions for state-changing operations)\n\n#### Request Headers:\n| **Header** | **Type** | **Required** | **Description** |\n|-------------------|------------|--------------|-----------------------------------|\n| `Authorization` | String | Yes | Token |\n| `Content-Type` | String | Yes | application/json |\n\n#### Response Codes:\n- **200 OK**: Logout successful, FCM token cleared\n- **401 Unauthorized**: Authentication credentials not provided or invalid\n- **500 Internal Server Error**: Unexpected server error during logout\n\n#### Success Response Example:\n```json\n{\n \"status\": \"success\",\n \"message\": \"Logged out successfully\"\n}\n```\n\n#### Error Response Examples:\n\n**401 Unauthorized:**\n```json\n{\n \"detail\": \"Authentication credentials were not provided.\"\n}\n```\n\n**500 Internal Server Error:**\n```json\n{\n \"status\": \"error\",\n \"message\": \"An error occurred during logout\"\n}\n```\n\n#### Usage Example:\n```bash\ncurl -X POST https://api.example.com/auth/logout/ \\\n -H \"Authorization: Token 516e059d2a6b31d74b6a9e4c8f98fe4e8413efbc\" \\\n -H \"Content-Type: application/json\"\n```\n\n#### Security Considerations:\n- The FCM token is immediately cleared to prevent unauthorized push notifications\n- The authentication token remains valid until explicitly deleted or expired\n- Users should clear local storage/cache on the client side after successful logout\n- Consider implementing token blacklisting for enhanced security if needed\n\n#### Integration Notes:\n- After successful logout, clients should redirect users to the login screen\n- Clear any locally stored user data and authentication tokens\n- Stop any background services that depend on user authentication\n- Update UI state to reflect the logged-out status\n", "parameters": [], "responses": {"200": {"description": "Logout successful", "examples": {"application/json": {"status": "success", "message": "Logged out successfully"}}}, "401": {"description": "Authentication required", "examples": {"application/json": {"detail": "Authentication credentials were not provided."}}}, "500": {"description": "Internal server error", "examples": {"application/json": {"status": "error", "message": "An error occurred during logout"}}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/phone/": {"post": {"operationId": "account_auth_phone_create", "description": "\n### Phone Authentication API\n\nThis API allows users to authenticate by providing a phone number. A one-time password (OTP) is sent to the\nuser via the specified method, and the response indicates whether the OTP was successfully sent.\n\n#### Response:\n- **200 OK**: Returns user ID, phone number, verification method, OTP send status, and time limit for resending the OTP.\n- **400 Bad Request**: Input validation failed.\n- **500 Internal Server Error**: Unexpected error occurred.\n\n#### Output Fields:\n\n| **Field** | **Type** | **Description** |\n|---------------------------|------------|----------------------------------------------------------|\n| `user_id` | String | Unique identifier of the authenticated user. |\n| `phone_number` | String | The phone number used for authentication. |\n| `verification_method` | String | Method used to send the OTP (e.g., \"SMS\" or \"WHATSAPP\").|\n| `verification_time_limit` | Integer | Time (in minutes) until the OTP can be resent. |\n| `is_send` | Boolean | Indicates whether the OTP was successfully sent. |\n\n#### Example Response:\n\n```json\n{\n \"user_id\": \"1a2b3c4d\",\n \"phone_number\": \"+1234567890\",\n \"verification_method\": \"WHATSAPP\",\n \"verification_time_limit\": 5,\n \"is_send\": true\n}\n```\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/PhoneAuth"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/PhoneAuth"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/staff/login/": {"post": {"operationId": "account_auth_staff_login_create", "summary": "Email/password login for staff, admin and superuser accounts.", "description": "Returns a DRF auth token (the same token type used everywhere else in the\nproject, see ``TokenAuthentication2``) so the dashboard can authenticate\nsubsequent requests with ``Authorization: Token ``.\n\nOpen to anonymous callers (``AllowAny``) — the staff check happens inside\nthe serializer; only an account with ``is_staff``/``is_superuser`` and a\ncorrect password gets a token back.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["email", "password"], "type": "object", "properties": {"email": {"type": "string", "format": "email"}, "password": {"type": "string", "format": "password"}}}}], "responses": {"200": {"description": "Authenticated", "schema": {"type": "object", "properties": {"token": {"type": "string"}, "user_id": {"type": "integer"}, "email": {"type": "string"}, "name": {"type": "string"}, "is_staff": {"type": "boolean"}, "is_superuser": {"type": "boolean"}}}}, "400": {"description": "Invalid credentials or not a staff account"}}, "tags": ["account"]}, "parameters": []}, "/account/auth/user/me/": {"get": {"operationId": "account_auth_user_me_list", "description": "این متد اطلاعات کاربر را برمی‌گرداند", "parameters": [], "responses": {"200": {"description": "اطلاعات کاربر", "examples": {"application/json": {"user_id": "ایدی کاربر", "name": "نام کاربر", "email": "ایمیل کاربر", "avatar": "آدرس آواتار", "country": "کشور", "city": "شهر", "phone_number": "شماره تلفن", "possible_phone_number": "شماره تماس احتمالی کاربر", "is_phone_number_verified": "شماره تماس تایید شده باشد", "date_joined": "تاریخ عضویت", "publisher_in": "اطلاعات ناشر", "settings": "تنظیمات کاربر", "provider": "اطلاعات ارائه‌دهنده", "coin_balance": "موجودی کوین ها", "balance_in_dollars": "مقدار دلار کاربر (اگر پرووایدر نباشد خالی است)", "notification_count": "تعداد نوتیفیکیشن‌ها", "bucket_services": "لیست سرویس باکت های کاربر"}}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/user/merge/": {"post": {"operationId": "account_auth_user_merge_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MergeAccount"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/MergeAccount"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/user/merge/phone/info/": {"get": {"operationId": "account_auth_user_merge_phone_info_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["account"]}, "parameters": []}, "/account/auth/user/merge/phone/verify/": {"post": {"operationId": "account_auth_user_merge_phone_verify_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MergeVerify"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/MergeVerify"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/user/profile/update/": {"put": {"operationId": "account_auth_user_profile_update_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserProfile"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserProfile"}}}, "tags": ["account"]}, "patch": {"operationId": "account_auth_user_profile_update_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserProfile"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserProfile"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/user/region/": {"get": {"operationId": "account_auth_user_region_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["account"]}, "parameters": []}, "/account/auth/verify/": {"post": {"operationId": "account_auth_verify_create", "description": "\n### Phone Verification Logic\n\nThe phone verification process ensures user authenticity through a one-time verification code. Below is the streamlined flow:\n\n1. **Input Validation **:\n - Accepts `user_id`, `phone_number`, and a 5-digit `code`.\n - Validates input and raises errors for missing or invalid data.\n\n2. **User Retrieval**:\n - Fetch the user using `user_id`.\n - Raise an error if the user does not exist.\n\n3. **Verification Data Fetch**:\n - Retrieve the verification data from Redis using `phone_number`.\n - Raise an error if data is missing or expired.\n\n4. **Code Comparison**:\n - Compare the provided `code` with the one in Redis.\n - Raise an error for mismatched codes.\n\n5. **User Update**:\n - On success, update the user's `phone_number` and mark them as verified.\n\n6. **Response Generation**:\n - Return an authentication token along with user profile details (e.g., name, email, location, settings).\n\n#### Failure Scenarios:\n- Errors are raised for invalid input, missing verification data, or incorrect codes.\n\nThis process ensures secure and efficient phone verification.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/PhoneVerify"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/PhoneVerify"}}}, "tags": ["account"]}, "parameters": []}, "/account/auth/{device_id}/update/": {"put": {"operationId": "account_auth_update_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GuestUser"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/GuestUser"}}}, "tags": ["account"]}, "patch": {"operationId": "account_auth_update_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GuestUser"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/GuestUser"}}}, "tags": ["account"]}, "parameters": [{"name": "device_id", "in": "path", "required": true, "type": "string"}]}, "/account/bucket/update/": {"get": {"operationId": "account_bucket_update_list", "description": "Remove a service from user's bucket services", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "service", "in": "query", "description": "Service name to remove from bucket services", "required": false, "type": "string"}], "responses": {"200": {"description": "Service removed successfully from bucket services", "examples": {"application/json": {"message": "Successfully updated"}}}, "400": {"description": "Bad request"}, "401": {"description": "Authentication credentials were not provided"}}, "tags": ["account"]}, "parameters": []}, "/account/delete-account/": {"post": {"operationId": "account_delete-account_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["account"]}, "parameters": []}, "/account/geolocation/": {"get": {"operationId": "account_geolocation_list", "description": "Get geolocation information based on the client's IP address", "parameters": [], "responses": {"200": {"description": "Geolocation information", "schema": {"$ref": "#/definitions/IPGeolocation"}}, "404": {"description": "IP address not found in database or database not available"}, "500": {"description": "Internal server error"}}, "tags": ["account"]}, "parameters": []}, "/account/geolocation/coordinates/": {"get": {"operationId": "account_geolocation_coordinates_list", "description": "Get location information (city, country) based on geographic coordinates using reverse geocoding", "parameters": [{"name": "lat", "in": "query", "description": "Latitude coordinate (-90 to 90)", "required": true, "type": "number"}, {"name": "lon", "in": "query", "description": "Longitude coordinate (-180 to 180)", "required": true, "type": "number"}], "responses": {"200": {"description": "Location information", "schema": {"$ref": "#/definitions/ReverseGeolocationResponse"}}, "400": {"description": "Invalid or missing coordinates"}, "404": {"description": "No location found for the given coordinates"}, "500": {"description": "Internal server error"}}, "tags": ["account"]}, "parameters": []}, "/account/location-update/": {"post": {"operationId": "account_location-update_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/LocationHistory"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/LocationHistory"}}}, "tags": ["account"]}, "parameters": []}, "/account/notif-list/": {"get": {"operationId": "account_notif-list_list", "description": "### Example JSON Response:\n```json\n{\n \"count\": 36,\n \"next\": \"https://habibapp.com/account/notif-list/?limit=16&offset=16\",\n \"previous\": null,\n \"results\": [\n {\n \"id\": 126753,\n \"service\": \"mafatih\",\n \"title\": \"اللهم عجل لولیک الفرج\",\n \"message\": \"خواهر یا اخوان،\",\n \"data\": \"4450\",\n \"image\": null,\n \"is_read\": true,\n \"created_at\": \"2024-10-06T14:39:32.893330\"\n }\n ]\n}\n```", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "service", "in": "query", "description": "Specify the service to filter messages (optional).", "required": false, "type": "string", "enum": ["hussainiya", "library", "talk", "meet", "mafatih", "hadis", "khatm", "quran", "tafsir", "ahkam", "coin", "global"]}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/UserNotification"}}}}}}, "tags": ["notification"]}, "parameters": []}, "/account/provider/requests/": {"get": {"operationId": "account_provider_requests_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Provider"}}}}}}, "tags": ["account"]}, "post": {"operationId": "account_provider_requests_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Provider"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Provider"}}}, "tags": ["account"]}, "parameters": []}, "/account/read-all-notif/": {"get": {"operationId": "account_read-all-notif_list", "description": "", "parameters": [{"name": "service", "in": "query", "description": "Specify the service to filter messages (optional). If omitted, all messages for the user will be marked as read.", "required": false, "type": "string", "enum": ["hussainiya", "library", "talk", "meet", "mafatih", "hadis", "khatm", "quran", "tafsir", "ahkam", "coin", "global", "null"]}, {"name": "value_id", "in": "query", "description": "value_id optional parameter to mark a specific message as read.(value id notificaiton)", "required": false, "type": "string"}], "responses": {"200": {"description": "Messages marked as read"}, "400": {"description": "Service parameter is required"}}, "tags": ["notification"]}, "parameters": []}, "/account/send-notification/": {"post": {"operationId": "account_send-notification_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"description": "Send notification to authenticated user with flexible payload options:\n\n 1. Regular notification: Provide title and message\n 2. Data-only notification: Omit title and message, provide data_notif\n 3. Custom payload: Set use_custom_payload=true to send data_notif keys directly in Firebase payload\n\n When use_custom_payload=true, you can test full FCM payload structure including Android-specific configurations.", "required": [], "type": "object", "properties": {"title": {"description": "Notification title (optional - if both title and message are omitted, sends data-only notification)", "type": "string"}, "message": {"description": "Notification message (optional - if both title and message are omitted, sends data-only notification)", "type": "string"}, "data_notif": {"description": "Additional data to send with notification (can be object or JSON string)", "type": "object"}, "use_custom_payload": {"description": "If true, all keys from data_notif will be placed directly in the Firebase payload message object", "type": "boolean", "default": false}}}}], "responses": {"200": {"description": "Notification sent successfully", "schema": {"type": "object", "properties": {"result": {"description": "FCM response result", "type": "array", "items": {"type": "object"}}}}}, "400": {"description": "Bad request - invalid data_notif format"}, "404": {"description": "User not found"}}, "tags": ["notification"]}, "parameters": []}, "/account/settings/": {"put": {"operationId": "account_settings_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserSettings"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserSettings"}}}, "tags": ["account"]}, "patch": {"operationId": "account_settings_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserSettings"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserSettings"}}}, "tags": ["account"]}, "parameters": []}, "/api/chat-producer/": {"post": {"operationId": "api_chat-producer_create", "description": "API producer for chat application", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["Talk"]}, "parameters": []}, "/api/crm/reviews/": {"get": {"operationId": "api_crm_reviews_list", "description": "", "parameters": [{"name": "platform", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "needs_human_intervention", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "review_status", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "ordering", "in": "query", "description": "Which field to use when ordering the results.", "required": false, "type": "string"}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ReviewList"}}}}}}, "tags": ["api"]}, "post": {"operationId": "api_crm_reviews_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReviewDetail"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/ReviewDetail"}}}, "tags": ["api"]}, "parameters": []}, "/api/crm/reviews/{id}/": {"get": {"operationId": "api_crm_reviews_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ReviewDetail"}}}, "tags": ["api"]}, "put": {"operationId": "api_crm_reviews_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReviewDetail"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ReviewDetail"}}}, "tags": ["api"]}, "patch": {"operationId": "api_crm_reviews_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReviewDetail"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ReviewDetail"}}}, "tags": ["api"]}, "delete": {"operationId": "api_crm_reviews_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["api"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/api/crm/reviews/{id}/edit_reply/": {"patch": {"operationId": "api_crm_reviews_edit_reply", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReviewDetail"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ReviewDetail"}}}, "tags": ["api"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/api/crm/reviews/{id}/reply/": {"post": {"operationId": "api_crm_reviews_reply", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReviewDetail"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/ReviewDetail"}}}, "tags": ["api"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/api/marriage/cases/{case_id}/contact-info/": {"get": {"operationId": "api_marriage_cases_contact-info_list", "description": "\nدریافت اطلاعات تماس خانم پس از پرداخت\n\nپس از تأیید پرداخت (وضعیت payment_done)، آقا می‌تواند اطلاعات تماس\nمجاز خانم را دریافت کند.\n\nشرایط دسترسی:\n - کاربر (آقا یا خانم) باید عضو این کیس باشد\n - وضعیت کیس باید دقیقاً payment_done باشد\n\nاطلاعات تماس قابل‌نمایش توسط ادمین از طریق فیلد female_contact_keys در کیس\nبرای هر کیس به‌صورت اختصاصی تنظیم می‌شود.\nمثال کلیدهای رایج: phone_father, phone_self, address\n\nخروجی: لیستی از فیلدهای فرم با کلید، برچسب، نوع و مقدار واقعی\n", "parameters": [], "responses": {"200": {"description": "ادمین هنوز هیچ کلید تماسی برای این کیس تنظیم نکرده", "examples": {"application/json": {"contact_info": []}}}, "403": {"description": "دسترسی ندارید یا کیس هنوز payment_done نیست", "examples": {"application/json": {"detail": "اطلاعات تماس فقط پس از تأیید پرداخت در دسترس است."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "کیس یافت نشد"}}, "tags": ["Marriage"]}, "parameters": [{"name": "case_id", "in": "path", "required": true, "type": "string"}]}, "/api/marriage/cases/{case_id}/contact-status/": {"post": {"operationId": "api_marriage_cases_contact-status_create", "description": "\nگزارش وضعیت تماس پس از دریافت اطلاعات — فقط توسط خانم\n\nخانم پس از دریافت اطلاعات تماس آقا (پس از payment_done) باید در مهلت ۴۸ ساعت\nوضعیت تماس را گزارش دهد. کنترل زمان ۴۸ ساعت در کلاینت انجام می‌شود.\n\nزمان اشتراک‌گذاری اطلاعات تماس از فیلد `contact_shared_at` در `active_case` قابل دسترسی است.\n\nپیش‌شرط:\n - فقط خانم می‌تواند این اندپوینت را فراخوانی کند\n - وضعیت کیس باید payment_done باشد\n\nمنطق:\n contacted →\n وضعیت کیس: payment_done → finalized\n هر دو پروفایل: in_case → matched\n reason_code و custom_note (اگر ارسال شده باشند) در CaseRejection ذخیره می‌شوند\n (کیس با موفقیت به نتیجه رسید)\n\n no_contact →\n جریمه time_suspend برای آقا ثبت می‌شود (۷ روز تعلیق)\n وضعیت کیس: payment_done → dismissed\n reason_code و custom_note در CaseRejection ذخیره می‌شوند\n پروفایل آقا: in_case → suspended (+ penalty_until تنظیم می‌شود)\n پروفایل خانم: in_case → waiting (آزاد برای کیس جدید)\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["action"], "type": "object", "properties": {"action": {"description": "contacted: آقا تماس گرفت | no_contact: آقا تماس نگرفت", "type": "string", "enum": ["contacted", "no_contact"]}, "reason_code": {"description": "کد دلیل (اختیاری) — مثال: no_call_received, wrong_number", "type": "string"}, "custom_note": {"description": "توضیح اضافه (اختیاری)", "type": "string"}}, "example": {"action": "no_contact", "reason_code": "no_call_received", "custom_note": "48 ساعت گذشته ولی تماسی نگرفت"}}}], "responses": {"200": {"description": "وضعیت تماس ثبت شد — حالت no_contact (جریمه اعمال شد، status در database dismissed است اما در response male_accepted نمایش داده می‌شود)", "examples": {"application/json": {"detail": "عدم تماس ثبت شد. جریمه اعمال گردید.", "case": {"id": 15, "status": "male_accepted", "introduced_at": "2026-04-20T08:30:00Z", "male_responded_at": "2026-04-20T10:15:00Z", "female_responded_at": "2026-04-21T09:00:00Z", "payment_done_at": "2026-04-21T09:00:00Z", "contact_shared_at": "2026-04-21T09:00:00Z"}}}}, "400": {"description": "وضعیت کیس برای این عملیات مناسب نیست", "examples": {"application/json": {"detail": "وضعیت کیس برای این عملیات مناسب نیست."}}}, "403": {"description": "فقط خانم می‌تواند این عملیات را انجام دهد", "examples": {"application/json": {"detail": "فقط خانم می‌تواند وضعیت تماس را گزارش دهد."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "کیس یافت نشد"}}, "tags": ["Marriage"]}, "parameters": [{"name": "case_id", "in": "path", "required": true, "type": "string"}]}, "/api/marriage/cases/{case_id}/respond/": {"post": {"operationId": "api_marriage_cases_respond_create", "description": "\nپاسخ به کیس معرفی (تأیید یا رد)\n\nآقا یا خانم می‌توانند کیس پیشنهادی را تأیید یا رد کنند.\n\nمنطق انتقال وضعیت:\n\nآقا (وقتی کیس در introduced است):\n accept → male_accepted (اطلاعات عمومی خانم برای آقا قابل مشاهده می‌شود)\n reject → male_rejected (هر دو پروفایل به waiting برمی‌گردند)\n\nخانم (وقتی کیس در male_accepted است):\n accept →\n اگر آقا اشتراک معتبر دارد: payment_done (مستقیم — consume_usage فراخوانی می‌شود)\n اگر آقا اشتراک ندارد: payment_pending (نیاز به خرید اشتراک)\n **توجه:** در response، status به `male_accepted` تبدیل می‌شود و جزئیات پرداخت از `needs_subscription` مشخص می‌شود\n reject → female_rejected (هر دو پروفایل به waiting برمی‌گردند)\n\nreason_code: کدهای هاردکد‌شده در فرانت‌اند — مثال: not_matched_financially, changed_mind\ncustom_note: توضیح اضافه اختیاری\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["action"], "type": "object", "properties": {"action": {"description": "تأیید یا رد کیس", "type": "string", "enum": ["accept", "reject"]}, "reason_code": {"description": "کد دلیل رد (اختیاری) — مثال: not_matched_financially", "type": "string", "default": ""}, "custom_note": {"description": "توضیح اضافه (اختیاری)", "type": "string", "default": ""}}, "example": {"action": "reject", "reason_code": "not_matched_financially", "custom_note": "از نظر مالی تناسب نداشتیم"}}}], "responses": {"200": {"description": "آقا تأیید کرد و خانم هم تأیید کرد — در database به payment_done می‌رود اما در response male_accepted نمایش داده می‌شود", "examples": {"application/json": {"detail": "پاسخ شما با موفقیت ثبت شد.", "case": {"id": 15, "status": "male_accepted", "introduced_at": "2026-04-20T08:30:00Z", "male_responded_at": "2026-04-20T10:15:00Z", "female_responded_at": "2026-04-21T09:00:00Z", "payment_done_at": "2026-04-21T09:00:00Z", "contact_shared_at": "2026-04-21T09:00:00Z"}}}}, "400": {"description": "وضعیت کیس برای این عملیات مناسب نیست", "examples": {"application/json": {"detail": "وضعیت کیس برای این عملیات مناسب نیست."}}}, "403": {"description": "کاربر عضو این کیس نیست", "examples": {"application/json": {"detail": "شما به این کیس دسترسی ندارید."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "کیس یافت نشد"}}, "tags": ["Marriage"]}, "parameters": [{"name": "case_id", "in": "path", "required": true, "type": "string"}]}, "/api/marriage/match/start/": {"post": {"operationId": "api_marriage_match_start_create", "description": "\nورود به صف مچینگ\n\nپس از تکمیل تمام محورهای اجباری، کاربر می‌تواند وارد صف انتظار شود\nتا سیستم برایش یک کیس مناسب پیدا کند.\n\nپیش‌شرط‌ها:\n ۱. وضعیت پروفایل باید pending_info باشد\n ۲. کاربر نباید معلق (suspended) باشد\n ۳. تمام محورهای is_required=True باید current_step >= total_steps داشته باشند\n\nپس از موفقیت:\n وضعیت پروفایل از pending_info به waiting تغییر می‌کند.\n ویرایش فرم‌ها قفل می‌شود (can_edit_profile = False).\n", "parameters": [], "responses": {"200": {"description": "با موفقیت وارد صف مچینگ شدید", "examples": {"application/json": {"detail": "با موفقیت وارد صف مچینگ شدید."}}}, "400": {"description": "خطا — پروفایل ناقص یا وضعیت نامناسب", "examples": {"application/json": {"detail": "لطفاً ابتدا تمام محورهای اجباری را تکمیل کنید."}}}, "403": {"description": "کاربر معلق است", "examples": {"application/json": {"detail": "حساب شما معلق است و امکان ورود به صف مچینگ را ندارید."}}}, "401": {"description": "کاربر احراز هویت نشده است"}}, "tags": ["Marriage"]}, "parameters": []}, "/api/marriage/profile/basic/": {"patch": {"operationId": "api_marriage_profile_basic_partial_update", "description": "\nثبت اطلاعات پایه پروفایل (آنبوردینگ)\n\nاولین قدم پس از ورود به سیستم مریج.\nجنسیت و نوع ثبت‌نام کاربر ثبت می‌شود.\n\nمنطق انتقال وضعیت:\n pending_onboarding → pending_info (وقتی هر دو فیلد پر شوند)\n\nis_registering_for_self:\n - True: کاربر برای خودش ثبت‌نام می‌کند\n - False: کاربر برای شخص دیگری (مثلاً خواهر) ثبت‌نام می‌کند\n این مقدار روی کدام محورهای فرم نمایش داده شوند تأثیر مستقیم دارد.\n\nخروجی: پروفایل آپدیت‌شده (همان فرمت GET /profile/main/)\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["gender", "is_registering_for_self"], "type": "object", "properties": {"gender": {"description": "جنسیت کاربر", "type": "string", "enum": ["male", "female"]}, "is_registering_for_self": {"description": "True = برای خودش | False = برای شخص دیگر", "type": "boolean"}}, "example": {"gender": "male", "is_registering_for_self": true}}}], "responses": {"200": {"description": "اطلاعات پایه با موفقیت ثبت شد", "examples": {"application/json": {"id": 42, "status": "pending_info", "gender": "male", "is_registering_for_self": true, "can_edit_profile": true, "can_message_expert": false, "active_subscription": null, "is_ready_for_match": false, "active_case": null, "needs_subscription": false, "match_summary": null}}}, "400": {"description": "خطا در اعتبارسنجی ورودی", "examples": {"application/json": {"gender": ["مقدار وارد شده معتبر نیست."], "is_registering_for_self": ["این فیلد الزامی است."]}}}, "401": {"description": "کاربر احراز هویت نشده است"}}, "tags": ["Marriage"]}, "parameters": []}, "/api/marriage/profile/main/": {"get": {"operationId": "api_marriage_profile_main_list", "description": "\n## دریافت وضعیت کامل پروفایل مریج\n\nاصلی‌ترین اندپوینت ماژول مریج. تمام اطلاعات لازم برای رندر صفحه اصلی را در یک درخواست برمی‌گرداند.\nاگر پروفایل وجود نداشته باشد، به‌صورت خودکار ساخته می‌شود.\n\n---\n\n### فیلدهای پاسخ\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `id` | integer | شناسه پروفایل |\n| `status` | string | وضعیت فعلی پروفایل (جدول وضعیت‌ها را ببینید) |\n| `gender` | string\\|null | جنسیت: `male` \\| `female` \\| `null` |\n| `is_registering_for_self` | boolean\\|null | `true` = برای خودش \\| `false` = برای شخص دیگر |\n| `can_edit_profile` | boolean | فقط در `pending_onboarding` / `pending_info` مجاز است |\n| `can_message_expert` | boolean | `true` اگر `in_case` باشد یا آقا اشتراک معتبر داشته باشد |\n| `active_subscription` | object\\|null | اشتراک فعال و معتبر — `null` اگر نداشته باشد |\n| `is_ready_for_match` | boolean | تمام فرم‌های `is_required=true` تکمیل شده‌اند |\n| `active_case` | object\\|null | اطلاعات کیس فعال — `null` اگر در کیس نباشد. شامل `my_action` و `other_action` |\n| `needs_subscription` | boolean | `true` فقط برای آقا در `payment_pending` بدون اشتراک معتبر. **توجه:** status های `payment_pending` و `payment_done` در response به `male_accepted` تبدیل می‌شوند و جزئیات پرداخت از این فیلد مشخص می‌شود |\n| `recommended_plan` | object\\|null | پلن پیشنهادی برای خرید اشتراک — همیشه اولین پلن فعال (کمترین order/price) |\n| `match_summary` | object\\|null | خلاصه عمومی پروفایل طرف مقابل — فقط در وضعیت‌های کیس فعال |\n\n---\n\n### جدول وضعیت‌های پروفایل (`status`)\n\n| مقدار | معنا |\n|-------|------|\n| `pending_onboarding` | هنوز جنسیت ثبت نشده |\n| `pending_info` | در حال تکمیل فرم‌ها |\n| `waiting` | در صف انتظار مچینگ |\n| `in_case` | در کیس فعال — ویرایش فرم‌ها قفل است |\n| `suspended` | معلق به دلیل جریمه (عدم تماس) |\n| `matched` | کیس به نتیجه رسیده |\n\n---\n\n### فیلد `active_case`\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `case_id` | integer | شناسه کیس |\n| `status` | string | وضعیت کیس. **توجه:** `payment_pending` و `payment_done` در response به `male_accepted` تبدیل می‌شوند. جزئیات پرداخت از `needs_subscription` و `payment_done_at` مشخص می‌شود |\n| `introduced_at` | datetime | تاریخ معرفی |\n| `contact_shared_at` | datetime\\|null | تاریخ اشتراک‌گذاری اطلاعات تماس به آقا |\n| `minutes_since_contact_shared` | float\\|null | تعداد دقیقه‌های سپری شده از اشتراک‌گذاری — محاسبه شده توسط سرور |\n| `can_report_no_contact` | boolean | `true` اگر ۴۸ ساعت (۲۸۸۰ دقیقه) گذشته باشد — برای فعال‌سازی دکمه |\n| `my_action` | string | اقدام مورد نیاز از کاربر فعلی |\n| `other_action` | string | اقدام مورد نیاز از طرف مقابل |\n\n#### مقادیر `my_action` / `other_action`\n\n| مقدار | معنا |\n|-------|------|\n| `pending` | نوبت این طرف است که تأیید یا رد کند |\n| `waiting` | منتظر اقدام طرف مقابل |\n| `rejected` | این طرف رد کرده |\n| `other_rejected` | طرف مقابل رد کرده |\n| `payment_required` | آقا باید پرداخت کند |\n| `completed` | پرداخت انجام شده |\n\n---\n\n### فیلد `recommended_plan`\n\nوقتی `needs_subscription = true`، این فیلد اولین پلن فعال را برمی‌گرداند.\nکلاینت باید `id` این پلن را مستقیماً برای پرداخت استفاده کند (اندپوینت جداگانه‌ای برای لیست پلن‌ها وجود ندارد).\n\n```json\n{\n \"id\": 2,\n \"title\": \"اشتراک ۳ معرفی\",\n \"price\": \"150000\"\n}\n```\n\n---\n\n
\n💳 جریان پرداخت اشتراک از طریق habcoin (کلیک کنید)\n\nپس از دریافت `recommended_plan.id`، کلاینت باید درخواست پرداخت را به اندپوینت habcoin بزند:\n\n```\nGET /api/habcoin/pay/\n ?token=\n &service=marriagesubscriptionplan\n &object_id=\n```\n\n**جریان عملیات پس از فراخوانی:**\n\n1. habcoin سکه‌ها را از موجودی کاربر کسر می‌کند (FIFO — نزدیک‌ترین انقضا اول)\n2. رکورد `UserCoinUsage` با `service=marriagesubscriptionplan` ثبت می‌شود\n3. سیگنال `activate_marriage_subscription` به‌صورت خودکار اجرا می‌شود:\n - `ActiveSubscription` برای پروفایل آقا ساخته می‌شود\n - `consume_usage()` فراخوانی می‌شود\n - وضعیت کیس: `payment_pending` → `payment_done`\n - `payment_done_at` و `contact_shared_at` پر می‌شوند\n4. کلاینت می‌تواند اطلاعات تماس را از `GET /cases//contact-info/` دریافت کند\n\n**خطاهای احتمالی از habcoin/pay:**\n\n| کد | پیام | دلیل |\n|----|------|-------|\n| 400 | `Not enough coins` | موجودی سکه کافی نیست |\n| 400 | `Invalid service type` | پارامتر `service` اشتباه است |\n| 403 | `Invalid security token` | توکن امنیتی نامعتبر است |\n| 404 | `Object not found` | `plan_id` یافت نشد یا غیرفعال است |\n\n
\n", "parameters": [], "responses": {"200": {"description": "پروفایل با موفقیت بازگردانده شد", "examples": {"application/json": {"id": 42, "status": "in_case", "gender": "male", "is_registering_for_self": true, "can_edit_profile": false, "can_message_expert": true, "active_subscription": {"id": 7, "plan": {"id": 2, "title": "اشتراک ۳ معرفی", "plan_type": "count_based", "duration_days": null, "usage_limit": 3, "price": "150000"}, "start_date": "2026-04-01T10:00:00Z", "end_date": null, "total_usages": 1, "is_active": true, "is_valid": true}, "is_ready_for_match": true, "active_case": {"case_id": 15, "status": "male_accepted", "introduced_at": "2026-04-20T08:30:00Z", "contact_shared_at": "2026-04-22T14:15:00Z", "minutes_since_contact_shared": 2760.5, "can_report_no_contact": false, "my_action": "completed", "other_action": "completed"}, "needs_subscription": false, "recommended_plan": {"id": 2, "title": "اشتراک ۳ معرفی", "price": "150000"}, "match_summary": {"id": 58, "gender": "female", "overall_completion_percent": 85.0, "public_info": [{"key": "birth_year", "label": "سال تولد", "type": "number", "value": 1998}, {"key": "city", "label": "شهر", "type": "text", "value": "تهران"}, {"key": "education", "label": "تحصیلات", "type": "text", "value": "کارشناسی"}, {"key": "job", "label": "شغل", "type": "text", "value": null}, {"key": "height", "label": "قد", "type": "number", "value": null}]}}}}, "401": {"description": "کاربر احراز هویت نشده است"}}, "tags": ["Marriage"]}, "parameters": []}, "/api/marriage/sections/": {"get": {"operationId": "api_marriage_sections_list", "description": "\nلیست محورهای اطلاعاتی فرم به همراه درصد پیشرفت\n\nمحورهایی که برای جنسیت و نوع ثبت‌نام کاربر فعال هستند را به همراه درصد پیشرفت هر کدام برمی‌گرداند.\nاین اندپوینت باید فقط زمانی که کاربر در صفحه «تکمیل پروفایل» است فراخوانی شود (وضعیت pending_info).\nاگر کاربر هنوز جنسیت یا نوع ثبت‌نام را وارد نکرده باشد، آرایه خالی برمی‌گرداند.\n", "parameters": [], "responses": {"200": {"description": "لیست محورها با موفقیت بازگردانده شد", "examples": {"application/json": [{"id": 1, "slug": "personal_info", "title": "اطلاعات شخصی", "is_required": true, "importance_weight": 1.0, "estimated_minutes": 10, "total_steps": 3, "order": 1, "current_step": 3, "completion_percent": 100.0}, {"id": 2, "slug": "financial_info", "title": "اطلاعات مالی", "is_required": true, "importance_weight": 1.5, "estimated_minutes": 8, "total_steps": 2, "order": 2, "current_step": 1, "completion_percent": 50.0}]}}, "401": {"description": "کاربر احراز هویت نشده است"}}, "tags": ["Marriage"]}, "parameters": []}, "/api/marriage/sections/{slug}/data/": {"get": {"operationId": "api_marriage_sections_data_list", "description": "\nدریافت دیتای ذخیره‌شده یک محور فرم\n\nدیتای پر‌شده توسط کاربر برای یک محور اطلاعاتی مشخص (با slug) را برمی‌گرداند.\nاگر کاربر هنوز این محور را شروع نکرده باشد، پاسخ با مقادیر پیش‌فرض برگردانده می‌شود.\n\nساختار فیلد data:\n آرایه‌ای از آبجکت‌ها، هر آبجکت شامل:\n - key: کلید یکتای فیلد (مثل \"birth_year\"، \"job\")\n - label: برچسب نمایشی (مثل \"سال تولد\")\n - type: نوع فیلد (text | number | media | select | ...)\n - value: مقدار وارد شده (برای media: URL فایل دائمی یا null)\n\ncompletion_percent = (current_step / total_steps) * 100\n", "parameters": [], "responses": {"200": {"description": "محور هنوز شروع نشده — مقادیر پیش‌فرض", "examples": {"application/json": {"slug": "financial_info", "data": [], "current_step": 0, "total_steps": 2, "completion_percent": 0.0, "updated_at": null}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "محور اطلاعاتی با این slug یافت نشد یا غیرفعال است"}}, "tags": ["Marriage"]}, "patch": {"operationId": "api_marriage_sections_data_partial_update", "description": "\nآپدیت جزئی دیتای یک محور فرم\n\nدیتای یک یا چند فیلد در محور مشخص‌شده را ذخیره یا آپدیت می‌کند.\nاین عملیات Merge است — فیلدهایی که ارسال نشده‌اند حذف نمی‌شوند.\n\nپیش‌شرط: وضعیت پروفایل باید pending_onboarding یا pending_info باشد.\nدر وضعیت waiting یا in_case، PATCH با خطای ۴۰۳ رد می‌شود.\n\nساختار ورودی:\n - current_step: مرحله فعلی کاربر در این فرم (برای محاسبه درصد پیشرفت)\n - total_steps: (اختیاری) تعداد کل مراحل این فرم. اگر ارسال شود و با مقدار فعلی section متفاوت باشد، بروزرسانی می‌شود\n - fields: آرایه‌ای از فیلدهای تکمیل‌شده\n\nپردازش فیلدهای media:\n ۱. فرانت‌اند فایل را از طریق اندپوینت آپلود موقت می‌فرستد و URL tmp دریافت می‌کند\n ۲. آن URL tmp را به عنوان value فیلد media ارسال می‌کند\n ۳. سرور فایل را از مسیر موقت خوانده، در مسیر دائمی ذخیره می‌کند\n ۴. URL دائمی در JSON فرم جایگزین URL tmp می‌شود\n\nاگر value فیلد media شامل \"tmp\" نباشد (فایل قبلاً دائمی شده)، بدون تغییر ذخیره می‌شود.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["current_step", "fields"], "type": "object", "properties": {"current_step": {"description": "مرحله فعلی کاربر در این فرم (از صفر)", "type": "integer", "minimum": 0}, "total_steps": {"description": "تعداد کل مراحل این فرم (اختیاری). اگر با مقدار فعلی section متفاوت باشد، بروزرسانی می‌شود", "type": "integer", "minimum": 1}, "fields": {"description": "لیست فیلدهای تکمیل‌شده", "type": "array", "items": {"required": ["key", "label", "type", "value"], "type": "object", "properties": {"key": {"description": "کلید یکتای فیلد — مثال: birth_year", "type": "string"}, "label": {"description": "برچسب نمایشی فیلد — مثال: سال تولد", "type": "string"}, "type": {"description": "نوع فیلد: text | number | media | select | ...", "type": "string"}, "value": {"description": "مقدار فیلد — برای media: URL موقت یا دائمی (می‌تواند عدد، رشته، یا null باشد)", "type": "string", "x-nullable": true}}}}}, "example": {"current_step": 2, "total_steps": 3, "fields": [{"key": "birth_year", "label": "سال تولد", "type": "number", "value": 1995}, {"key": "city", "label": "شهر", "type": "text", "value": "تهران"}, {"key": "id_scan", "label": "کارت ملی", "type": "media", "value": "/media/tmp/upload_abc123.jpg"}]}}}], "responses": {"200": {"description": "دیتای محور با موفقیت آپدیت شد", "examples": {"application/json": {"id": 33, "slug": "personal_info", "data": [{"key": "birth_year", "label": "سال تولد", "type": "number", "value": 1995}, {"key": "city", "label": "شهر", "type": "text", "value": "تهران"}, {"key": "id_scan", "label": "کارت ملی", "type": "media", "value": "/media/marriage/media/2026/04/upload_abc123.jpg"}], "current_step": 2, "total_steps": 3, "completion_percent": 66.7, "updated_at": "2026-04-23T09:15:00Z"}}}, "400": {"description": "خطا در اعتبارسنجی یا فایل media یافت نشد", "examples": {"application/json": {"detail": "فایل رسانه‌ای یافت نشد. لطفاً دوباره آپلود کنید."}}}, "403": {"description": "ویرایش در وضعیت فعلی مجاز نیست", "examples": {"application/json": {"detail": "در وضعیت فعلی امکان ویرایش پروفایل وجود ندارد."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "محور اطلاعاتی با این slug یافت نشد یا غیرفعال است"}}, "tags": ["Marriage"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/api/talk/guidelines/": {"get": {"operationId": "api_talk_guidelines_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["Talk"]}, "parameters": []}, "/api/talk/provider/": {"post": {"operationId": "api_talk_provider_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/talk_provider_profile"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/talk_provider_profile"}}}, "tags": ["Talk"]}, "parameters": []}, "/appversions/": {"get": {"operationId": "appversions_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["appversions"]}, "parameters": []}, "/appversions/v2/": {"get": {"operationId": "appversions_v2_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["appversions"]}, "parameters": []}, "/bookmark/add/": {"post": {"operationId": "bookmark_add_create", "summary": "Add a new bookmark for a service.", "description": "Request should contain:\n- service: The service to be bookmarked.\n- content_id: The content ID of the service to be bookmarked.\n\nReturns the created bookmark.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/BookmarkSerializers"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/BookmarkSerializers"}}}, "tags": ["bookmark"]}, "parameters": []}, "/bookmark/bulk/modify/": {"post": {"operationId": "bookmark_bulk_modify_create", "description": "Bulk modify bookmarks by adding and removing them.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["add", "remove"], "type": "object", "properties": {"add": {"description": "List of items to add to bookmarks", "type": "array", "items": {"type": "object", "properties": {"service": {"description": "The service to be bookmarked (e.g., quran, mafatih, etc.)", "type": "string"}, "content_id": {"description": "The content ID of the service", "type": "string"}, "text": {"description": "Optional text for the bookmark", "type": "string", "nullable": true}}}}, "remove": {"description": "List of items to remove from bookmarks", "type": "array", "items": {"type": "object", "properties": {"content_id": {"description": "The content ID of the service to be removed", "type": "string"}, "service": {"description": "The service to be bookmarked (e.g., quran, mafatih, etc.)", "type": "string"}}}}}, "example": {"add": [{"service": "quran", "content_id": "123", "text": "My favorite verse"}, {"service": "mafatih", "content_id": "456", "text": "Daily dua"}], "remove": [{"content_id": "789", "service": "quran"}]}}}], "responses": {"200": {"description": "Bulk modify completed."}}, "tags": ["bookmark"]}, "parameters": []}, "/bookmark/list/": {"get": {"operationId": "bookmark_list_list", "summary": "List all bookmarks for the authenticated user.", "description": "Can be filtered by service using the `service` query parameter.\n\nReturns a list of bookmarks.", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookmarkSerializers"}}}}}}, "tags": ["bookmark"]}, "parameters": []}, "/bookmark/remove/{service}/{content_id}/": {"delete": {"operationId": "bookmark_remove_delete", "summary": "Deactivate a bookmark by setting its status to False using content_id and user.", "description": "The request should specify the content_id of the bookmark to be deactivated.\n\nReturns no content.", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["bookmark"]}, "parameters": [{"name": "service", "in": "path", "required": true, "type": "string"}, {"name": "content_id", "in": "path", "required": true, "type": "string"}]}, "/calendar/adjustemnts/": {"get": {"operationId": "calendar_adjustemnts_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["calendar"]}, "parameters": []}, "/calendar/occasions/": {"get": {"operationId": "calendar_occasions_list", "description": "accept parameters:
\n-- **country** : str = Could be empty or ir, de, sp
\n-- **language_code** : str = en, fa
\n-- **last_updated** : datetime = 2021-06-20 08:36:53.153834
", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Calendar"}}}}, "tags": ["calendar"]}, "parameters": []}, "/calendar/occasions/{occasion_id}/": {"get": {"operationId": "calendar_occasions_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["calendar"]}, "parameters": [{"name": "occasion_id", "in": "path", "required": true, "type": "string"}]}, "/category-masaels/": {"get": {"operationId": "category-masaels_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/MasaelCategories"}}}}, "tags": ["category-masaels"]}, "parameters": []}, "/checkup/list/": {"get": {"operationId": "checkup_list_list", "description": "\nدریافت لیست تمام چک‌آپ‌های فعال\n\nاین API لیست تمام چک‌آپ‌های موجود را با اطلاعات پایه نمایش می‌دهد.\nبرای هر چک‌آپ، اطلاعاتی شامل عنوان، تصویر، خلاصه، قیمت و فیلدهای زیر نمایش داده می‌شود:\n\nفیلدهای پاسخ:\n- questions_count: تعداد سوالات منحصر به فرد در چک‌آپ\n- answered_questions: تعداد سوالاتی که پاسخ داده شده است\n- has_access: آیا کاربر دسترسی دارد (رایگان یا خریده شده)\n- is_user_completed: آیا کاربر چک‌آپ را کامل کرده است\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "لیست چک‌آپ‌ها با موفقیت بازگردانده شد", "examples": {"application/json": [{"id": 1, "title": "چک‌آپ رزق و روزی", "image": {"sm": "http://example.com/media/image_sm.jpg", "md": "http://example.com/media/image_md.jpg", "lg": "http://example.com/media/image_lg.jpg"}, "summary": "بررسی وضعیت رزق و روزی شما", "price": "10.00", "is_free": false, "questions_count": 15, "has_participated": 0, "answered_questions": null, "is_user_completed": false, "has_access": false}, {"id": 2, "title": "چک‌آپ سلامت روحی", "image": {"sm": "http://example.com/media/image2_sm.jpg", "md": "http://example.com/media/image2_md.jpg", "lg": "http://example.com/media/image2_lg.jpg"}, "summary": "ارزیابی سلامت روان", "price": "0.00", "is_free": true, "questions_count": 20, "has_participated": 2, "answered_questions": 15, "is_user_completed": false, "has_access": true}]}}, "401": {"description": "کاربر احراز هویت نشده است"}}, "tags": ["checkup"]}, "parameters": []}, "/checkup/parameter/{id}/detail/": {"get": {"operationId": "checkup_parameter_detail_read", "description": "\nدریافت جزئیات یک پارامتر چک‌آپ\n\nاین API جزئیات کامل یک پارامتر شامل عنوان و توضیحات (حدیث یا متن تکمیلی) را نمایش می‌دهد.\n\nاستفاده:\n- زمانی که در نتایج چک‌آپ، فیلد has_details = true باشد\n- برای نمایش اطلاعات بیشتر درباره یک توصیه یا نقطه قوت\n\nفیلدهای پاسخ:\n- id: شناسه پارامتر\n- title: عنوان پارامتر\n- description: متن کامل شامل حدیث عربی، ترجمه و منبع\n", "parameters": [], "responses": {"200": {"description": "جزئیات پارامتر با موفقیت بازگردانده شد", "examples": {"application/json": {"id": 76, "title": "دوری از دعای بد علیه والدین", "description": "«لا تَدْعُ عَلى والِدَیْکَ فَاِنَّهُ یُورِثُ الفَقْرَ»\n\nنفرین بر والدین باعث فقر می‌شود. والدین مجرای فیض وجود شما هستند...\n\n📚 منبع: کتاب الکافی، جلد 5، صفحه 554"}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "پارامتر یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Checkup Parameter.", "required": true, "type": "integer"}]}, "/checkup/parameter/{id}/detail/v2/": {"get": {"operationId": "checkup_parameter_detail_v2_read", "description": "V2 - دریافت جزئیات یک CheckupParameter با ساختار جدید", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/CheckupParameterDetailSerializerV2"}}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Checkup Parameter.", "required": true, "type": "integer"}]}, "/checkup/user-checkups/": {"get": {"operationId": "checkup_user-checkups_list", "description": "\nدریافت لیست چک‌آپ‌های کاربر\n\nاین API لیست تمام چک‌آپ‌هایی را که کاربر در آنها شرکت کرده است نمایش می‌دهد.\nبرای هر چک‌آپ، اطلاعاتی شامل عنوان، تصویر، خلاصه، قیمت و فیلدهای زیر نمایش داده می‌شود:\n\nفیلدهای پاسخ:\n- questions_count: تعداد سوالات منحصر به فرد در چک‌آپ\n- answered_questions: تعداد سوالاتی که پاسخ داده شده است\n- has_access: آیا کاربر دسترسی دارد (رایگان یا خریده شده)\n- is_user_completed: آیا کاربر چک‌آپ را کامل کرده است\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "لیست چک‌آپ‌های کاربر با موفقیت بازگردانده شد", "examples": {"application/json": [{"id": 1, "title": "چک‌آپ رزق و روزی", "image": {"sm": "http://example.com/media/image_sm.jpg", "md": "http://example.com/media/image_md.jpg", "lg": "http://example.com/media/image_lg.jpg"}, "summary": "بررسی وضعیت رزق و روزی شما", "price": "10.00", "is_free": false, "questions_count": 15, "has_participated": 2, "answered_questions": 20, "is_user_completed": true}, {"id": 2, "title": "چک‌آپ سلامت روحی", "image": {"sm": "http://example.com/media/image2_sm.jpg", "md": "http://example.com/media/image2_md.jpg", "lg": "http://example.com/media/image2_lg.jpg"}, "summary": "ارزیابی سلامت روان", "price": "0.00", "is_free": true, "questions_count": 20, "has_participated": 1, "answered_questions": 10, "is_user_completed": false}]}}, "401": {"description": "کاربر احراز هویت نشده است"}}, "tags": ["checkup"]}, "parameters": []}, "/checkup/{id}/": {"get": {"operationId": "checkup_read", "description": "\nدریافت جزئیات کامل یک چک‌آپ\n\nاین API اطلاعات کامل یک چک‌آپ شامل عنوان، تصویر، خلاصه، توضیحات کامل، قیمت و فیلدهای زیر را نمایش می‌دهد:\n\nفیلدهای پاسخ:\n- questions_count: تعداد سوالات منحصر به فرد در چک‌آپ\n- answered_questions: تعداد سوالاتی که پاسخ داده شده است\n- has_access: آیا کاربر دسترسی دارد (رایگان یا خریده شده)\n- is_user_completed: آیا کاربر چک‌آپ را کامل کرده است\n", "parameters": [], "responses": {"200": {"description": "جزئیات چک‌آپ با موفقیت بازگردانده شد", "examples": {"application/json": {"id": 1, "title": "چک‌آپ رزق و روزی", "image": {"sm": "http://example.com/media/image_sm.jpg", "md": "http://example.com/media/image_md.jpg", "lg": "http://example.com/media/image_lg.jpg"}, "summary": "بررسی وضعیت رزق و روزی شما", "description": "توضیحات کامل در مورد چک‌آپ رزق و روزی...", "price": "10.00", "is_free": false, "questions_count": 15, "has_participated": 2, "answered_questions": 5, "is_user_completed": false, "has_access": true}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Checkup.", "required": true, "type": "integer"}]}, "/checkup/{id}/basic-questions/": {"get": {"operationId": "checkup_basic-questions_list", "description": "\nدریافت لیست سوالات پایه یک چک‌آپ\n\nاین API سوالات پایه (مانند جنسیت، سن، وضعیت تأهل) یک چک‌آپ را به همراه \nگزینه‌های پاسخ آن نمایش می‌دهد.\nکاربر باید قبلاً در چک‌آپ شرکت کرده باشد (join).\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "لیست سوالات پایه با موفقیت بازگردانده شد", "examples": {"application/json": {"answered_questions": 2, "result": [{"id": 1, "title": "جنسیت شما چیست؟", "question_help_text": "لطفاً جنسیت خود را انتخاب کنید", "question_type": "single", "question_widget_type": "radio", "answers": [{"id": 1, "title": "مرد", "image": {"sm": "http://example.com/media/male_sm.jpg", "md": "http://example.com/media/male_md.jpg", "lg": "http://example.com/media/male_lg.jpg"}}, {"id": 2, "title": "زن", "image": {"sm": "http://example.com/media/female_sm.jpg", "md": "http://example.com/media/female_md.jpg", "lg": "http://example.com/media/female_lg.jpg"}}]}]}}}, "400": {"description": "کاربر هنوز در چک‌آپ شرکت نکرده است"}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/basic-questions/submit/": {"post": {"operationId": "checkup_basic-questions_submit_create", "description": "\nثبت پاسخ‌های سوالات پایه\n\nاین API برای ثبت پاسخ‌های کاربر به سوالات پایه چک‌آپ استفاده می‌شود.\nبرای هر سوال، باید شناسه سوال (question_id) و شناسه پاسخ انتخابی (answer_id) ارسال شود.\nاگر UserCheckup وجود نداشته باشد، به صورت خودکار ایجاد می‌شود.\nاین عملیات در یک transaction انجام می‌شود.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["answers"], "type": "object", "properties": {"answers": {"description": "لیست پاسخ‌های سوالات پایه", "type": "array", "items": {"type": "object", "properties": {"question_id": {"description": "شناسه سوال", "type": "integer"}, "answer_id": {"description": "شناسه پاسخ", "type": "integer"}}}}}, "example": {"answers": [{"question_id": 1, "answer_id": 2}, {"question_id": 2, "answer_id": 5}]}}}], "responses": {"201": {"description": "پاسخ‌ها با موفقیت ثبت شد", "examples": {"application/json": {"detail": "Basic answers submitted successfully."}}}, "400": {"description": "خطا در اعتبارسنجی", "examples": {"application/json": {"detail": "Each answer must contain 'question_id' and 'answer_id'."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/history/": {"get": {"operationId": "checkup_history_list", "description": "لیست تمام دفعاتی که کاربر در یک چک‌آپ خاص شرکت کرده و تمام کرده.", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/join/": {"post": {"operationId": "checkup_join_create", "description": "\nشرکت در یک چک‌آپ\n\nاین API برای شرکت کاربر در یک چک‌آپ استفاده می‌شود.\nاگر چک‌آپ رایگان باشد، مستقیماً کاربر ثبت می‌شود.\nاگر چک‌آپ پولی باشد، کوین‌های کاربر کسر شده و سپس ثبت‌نام انجام می‌شود.\nکاربر می‌تواند چند بار در یک چک‌آپ شرکت کند.\n", "parameters": [], "responses": {"201": {"description": "شرکت در چک‌آپ با موفقیت انجام شد", "examples": {"application/json": {"detail": "Successfully joined the checkup."}}}, "400": {"description": "خطا در شرکت", "examples": {"application/json": {"detail": "Insufficient coins. You need 100 coins but have 50."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/parameter-questions/": {"get": {"operationId": "checkup_parameter-questions_list", "description": "\nدریافت لیست سوالات پارامتر یک چک‌آپ\n\nاین API سوالات اصلی چک‌آپ (CheckupParameter Questions) را که از طریق BasicQuestion \nبه پارامترها متصل هستند، به همراه گزینه‌های پاسخ نمایش می‌دهد.\nاین سوالات امتیازدهی دارند و در محاسبه نتیجه نهایی استفاده می‌شوند.\nکاربر باید قبلاً در چک‌آپ شرکت کرده باشد (join).\n\nفیلدهای جدید:\n- is_weight_visible: آیا وزن پارامتر باید برای کاربر نمایش داده شود یا خیر\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "لیست سوالات پارامتر با موفقیت بازگردانده شد", "examples": {"application/json": {"answered_questions": 3, "result": [{"id": 10, "title": "آیا در نماز صبح شرکت می‌کنید؟", "question": "توضیحاتی درباره سوال", "description": "توضیح کامل پارامتر", "order": 1, "parameter_type": "positive", "is_weight_visible": true, "parameter_answers": [{"id": 25, "title": "هیچ وقت", "answer_type": "text", "image": null, "weight": 0}, {"id": 26, "title": "گاهی اوقات", "answer_type": "text", "image": null, "weight": 25}, {"id": 27, "title": "بیشتر اوقات", "answer_type": "text", "image": null, "weight": 75}, {"id": 28, "title": "همیشه", "answer_type": "text", "image": null, "weight": 100}]}]}}}, "400": {"description": "کاربر هنوز در چک‌آپ شرکت نکرده است"}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/parameters/submit/": {"post": {"operationId": "checkup_parameters_submit_create", "description": "\nثبت پاسخ‌های سوالات اصلی و محاسبه نتیجه\n\nاین API برای ثبت پاسخ‌های کاربر به سوالات اصلی چک‌آپ (CheckupParameter) استفاده می‌شود.\nبرای هر سوال، باید شناسه سوال (question_id) و شناسه پاسخ (answer_id) ارسال شود.\n\nسیستم به صورت خودکار:\n1. از طریق BasicQuestion، پارامتر مرتبط را پیدا می‌کند\n2. بر اساس parameter_type (positive/negative) و weight، امتیاز محاسبه می‌شود\n3. درصد امکان بهبود (possibility_of_improvement) محاسبه می‌شود\n4. گزارش با سه وضعیت (emergency, improvement, positive) ایجاد می‌شود\n5. لیست توصیه‌ها بر اساس امتیازها تولید می‌شود\n\nاین عملیات در یک transaction انجام می‌شود و UserCheckup به حالت completed تغییر می‌کند.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["answers"], "type": "object", "properties": {"answers": {"description": "لیست پاسخ‌های سوالات اصلی", "type": "array", "items": {"type": "object", "properties": {"question_id": {"description": "شناسه سوال", "type": "integer"}, "answer_id": {"description": "شناسه پاسخ", "type": "integer"}}}}}, "example": {"answers": [{"question_id": 10, "answer_id": 25}, {"question_id": 11, "answer_id": 30}, {"question_id": 12, "answer_id": 28}]}}}], "responses": {"201": {"description": "پاسخ‌ها با موفقیت ثبت و نتیجه محاسبه شد", "examples": {"application/json": {"possibility_of_improvement": 65.5, "people_medium": 58, "report": [{"status": "emergency", "count": 2, "items": [{"order": 1, "text": "نماز صبح"}, {"order": 3, "text": "روزه"}]}, {"status": "improvement", "count": 3, "items": [{"order": 2, "text": "صدقه"}, {"order": 5, "text": "دعا"}, {"order": 7, "text": "استغفار"}]}, {"status": "positive", "count": 4, "items": [{"order": 4, "text": "نماز جماعت"}, {"order": 6, "text": "قرآن"}, {"order": 8, "text": "زیارت"}, {"order": 9, "text": "حج"}]}], "recommendations_count": 9, "recommendations": [{"order": 1, "text": "نماز صبح"}, {"order": 2, "text": "صدقه"}, {"order": 3, "text": "روزه"}]}}}, "400": {"description": "خطا در اعتبارسنجی یا UserCheckup یافت نشد", "examples": {"application/json": {"detail": "UserCheckup not found. Please join the checkup first or complete basic questions."}}}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/previous-answers/": {"get": {"operationId": "checkup_previous-answers_read", "description": "\nGet user's previous answers for a completed checkup\n\nThis API returns the most recent completed UserCheckup for the authenticated user\nalong with all their basic question answers and parameter answers.\n\nUse this when user wants to review their previous checkup results or\nwhen they want to redo a checkup with their previous answers pre-filled.\n\nResponse includes:\n- user_checkup_id: ID of the UserCheckup record\n- checkup_id: ID of the checkup\n- completed_at: When the checkup was completed\n- is_completed: Whether the checkup is completed\n- total_score: Total score achieved\n- basic_question_answers: List of all basic question answers\n- parameter_answers: List of all parameter answers with weighted scores\n", "parameters": [], "responses": {"200": {"description": "Previous answers retrieved successfully", "examples": {"application/json": {"user_checkup_id": 123, "checkup_id": 5, "completed_at": "2025-12-20T10:00:00Z", "is_completed": true, "total_score": 85, "basic_question_answers": [{"question_id": 1, "question_title": "Gender", "answer_id": 10, "answer_title": "Male", "answered_at": "2025-12-20T09:30:00Z"}], "parameter_answers": [{"parameter_id": 50, "parameter_title": "Sleep Quality", "answer_id": 200, "answer_title": "Good", "weighted_score": 8.5, "answered_at": "2025-12-20T09:35:00Z"}]}}}, "401": {"description": "User not authenticated"}, "404": {"description": "No completed checkup found for this user"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/result/": {"get": {"operationId": "checkup_result_read", "description": "\nدریافت نتیجه نهایی چک‌آپ\n\nاین API نتیجه نهایی چک‌آپ را پس از پاسخ به تمام سوالات نمایش می‌دهد.\n\nفیلدهای پاسخ:\n- statistics: آمار متغیرها شامل name، code، value، type، display_mode، achieved_items و total_items\n- report: گزارش دسته‌بندی شده (emergency, improvement, positive)\n- recommendations: لیست توصیه‌های اولویت‌دار\n- total_score: امتیاز کل (میانگین)\n\nتوضیحات statistics:\n- name: نام نمایشی متغیر (ترجمه شده)\n- code: کد یکتای متغیر (برای استفاده در لاجیک)\n- display_mode: نحوه نمایش (gauge: نمودار دایره‌ای، progress_bar: کارت بزرگ، hidden: مخفی)\n- achieved_items: تعداد موارد موفق (برای positive: وزن>=75، برای negative: وزن<=25)\n- total_items: تعداد کل سوالات مرتبط با متغیر\n", "parameters": [], "responses": {"200": {"description": "نتیجه چک‌آپ با موفقیت محاسبه شد", "examples": {"application/json": {"statistics": [{"name": "عامل برکت روزی", "code": "blessing_factor", "value": 97.0, "type": "positive", "display_mode": "gauge", "achieved_items": 73, "total_items": 75}, {"name": "عامل موانع روزی", "code": "obstacle_factor", "value": 7.7, "type": "negative", "display_mode": "progress_bar", "achieved_items": 1, "total_items": 68}], "report": [{"status": "emergency", "count": 2, "items": [{"order": 1, "text": "نماز صبح"}, {"order": 3, "text": "روزه"}]}, {"status": "improvement", "count": 3, "items": [{"order": 2, "text": "صدقه"}, {"order": 5, "text": "دعا"}]}, {"status": "positive", "count": 4, "items": [{"order": 4, "text": "نماز جماعت"}, {"order": 6, "text": "قرآن"}]}], "recommendations_count": 9, "recommendations": [{"order": 1, "text": "نماز صبح"}, {"order": 2, "text": "صدقه"}], "total_score": 85.5}}}, "400": {"description": "چک‌آپ تکمیل نشده است"}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{id}/result/v2/": {"get": {"operationId": "checkup_result_v2_read", "description": "\nدریافت نتیجه نهایی چک‌آپ - نسخه 2\n\nاین API نسخه بهبود یافته نتایج است که شامل گزارش با 4 وضعیت جدید می‌شود:\n- strengths: نقاط قوت (امتیاز بالا)\n- emergencies: موارد اضطراری (امتیاز بسیار پایین، نیاز فوری)\n- important: موارد مهم (امتیاز متوسط به پایین)\n- useful: موارد مفید (امتیاز متوسط)\n\nساختار پاسخ مشابه V1 است با این تفاوت که:\n- وضعیت‌های جدید به جای emergency, improvement, positive استفاده می‌شود\n- فیلدهای recommendations_count، recommendations و total_score حذف شده‌اند\n\nفیلدهای پاسخ:\n- statistics: آمار متغیرها شامل name، code، value، type، display_mode، achieved_items و total_items\n- report: آرایه‌ای از 4 وضعیت، هر کدام شامل status، count و items\n- هر آیتم شامل: parameter_id، order، title، text، score و has_details\n\nتوضیحات statistics:\n- name: نام نمایشی متغیر (ترجمه شده)\n- code: کد یکتای متغیر (برای استفاده در لاجیک)\n- display_mode: نحوه نمایش (gauge: نمودار دایره‌ای، progress_bar: کارت بزرگ، hidden: مخفی)\n- achieved_items: تعداد موارد موفق (برای positive: وزن>=75، برای negative: وزن<=25)\n- total_items: تعداد کل سوالات مرتبط با متغیر\n\nنکته مهم:\n- has_details: اگر true باشد، می‌توانید از API جزئیات پارامتر استفاده کنید\n- برای دریافت جزئیات: GET /checkup/parameter/{parameter_id}/detail/\n", "parameters": [], "responses": {"200": {"description": "نتیجه چک‌آپ نسخه 2 با موفقیت محاسبه شد", "examples": {"application/json": {"statistics": [{"name": "عامل برکت روزی", "code": "blessing_factor", "value": 97.0, "type": "positive", "display_mode": "gauge", "achieved_items": 73, "total_items": 75}, {"name": "عامل موانع روزی", "code": "obstacle_factor", "value": 7.7, "type": "negative", "display_mode": "progress_bar", "achieved_items": 1, "total_items": 68}], "report": [{"status": "strengths", "count": 2, "items": [{"parameter_id": 76, "order": 0, "title": "دوری از دعای بد علیه والدین", "text": "والدین، مجرایِ فیضِ وجودِ شما هستند؛ بستنِ این مجرا با نفرین، یعنی بستنِ شیرِ فلکه‌ی حیات...", "score": 300, "has_details": true}, {"parameter_id": 40, "order": 0, "title": "امانتداری", "text": "امانتداری، تنها یک فضیلت اخلاقی نیست، بلکه یک استراتژی اقتصادی قدرتمند است...", "score": 200, "has_details": true}]}, {"status": "emergencies", "count": 1, "items": [{"parameter_id": 15, "order": 0, "title": "نماز صبح", "text": "نماز صبح کلید برکت روز است...", "score": -300, "has_details": true}]}, {"status": "important", "count": 1, "items": [{"parameter_id": 25, "order": 0, "title": "صدقه", "text": "صدقه دادن درهای روزی را باز می‌کند...", "score": 150, "has_details": false}]}, {"status": "useful", "count": 1, "items": [{"parameter_id": 30, "order": 0, "title": "استغفار", "text": "استغفار باعث افزایش روزی می‌شود...", "score": 100, "has_details": false}]}]}}}, "400": {"description": "چک‌آپ تکمیل نشده است"}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/checkup/{participation_id}/result/v3/": {"get": {"operationId": "checkup_result_v3_read", "description": "\nدریافت نتیجه نهایی چک‌آپ - نسخه 2\n\nاین API نسخه بهبود یافته نتایج است که شامل گزارش با 4 وضعیت جدید می‌شود:\n- strengths: نقاط قوت (امتیاز بالا)\n- emergencies: موارد اضطراری (امتیاز بسیار پایین، نیاز فوری)\n- important: موارد مهم (امتیاز متوسط به پایین)\n- useful: موارد مفید (امتیاز متوسط)\n\nساختار پاسخ مشابه V1 است با این تفاوت که:\n- وضعیت‌های جدید به جای emergency, improvement, positive استفاده می‌شود\n- فیلدهای recommendations_count، recommendations و total_score حذف شده‌اند\n\nفیلدهای پاسخ:\n- statistics: آمار متغیرها شامل name، code، value، type، display_mode، achieved_items و total_items\n- report: آرایه‌ای از 4 وضعیت، هر کدام شامل status، count و items\n- هر آیتم شامل: parameter_id، order، title، text، score و has_details\n\nتوضیحات statistics:\n- name: نام نمایشی متغیر (ترجمه شده)\n- code: کد یکتای متغیر (برای استفاده در لاجیک)\n- display_mode: نحوه نمایش (gauge: نمودار دایره‌ای، progress_bar: کارت بزرگ، hidden: مخفی)\n- achieved_items: تعداد موارد موفق (برای positive: وزن>=75، برای negative: وزن<=25)\n- total_items: تعداد کل سوالات مرتبط با متغیر\n\nنکته مهم:\n- has_details: اگر true باشد، می‌توانید از API جزئیات پارامتر استفاده کنید\n- برای دریافت جزئیات: GET /checkup/parameter/{parameter_id}/detail/\n", "parameters": [], "responses": {"200": {"description": "نتیجه چک‌آپ نسخه 2 با موفقیت محاسبه شد", "examples": {"application/json": {"statistics": [{"name": "عامل برکت روزی", "code": "blessing_factor", "value": 97.0, "type": "positive", "display_mode": "gauge", "achieved_items": 73, "total_items": 75}, {"name": "عامل موانع روزی", "code": "obstacle_factor", "value": 7.7, "type": "negative", "display_mode": "progress_bar", "achieved_items": 1, "total_items": 68}], "report": [{"status": "strengths", "count": 2, "items": [{"parameter_id": 76, "order": 0, "title": "دوری از دعای بد علیه والدین", "text": "والدین، مجرایِ فیضِ وجودِ شما هستند؛ بستنِ این مجرا با نفرین، یعنی بستنِ شیرِ فلکه‌ی حیات...", "score": 300, "has_details": true}, {"parameter_id": 40, "order": 0, "title": "امانتداری", "text": "امانتداری، تنها یک فضیلت اخلاقی نیست، بلکه یک استراتژی اقتصادی قدرتمند است...", "score": 200, "has_details": true}]}, {"status": "emergencies", "count": 1, "items": [{"parameter_id": 15, "order": 0, "title": "نماز صبح", "text": "نماز صبح کلید برکت روز است...", "score": -300, "has_details": true}]}, {"status": "important", "count": 1, "items": [{"parameter_id": 25, "order": 0, "title": "صدقه", "text": "صدقه دادن درهای روزی را باز می‌کند...", "score": 150, "has_details": false}]}, {"status": "useful", "count": 1, "items": [{"parameter_id": 30, "order": 0, "title": "استغفار", "text": "استغفار باعث افزایش روزی می‌شود...", "score": 100, "has_details": false}]}]}}}, "400": {"description": "چک‌آپ تکمیل نشده است"}, "401": {"description": "کاربر احراز هویت نشده است"}, "404": {"description": "چک‌آپ یافت نشد"}}, "tags": ["checkup"]}, "parameters": [{"name": "participation_id", "in": "path", "required": true, "type": "string"}]}, "/command/": {"post": {"operationId": "command_create", "description": "Handles incoming API requests and routes them to the relevant handler.", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["command"]}, "parameters": []}, "/command/help/": {"get": {"operationId": "command_help_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/CommandHelp"}}}}, "tags": ["command"]}, "parameters": []}, "/command/suggestion/": {"get": {"operationId": "command_suggestion_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/CommandSuggestion"}}}}, "tags": ["command"]}, "parameters": []}, "/command/v2/": {"post": {"operationId": "command_v2_create", "description": "Handles incoming command requests and processes them through RAG system", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["command", "language_code"], "type": "object", "properties": {"command": {"description": "User command or query", "type": "string"}, "language_code": {"description": "Language code (e.g., \"en\", \"fa\")", "type": "string", "default": "en"}}}}], "responses": {"201": {"description": "", "schema": {"required": ["command", "language_code"], "type": "object", "properties": {"command": {"description": "User command or query", "type": "string"}, "language_code": {"description": "Language code (e.g., \"en\", \"fa\")", "type": "string", "default": "en"}}}}}, "tags": ["command"]}, "parameters": []}, "/donate/": {"post": {"operationId": "donate_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DonateUser"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DonateUser"}}}, "tags": ["donate"]}, "parameters": []}, "/donate/v2/": {"get": {"operationId": "donate_v2_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["donate"]}, "parameters": []}, "/donate/v2/create/": {"post": {"operationId": "donate_v2_create_create", "description": "\n**Donation Creation API**\n\nCreate a donation record and receive a payment link. This API is designed to never fail and always returns a working donation link without any errors.\n\n**Key Features:**\n- Error-free operation - never returns HTTP errors\n- All fields are completely optional with intelligent defaults\n- Automatic payment method selection based on user location\n- Support for multiple payment gateways\n- Backward compatibility with existing integrations\n\n**Smart Defaults:**\n- **donate_type**: Defaults to 'once' if not provided or invalid\n- **price**: Defaults to '10.00' if not provided or invalid\n- **id**: Auto-selected based on user location (CloudTips for Russian users, Stripe for others)\n- **phone_number**: Optional field, stored if provided, otherwise null\n\n**Payment Methods:**\n- **Stripe**: International payment gateway with predefined donation links\n- **CloudTips**: Russian payment gateway for Russian users\n\n**Localization Logic:**\n- Russian users (language_code=ru OR user.country=RU) default to CloudTips\n- All other users default to Stripe payment gateway\n- Fallback to default donation links for custom amounts\n\n**Business Logic:**\n- Creates donation record in database (optional, doesn't affect response)\n- Optionally stores donor's phone number for contact purposes\n- Maps donation amounts to predefined Stripe payment links\n- Uses fallback links for unmapped amounts\n- Always returns HTTP 200 with working payment link\n\n**Authentication**: Not required - Public API\n**Permissions**: None - Accessible to all users\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": [], "type": "object", "properties": {"donate_type": {"description": "Type of donation - either 'monthly' for recurring donations or 'once' for one-time donations. This field is completely optional and will default to 'once' if not provided or if an invalid value is sent.", "type": "string", "enum": ["monthly", "once"]}, "price": {"description": "Donation amount as a string (e.g., '5.00', '10.00', '20.00'). This field is completely optional and will default to '10.00' if not provided or if an invalid value is sent.", "type": "string"}, "id": {"description": "Payment gateway identifier. This field is completely optional. If not provided, the system will automatically choose 'stripe' for non-Russian users and 'cloudtips' for Russian users (detected by language_code=ru or user country=RU). If an invalid value is provided, it defaults to 'stripe'.", "type": "string", "enum": ["stripe", "cloudtips"]}, "phone_number": {"description": "Optional phone number for the donor. This field is completely optional and can be omitted. If provided, it will be stored with the donation record.", "type": "string"}}, "example": {"donate_type": "once", "price": "15.00", "id": "stripe", "phone_number": "+1234567890"}}}], "responses": {"200": {"description": "Donation link created successfully. This API is guaranteed to always return HTTP 200 status with a working donation link, regardless of the input provided. Even if no data is sent in the request body, the API will respond with appropriate defaults.", "examples": {"application/json": {"complete_request": {"summary": "Complete Request with Phone Number", "description": "Response when all fields including phone_number are provided", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/bIYdSDgiK7Pwh0ccMN"}}, "request_with_phone": {"summary": "Request Example with Phone", "description": "Example showing phone_number parameter usage", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/9AQ01N5E68TAbFS002"}}, "empty_request_default": {"summary": "Empty Request (Default)", "description": "Response when no fields are provided - uses intelligent defaults", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV"}}, "empty_request_russian_user": {"summary": "Empty Request (Russian User)", "description": "Response for Russian users when no fields are provided", "value": {"donate_user": 1, "donate_link": "https://pay.cloudtips.ru/p/d5881ddf"}}, "cloudtips_payment": {"summary": "CloudTips Payment", "description": "Response when CloudTips payment method is selected", "value": {"donate_user": 1, "donate_link": "https://pay.cloudtips.ru/p/d5881ddf"}}, "invalid_data_fallback": {"summary": "Invalid Data Fallback", "description": "Response when invalid data is provided - normalized to defaults", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV"}}}}}}, "tags": ["Donate"]}, "parameters": []}, "/donate/v3/": {"get": {"operationId": "donate_v3_list", "description": "\n**Donation Details API V3**\n\nRetrieve donation pricing information and available payment methods with intelligent localization support.\n\n**Key Features:**\n- Monthly and one-time donation options\n- Dynamic pricing based on user location\n- Multiple payment gateway support\n- Localized currency and payment methods\n- Russian language and payment gateway support\n\n**Donation Types:**\n- **Monthly**: Recurring donations with subscription pricing\n- **Once**: One-time donations with flexible amounts\n\n**Payment Methods:**\n- **Stripe**: International payment gateway (default)\n- **CloudTips**: Russian payment gateway for Russian users\n\n**Localization Logic:**\n- Detects user language from request headers or query parameters\n- Detects user country from authenticated user profile\n- Russian users see ruble pricing and CloudTips payment option\n- Non-Russian users see USD pricing with Stripe only\n\n**Business Logic:**\n- Monthly donations: Same pricing for all users ($5, $10, $20, $50)\n- Once donations: USD for international users, RUB for Russian users\n- Russian detection: language_code=ru OR user.country=RU\n- Payment buttons include icon, text, and payment method ID\n\n**Authentication**: Not required - Public API\n**Permissions**: None - Accessible to all users\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language preference (e.g., 'ru' for Russian, 'en' for English)", "required": false, "type": "string"}], "responses": {"200": {"description": "Donation details retrieved successfully", "examples": {"application/json": {"international_user_response": {"summary": "International User Response", "description": "Default response for non-Russian users with USD pricing", "value": {"monthly": {"prices": [{"value": "$5", "price": "5.00"}, {"value": "$10", "price": "10.00"}, {"value": "$20", "price": "20.00"}, {"value": "$50", "price": "50.00"}], "buttons": [{"icon": "https://habibapp.com/static/payicon.jpg", "text": "Donate Now", "id": "stripe"}]}, "once": {"prices": [{"value": "$5", "price": "5.00"}, {"value": "$15", "price": "15.00"}, {"value": "$30", "price": "30.00"}, {"value": "$40", "price": "40.00"}], "buttons": [{"icon": "https://habibapp.com/static/payicon.jpg", "text": "Donate Now", "id": "stripe"}]}}}, "russian_user_response": {"summary": "Russian User Response", "description": "Localized response for Russian users with ruble pricing and CloudTips", "value": {"monthly": {"prices": [{"value": "$5", "price": "5.00"}, {"value": "$10", "price": "10.00"}, {"value": "$20", "price": "20.00"}, {"value": "$50", "price": "50.00"}], "buttons": [{"icon": "https://habibapp.com/static/payicon.jpg", "text": "Donate Now", "id": "stripe"}]}, "once": {"prices": [{"value": "₽500", "price": "5.00"}, {"value": "₽1500", "price": "15.00"}, {"value": "₽3000", "price": "30.00"}, {"value": "₽4000", "price": "40.00"}], "buttons": [{"icon": "https://habibapp.com/static/payicon.jpg", "text": "Donate Now", "id": "stripe"}, {"icon": "https://habibapp.com/static/cloudtips_icon.png", "text": "Пожертвовать через CloudTips", "id": "cloudtips"}]}}}}}}}, "tags": ["Donate"]}, "parameters": []}, "/dont-kill-help/": {"get": {"operationId": "dont-kill-help_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DontKillApp"}}}, "tags": ["dont-kill-help"]}, "parameters": []}, "/eightmag-categories/": {"get": {"operationId": "eightmag-categories_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/EightmagCategories"}}}}, "tags": ["eightmag-categories"]}, "parameters": []}, "/eightmag-category-items/{slug}/": {"get": {"operationId": "eightmag-category-items_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/EightmagList"}}}}}}, "tags": ["eightmag-category-items"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/eightmag-details/{slug}/": {"get": {"operationId": "eightmag-details_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/EightmagDetails"}}}, "tags": ["eightmag-details"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/eightmag-details/{slug}/like/": {"post": {"operationId": "eightmag-details_like_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["eightmag-details"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/eightmag-list/": {"get": {"operationId": "eightmag-list_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/EightmagList"}}}}}}, "tags": ["eightmag-list"]}, "parameters": []}, "/elalhabib/": {"get": {"operationId": "elalhabib_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ElalHabib"}}}}}}, "tags": ["elalhabib"]}, "parameters": []}, "/elalhabib/lectures/": {"get": {"operationId": "elalhabib_lectures_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ElalHabibSingerInList"}}}}}}, "tags": ["elalhabib"]}, "parameters": []}, "/elalhabib/madah/": {"get": {"operationId": "elalhabib_madah_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ElalHabibSingerInList"}}}}}}, "tags": ["elalhabib"]}, "parameters": []}, "/habcoin/buy-package/": {"post": {"operationId": "habcoin_buy-package_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/contact-info/": {"get": {"operationId": "habcoin_contact-info_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/discount-usage-history/": {"get": {"operationId": "habcoin_discount-usage-history_list", "description": "Get user's discount code usage history", "parameters": [], "responses": {"200": {"description": "List of user discount code usages", "schema": {"type": "array", "items": {"$ref": "#/definitions/DiscountCodeUsage"}}}, "401": {"description": "Unauthorized - Authentication required"}}, "tags": ["Discount Code"]}, "parameters": []}, "/habcoin/inventory/": {"get": {"operationId": "habcoin_inventory_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/packages/": {"get": {"operationId": "habcoin_packages_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Package"}}}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/pay/": {"get": {"operationId": "habcoin_pay_list", "description": "", "parameters": [{"name": "token", "in": "query", "description": "Security token", "required": true, "type": "string"}, {"name": "service", "in": "query", "description": "Service type", "required": true, "type": "string"}, {"name": "object_id", "in": "query", "description": "Object ID related to the service", "required": true, "type": "integer"}, {"name": "amount", "in": "query", "description": "The number of coins to be deducted", "required": false, "type": "integer"}, {"name": "app_name", "in": "query", "description": "Optional app label for the model", "required": false, "type": "string"}, {"name": "discount_code", "in": "query", "description": "Optional discount code to apply discount on payment. The code will be validated and discount will be automatically applied if valid.", "required": false, "type": "string"}], "responses": {"200": {"description": "Coins deducted successfully", "examples": {"application/json": {"status": "Coins deducted successfully", "original_price": 10, "final_price": 8, "discount_applied": 2}}}, "400": {"description": "Not enough coins or invalid discount code"}, "403": {"description": "Invalid security token"}, "404": {"description": "User not found"}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/support/": {"post": {"operationId": "habcoin_support_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Support"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Support"}}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/transactions/": {"get": {"operationId": "habcoin_transactions_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Transactions"}}}}}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/user-coin-usages/": {"get": {"operationId": "habcoin_user-coin-usages_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/UserCoinUsage"}}}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/user-packages/": {"get": {"operationId": "habcoin_user-packages_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/UserPackage"}}}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/v2/pay/": {"get": {"operationId": "habcoin_v2_pay_list", "summary": "Escrow Payment API (V2)", "description": "Extends the original Pay view with support for escrow-style payments:\n- hold: Deduct coins from user but do NOT transfer to provider (escrow hold)\n- release: Transfer held coins to provider's wallet (after successful call)\n- refund: Return held coins to user's balance (on cancellation)\n- direct: Same as original Pay — deduct from user AND transfer to provider", "parameters": [{"name": "token", "in": "query", "description": "Security token", "required": true, "type": "string"}, {"name": "action", "in": "query", "description": "Payment action: hold, release, refund, direct", "required": true, "type": "string", "enum": ["hold", "release", "refund", "direct"]}, {"name": "username", "in": "query", "description": "User email (legacy fallback for hold, refund, direct)", "required": false, "type": "string"}, {"name": "habib_user_id", "in": "query", "description": "Unambiguous payer id; preferred over username when present", "required": false, "type": "integer"}, {"name": "amount", "in": "query", "description": "Number of coins", "required": true, "type": "integer"}, {"name": "object_id", "in": "query", "description": "Consultant ID", "required": false, "type": "integer"}, {"name": "call_id", "in": "query", "description": "Call ID for tracking", "required": false, "type": "integer"}, {"name": "service", "in": "query", "description": "Service type (e.g. calls_hold, calls_release)", "required": false, "type": "string"}, {"name": "app_name", "in": "query", "description": "App label for content type lookup", "required": false, "type": "string"}, {"name": "discount_code", "in": "query", "description": "Optional discount code (only used in hold/direct)", "required": false, "type": "string"}], "responses": {"200": {"description": "Success", "examples": {"application/json": {"status": "Coins deducted successfully"}}}, "400": {"description": "Bad request"}, "403": {"description": "Invalid security token"}, "404": {"description": "Not found"}}, "tags": ["habcoin"]}, "parameters": []}, "/habcoin/validate-discount/": {"post": {"operationId": "habcoin_validate-discount_create", "description": "Validate discount code and calculate final price", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["code", "service", "object_id"], "type": "object", "properties": {"code": {"description": "Discount code", "type": "string", "example": "SUMMER20"}, "service": {"description": "Service name (checkup, meet, etc.)", "type": "string", "example": "checkup"}, "object_id": {"description": "Object ID (Checkup or Meet ID)", "type": "integer", "example": 5}, "app_name": {"description": "App name (optional)", "type": "string", "example": "checkup"}}}}], "responses": {"200": {"description": "Discount code is valid", "examples": {"application/json": {"valid": true, "original_price": 10.0, "discounted_price": 8.0, "discount_amount": 2.0, "discount_percentage": 20.0, "message": "Discount code is valid and 20% discount will be applied"}}}, "400": {"description": "Invalid discount code", "examples": {"application/json": {"valid": false, "errors": {"code": ["Discount code has expired"]}}}}, "401": {"description": "Unauthorized - Authentication required"}}, "tags": ["Discount Code"]}, "parameters": []}, "/habibmeet/guidelines/": {"get": {"operationId": "habibmeet_guidelines_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/": {"get": {"operationId": "habibmeet_meets_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "meet_type", "in": "query", "description": "Meet Type (e.g., is_free, is_suggested)", "type": "string"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "search", "in": "query", "description": "Search term", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MeetSerializer"}}}}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/archive/{session_id}/": {"delete": {"operationId": "habibmeet_meets_archive_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["habibmeet"]}, "parameters": [{"name": "session_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/meets/create/": {"post": {"operationId": "habibmeet_meets_create_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MeetCreate"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/MeetCreate"}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/create/v2/": {"post": {"operationId": "habibmeet_meets_create_v2_create", "description": "Create a new meet with access control (public/private) and optional password.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MeetCreateV2"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/MeetCreateV2"}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/provider/profile/": {"post": {"operationId": "habibmeet_meets_provider_profile_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MeetProviderProfile"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/MeetProviderProfile"}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/providers/": {"get": {"operationId": "habibmeet_meets_providers_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ProviderMeetSerializer"}}}}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/providers/{id}/": {"get": {"operationId": "habibmeet_meets_providers_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ProviderDetailMeetSerializer"}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Meet Provider Profile.", "required": true, "type": "integer"}]}, "/habibmeet/meets/reminders/": {"get": {"operationId": "habibmeet_meets_reminders_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MeetSerializer"}}}}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/room/": {"get": {"operationId": "habibmeet_meets_room_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MeetProviderRoom"}}}}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/meets/{meet_id}/": {"get": {"operationId": "habibmeet_meets_read", "description": "\nRetrieve detailed information about a specific meet including recordings.\n\nReturns complete meet details with all associated session recordings.\nEach recording includes session information, file details, and metadata.\n\n### Response Structure:\n```json\n{\n \"id\": 174,\n \"name\": \"تست-(Tester)\",\n \"description\": \"Meeting description\",\n \"next_session_subject\": \"Next session topic\",\n \"next_session_schedule\": \"2024-01-01T10:00:00Z\",\n \"is_suggested\": false,\n \"provider\": {\n \"id\": 1,\n \"username\": \"provider_name\",\n \"email\": \"provider@example.com\"\n },\n \"is_free\": true,\n \"price\": \"0.00\",\n \"is_live\": false,\n \"is_closed\": false,\n \"online_users_count\": 0,\n \"language\": \"fa\",\n \"categories\": [],\n \"organizer\": \"Provider Name\",\n \"is_provider\": true,\n \"live_session_id\": null,\n \"has_archive\": true,\n \"recordings\": [\n {\n \"id\": 1,\n \"title\": \"Session Recording\",\n \"file\": \"https://habibapp.com/media/recorded_sessions/recording.mp4\",\n \"file_time\": \"01:30:00\",\n \"recording_type\": \"video\",\n \"created_at\": \"2024-01-01T10:00:00Z\",\n \"session_id\": 548,\n \"session_subject\": \"تلت\"\n }\n ],\n \"access\": \"public\",\n \"password\": null,\n \"has_recording\": true\n}\n```\n\n### Features:\n- Complete meet information\n- All active session recordings included\n- Provider and organizer details\n- Live session status and ID\n- Access control information\n- Recording availability status\n", "parameters": [{"name": "meet_id", "in": "path", "description": "ID of the meet to retrieve details for", "required": true, "type": "integer"}], "responses": {"200": {"description": "Meet details retrieved successfully", "schema": {"type": "object", "properties": {"id": {"description": "Meet ID", "type": "integer"}, "name": {"description": "Meet name", "type": "string"}, "description": {"description": "Meet description", "type": "string"}, "next_session_subject": {"description": "Next session subject", "type": "string"}, "next_session_schedule": {"description": "Next session schedule", "type": "string", "format": "date-time"}, "is_suggested": {"description": "Whether meet is suggested", "type": "boolean"}, "provider": {"type": "object", "properties": {"id": {"description": "Provider ID", "type": "integer"}, "username": {"description": "Provider username", "type": "string"}, "email": {"description": "Provider email", "type": "string"}}}, "is_free": {"description": "Whether meet is free", "type": "boolean"}, "price": {"description": "Meet price", "type": "string"}, "is_live": {"description": "Whether meet is currently live", "type": "boolean"}, "is_closed": {"description": "Whether meet is closed", "type": "boolean"}, "online_users_count": {"description": "Number of online users", "type": "integer"}, "language": {"description": "Meet language code", "type": "string"}, "categories": {"description": "Meet categories", "type": "array", "items": {"type": "string"}}, "organizer": {"description": "Organizer name", "type": "string"}, "is_provider": {"description": "Whether current user is the provider", "type": "boolean"}, "live_session_id": {"description": "ID of current live session", "type": "integer", "nullable": true}, "has_archive": {"description": "Whether meet has archived sessions", "type": "boolean"}, "recordings": {"description": "List of all active recordings for this meet", "type": "array", "items": {"type": "object", "properties": {"id": {"description": "Recording ID", "type": "integer"}, "title": {"description": "Recording title", "type": "string"}, "file": {"description": "Recording file URL", "type": "string"}, "file_time": {"description": "Recording duration", "type": "string"}, "recording_type": {"description": "Recording type: voice or video", "type": "string"}, "created_at": {"description": "Recording creation timestamp", "type": "string", "format": "date-time"}, "session_id": {"description": "Associated session ID", "type": "integer"}, "session_subject": {"description": "Session subject/title", "type": "string"}}}}, "access": {"description": "Meet access level", "type": "string"}, "password": {"description": "Meet password if required", "type": "string", "nullable": true}, "has_recording": {"description": "Whether meet has any recordings", "type": "boolean"}}}}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied"}, "404": {"description": "Meet not found"}}, "tags": ["habibmeet"]}, "put": {"operationId": "habibmeet_meets_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MeetDetailSerializer"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/MeetDetailSerializer"}}}, "tags": ["habibmeet"]}, "patch": {"operationId": "habibmeet_meets_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/MeetDetailSerializer"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/MeetDetailSerializer"}}}, "tags": ["habibmeet"]}, "delete": {"operationId": "habibmeet_meets_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/meets/{meet_id}/archive/": {"get": {"operationId": "habibmeet_meets_archive_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SessionArchiveSerializer"}}}}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "description": "The meet this session belongs to", "required": true, "type": "string"}]}, "/habibmeet/meets/{meet_id}/close/": {"post": {"operationId": "habibmeet_meets_close_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/meets/{meet_id}/reminder/update/": {"put": {"operationId": "habibmeet_meets_reminder_update_update", "description": "Update or create a reminder for a meet with specified active status", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["is_active"], "type": "object", "properties": {"is_active": {"description": "Whether the reminder is active or not", "type": "boolean"}}}}], "responses": {"200": {"description": "Reminder status updated successfully", "schema": {"type": "object", "properties": {"message": {"type": "string"}}}}, "201": {"description": "Reminder created with specified status", "schema": {"type": "object", "properties": {"message": {"type": "string"}}}}, "400": {"description": "Invalid request parameters", "schema": {"type": "object", "properties": {"detail": {"type": "string"}}}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/meets/{meet_id}/report/": {"post": {"operationId": "habibmeet_meets_report_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReportSerializer"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/ReportSerializer"}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "description": "Meet being reported on", "required": true, "type": "string"}]}, "/habibmeet/meets/{meet_id}/schedule/": {"delete": {"operationId": "habibmeet_meets_schedule_delete", "description": "Delete the next session subject and schedule if the meet is not live.\nIf the meet is live, an error is returned. If the next session subject and\nschedule are already empty, an error is returned.", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/meets/{meet_id}/session/": {"post": {"operationId": "habibmeet_meets_session_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/SessionCreate"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/SessionCreate"}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "meet_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/recordings/create/": {"post": {"operationId": "habibmeet_recordings_create_create", "summary": "API endpoint for creating new session recordings.", "description": "Allows authenticated users to create recordings for sessions.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/SessionRecordingCreateUpdateSerializer"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/SessionRecordingCreateUpdateSerializer"}}}, "tags": ["habibmeet"]}, "parameters": []}, "/habibmeet/recordings/{recording_id}/delete/": {"delete": {"operationId": "habibmeet_recordings_delete_delete", "description": "Handle DELETE request with proper error handling and status codes.", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["habibmeet"]}, "parameters": [{"name": "recording_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/recordings/{recording_id}/update/": {"put": {"operationId": "habibmeet_recordings_update_update", "summary": "API endpoint for updating existing session recordings.", "description": "Allows authenticated users to update recordings they own.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/SessionRecordingCreateUpdateSerializer"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SessionRecordingCreateUpdateSerializer"}}}, "tags": ["habibmeet"]}, "patch": {"operationId": "habibmeet_recordings_update_partial_update", "summary": "API endpoint for updating existing session recordings.", "description": "Allows authenticated users to update recordings they own.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/SessionRecordingCreateUpdateSerializer"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SessionRecordingCreateUpdateSerializer"}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "recording_id", "in": "path", "required": true, "type": "string"}]}, "/habibmeet/sessions/{id}/upload/": {"put": {"operationId": "habibmeet_sessions_upload_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/SessionFileUpload"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SessionFileUpload"}}}, "tags": ["habibmeet"]}, "patch": {"operationId": "habibmeet_sessions_upload_partial_update", "description": "Upload a file for a specific session.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/SessionFileUpload"}}, {"name": "recorded_file", "in": "file", "description": "The file to upload for the session.", "required": true, "type": "file"}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SessionFileUpload"}}}, "tags": ["habibmeet"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this session.", "required": true, "type": "integer"}]}, "/habibmeet/{id}/recordings/": {"get": {"operationId": "habibmeet_recordings_list", "description": "\nRetrieve a list of recorded meeting sessions for a specific meet.\n\nReturns all active session recordings for the specified meet ID with their\nassociated session details, file information, duration, and recording type (voice/video).\n\n### Response Structure:\n```json\n[\n {\n \"id\": 1,\n \"title\": \"Meeting Recording\",\n \"file\": \"https://habibapp.com/media/recorded_sessions/recording.mp4\",\n \"file_time\": \"01:30:00\",\n \"recording_type\": \"video\",\n \"created_at\": \"2024-01-01T10:00:00Z\",\n \"session_id\": 123,\n \"session_subject\": \"Weekly Team Meeting\"\n }\n]\n```\n\n### Features:\n- Only returns active recordings for the specified meet (is_active=True)\n- Includes session information for context\n- Supports filtering and pagination\n- Ordered by creation date (newest first)\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "id", "in": "path", "description": "ID of the meet to retrieve recordings for", "required": true, "type": "integer"}], "responses": {"200": {"description": "List of session recordings for the specified meet retrieved successfully", "schema": {"type": "array", "items": {"type": "object", "properties": {"id": {"description": "Recording ID", "type": "integer"}, "title": {"description": "Recording title", "type": "string"}, "file": {"description": "File URL", "type": "string"}, "file_time": {"description": "Recording duration", "type": "string"}, "recording_type": {"description": "Type: voice or video", "type": "string"}, "created_at": {"description": "Creation timestamp", "type": "string", "format": "date-time"}, "session_id": {"description": "Associated session ID", "type": "integer"}, "session_subject": {"description": "Session subject/title", "type": "string"}}}}}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied"}, "404": {"description": "Meet not found"}}, "tags": ["habibmeet"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/centers/": {"get": {"operationId": "habibnet_centers_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/CenterList"}}}}}}, "tags": ["habibnet"]}, "parameters": []}, "/habibnet/centers/{id}/": {"get": {"operationId": "habibnet_centers_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/CenterDetail"}}}, "tags": ["habibnet"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this center.", "required": true, "type": "integer"}]}, "/habibnet/centers/{id}/events/": {"get": {"operationId": "habibnet_centers_events_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/CenterEvent"}}}}}}, "tags": ["habibnet"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/provider/center/": {"get": {"operationId": "habibnet_provider_center_read", "description": "\nRetrieve the center owned by the authenticated provider.\n\n### Requirements:\n- User must be authenticated\n- User must have a verified provider profile\n- Provider must have created a center\n\n### Notes:\n- Each provider can only have one center\n- Returns the provider's center with all details including status\n\n### Response Structure:\nReturns the center details including status, images, and all other information.\n", "parameters": [], "responses": {"200": {"description": "Center retrieved successfully", "schema": {"type": "object", "properties": {"id": {"description": "Center ID", "type": "integer"}, "avatar": {"description": "Avatar URL", "type": "string"}, "name": {"description": "Center name", "type": "string"}, "slogan": {"description": "Center slogan", "type": "string"}, "center_type": {"description": "Center type", "type": "string"}, "about_center": {"description": "About center", "type": "string"}, "working_hours": {"description": "Working hours", "type": "object"}, "social_medias": {"description": "Social media links", "type": "array", "items": {"type": "object"}}, "address": {"description": "Address", "type": "string"}, "lat": {"description": "Latitude", "type": "number"}, "lon": {"description": "Longitude", "type": "number"}, "images": {"description": "Center images", "type": "array", "items": {"type": "object", "properties": {"id": {"type": "integer"}, "image": {"type": "string"}, "priority": {"type": "integer"}}}}, "status": {"description": "Approval status (pending, approved, rejected)", "type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "examples": {"application/json": {"id": 1, "avatar": "https://habibapp.com/media/habibnet/avatars/center_avatar.jpg", "name": "Islamic Center of New York", "slogan": "Serving the community since 1990", "center_type": "islamic_center", "about_center": "A comprehensive Islamic center...", "working_hours": {"monday": "9:00 AM - 9:00 PM", "friday": "9:00 AM - 11:00 PM"}, "social_medias": [{"platform": "facebook", "url": "https://facebook.com/center"}], "address": "123 Main Street, New York, NY 10001", "lat": 40.7128, "lon": -74.006, "images": [{"id": 1, "image": "https://habibapp.com/media/habibnet/image1.jpg", "priority": 1}], "status": "pending", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z"}}}, "401": {"description": "Authentication required"}, "404": {"description": "Provider profile or center not found", "examples": {"application/json": {"detail": "No verified provider profile found. Please submit a provider request first."}}}}, "tags": ["habibnet"]}, "parameters": []}, "/habibnet/provider/center/create/": {"post": {"operationId": "habibnet_provider_center_create_create", "description": "\nCreate a new center for the authenticated provider.\n\n### Requirements:\n- User must be authenticated\n- User must have a verified provider profile\n- Provider profile must be approved\n\n### Request Body:\nThe request should include center details and optionally images.\n\n**IMPORTANT**: Image fields (avatar, images) must be string URLs from the `/habibnet/upload-tmp-media/` endpoint, NOT binary file data.\n\n### Image Upload Workflow:\n1. First upload each image file to `/habibnet/upload-tmp-media/` endpoint\n2. Extract the `file` value from the response (e.g., \"/tmp/xyz-avatar.jpg\")\n3. Use this path string in the center creation request\n\n### Example Request:\n```json\n{\n \"avatar\": \"/tmp/xyz-avatar.jpg\",\n \"name\": \"Islamic Center of New York\",\n \"slogan\": \"Serving the community since 1990\",\n \"center_type\": \"islamic_center\",\n \"about_center\": \"A comprehensive Islamic center offering prayer facilities, educational programs, and community services.\",\n \"working_hours\": {\n \"monday\": \"9:00 AM - 9:00 PM\",\n \"tuesday\": \"9:00 AM - 9:00 PM\",\n \"wednesday\": \"9:00 AM - 9:00 PM\",\n \"thursday\": \"9:00 AM - 9:00 PM\",\n \"friday\": \"9:00 AM - 11:00 PM\",\n \"saturday\": \"9:00 AM - 11:00 PM\",\n \"sunday\": \"9:00 AM - 9:00 PM\"\n },\n \"social_medias\": [\n {\"platform\": \"facebook\", \"url\": \"https://facebook.com/islamiccenter\"},\n {\"platform\": \"instagram\", \"url\": \"https://instagram.com/islamiccenter\"}\n ],\n \"address\": \"123 Main Street, New York, NY 10001\",\n \"lat\": 40.7128,\n \"lon\": -74.0060,\n \"images\": [\n {\"image\": \"/tmp/xyz-image1.jpg\", \"priority\": 1},\n {\"image\": \"/tmp/xyz-image2.jpg\", \"priority\": 2}\n ]\n}\n```\n\n### Response Structure:\nReturns the created center with all details including generated ID and timestamps.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["name", "slogan"], "type": "object", "properties": {"avatar": {"description": "Avatar image path (string) from temporary upload. First upload to /habibnet/upload-tmp-media/ and use the file value from response.", "type": "string", "example": "/tmp/xyz-avatar.jpg"}, "name": {"description": "Center name", "type": "string", "example": "Islamic Center of New York"}, "slogan": {"description": "Center slogan or tagline", "type": "string", "example": "Serving the community since 1990"}, "center_type": {"description": "Type of center", "type": "string", "enum": ["islamic_center", "library", "mosque", "shia_center"], "example": "islamic_center"}, "about_center": {"description": "Detailed description about the center", "type": "string", "example": "A comprehensive Islamic center offering prayer facilities..."}, "working_hours": {"description": "Working hours for each day of the week", "type": "object", "example": {"monday": "9:00 AM - 9:00 PM", "friday": "9:00 AM - 11:00 PM"}}, "social_medias": {"description": "List of social media links", "type": "array", "items": {"type": "object", "properties": {"platform": {"type": "string"}, "url": {"type": "string"}}}, "example": [{"platform": "facebook", "url": "https://facebook.com/center"}]}, "address": {"description": "Physical address of the center", "type": "string", "example": "123 Main Street, New York, NY 10001"}, "lat": {"description": "Latitude coordinate", "type": "number", "example": 40.7128}, "lon": {"description": "Longitude coordinate", "type": "number", "example": -74.006}, "images": {"description": "List of center images. Each image must be a string path from /habibnet/upload-tmp-media/", "type": "array", "items": {"type": "object", "properties": {"image": {"description": "Image path (string) from temporary upload", "type": "string", "example": "/tmp/xyz-image.jpg"}, "priority": {"description": "Display priority (higher = shown first)", "type": "integer", "default": 10}}}}}}}], "responses": {"201": {"description": "Center created successfully", "schema": {"type": "object", "properties": {"id": {"description": "Center ID", "type": "integer"}, "avatar": {"description": "Avatar URL", "type": "string"}, "name": {"description": "Center name", "type": "string"}, "slogan": {"description": "Center slogan", "type": "string"}, "center_type": {"description": "Center type", "type": "string"}, "about_center": {"description": "About center", "type": "string"}, "working_hours": {"description": "Working hours", "type": "object"}, "social_medias": {"description": "Social media links", "type": "array", "items": {"type": "object"}}, "address": {"description": "Address", "type": "string"}, "lat": {"description": "Latitude", "type": "number"}, "lon": {"description": "Longitude", "type": "number"}, "images": {"description": "Center images", "type": "array", "items": {"type": "object", "properties": {"id": {"type": "integer"}, "image": {"type": "string"}, "priority": {"type": "integer"}}}}, "status": {"description": "Approval status", "type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "examples": {"application/json": {"id": 1, "avatar": "https://habibapp.com/media/habibnet/avatars/center_avatar.jpg", "name": "Islamic Center of New York", "slogan": "Serving the community since 1990", "center_type": "islamic_center", "about_center": "A comprehensive Islamic center...", "working_hours": {"monday": "9:00 AM - 9:00 PM", "friday": "9:00 AM - 11:00 PM"}, "social_medias": [{"platform": "facebook", "url": "https://facebook.com/center"}], "address": "123 Main Street, New York, NY 10001", "lat": 40.7128, "lon": -74.006, "images": [{"id": 1, "image": "https://habibapp.com/media/habibnet/image1.jpg", "priority": 1}], "status": "pending", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z"}}}, "400": {"description": "Validation error", "examples": {"application/json": {"name": ["This field is required."], "center_type": ["Invalid center type. Must be one of: islamic_center, library, mosque, shia_center"]}}}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Provider not verified", "examples": {"application/json": {"detail": "You must have a verified provider profile to create centers."}}}}, "tags": ["habibnet"]}, "parameters": []}, "/habibnet/provider/center/{center_id}/events/": {"get": {"operationId": "habibnet_provider_center_events_list", "description": "\nList all events for a specific center owned by the provider.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n\n### Response Structure:\nReturns a list of all events for the specified center.\n\n### Example Response:\n```json\n[\n {\n \"id\": 1,\n \"title\": \"Friday Prayer\",\n \"description\": \"Weekly Friday congregational prayer\",\n \"time\": \"1:00 PM\",\n \"start_time\": \"2024-01-19T13:00:00Z\",\n \"end_time\": \"2024-01-19T14:00:00Z\",\n \"date\": \"2024-01-19T13:00:00Z\",\n \"image\": \"https://habibapp.com/media/habibnet/event1.jpg\",\n \"center\": 1\n }\n]\n```\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "center_id", "in": "path", "description": "ID of the center to list events for", "required": true, "type": "integer"}], "responses": {"200": {"description": "List of center events", "schema": {"type": "array", "items": {"type": "object", "properties": {"id": {"description": "Event ID", "type": "integer"}, "title": {"description": "Event title", "type": "string"}, "description": {"description": "Event description", "type": "string"}, "time": {"description": "Event time (text format)", "type": "string"}, "start_time": {"description": "Start time", "type": "string", "format": "date-time"}, "end_time": {"description": "End time", "type": "string", "format": "date-time"}, "date": {"description": "Event date", "type": "string", "format": "date-time"}, "image": {"description": "Event image URL", "type": "string"}, "center": {"description": "Center ID", "type": "integer"}}}}}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Not the owner", "examples": {"application/json": {"detail": "You do not have permission to view events for this center."}}}, "404": {"description": "Center not found"}}, "tags": ["habibnet"]}, "parameters": [{"name": "center_id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/provider/center/{center_id}/events/create/": {"post": {"operationId": "habibnet_provider_center_events_create_create", "description": "\nCreate a new event for a center owned by the provider.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Image must be uploaded via `/habibnet/upload-tmp-media/` endpoint first\n\n**IMPORTANT**: The image field must be a string URL (apath) from the upload endpoint, NOT binary file data.\n\n### Example Request:\n```json\n{\n \"title\": \"Friday Prayer\",\n \"description\": \"Weekly Friday congregational prayer. All community members are welcome.\",\n \"time\": \"1:00 PM\",\n \"start_time\": \"2024-01-19T13:00:00Z\",\n \"end_time\": \"2024-01-19T14:00:00Z\",\n \"date\": \"2024-01-19T13:00:00Z\",\n \"image\": \"/tmp/xyz-event-image.jpg\"\n}\n```\n\n### Response Structure:\nReturns the created event with all details including the full image URL.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["title", "description", "time", "date", "image"], "type": "object", "properties": {"title": {"description": "Event title", "type": "string", "example": "Friday Prayer", "maxLength": 119}, "description": {"description": "Detailed event description", "type": "string", "example": "Weekly Friday congregational prayer. All community members are welcome."}, "time": {"description": "Event time in text format", "type": "string", "example": "1:00 PM", "maxLength": 255}, "start_time": {"description": "Event start time (optional)", "type": "string", "format": "date-time", "example": "2024-01-19T13:00:00Z"}, "end_time": {"description": "Event end time (optional)", "type": "string", "format": "date-time", "example": "2024-01-19T14:00:00Z"}, "date": {"description": "Event date", "type": "string", "format": "date-time", "example": "2024-01-19T13:00:00Z"}, "image": {"description": "Event image path from temporary upload", "type": "string", "example": "/static/tmp/xyz-event-image.jpg"}}}}, {"name": "center_id", "in": "path", "description": "ID of the center to create event for", "required": true, "type": "integer"}], "responses": {"201": {"description": "Event created successfully", "schema": {"type": "object", "properties": {"id": {"description": "Event ID", "type": "integer"}, "title": {"description": "Event title", "type": "string"}, "description": {"description": "Event description", "type": "string"}, "time": {"description": "Event time", "type": "string"}, "start_time": {"description": "Start time", "type": "string", "format": "date-time"}, "end_time": {"description": "End time", "type": "string", "format": "date-time"}, "date": {"description": "Event date", "type": "string", "format": "date-time"}, "image": {"description": "Event image URL", "type": "string"}, "center": {"description": "Center ID", "type": "integer"}}}, "examples": {"application/json": {"id": 1, "title": "Friday Prayer", "description": "Weekly Friday congregational prayer. All community members are welcome.", "time": "1:00 PM", "start_time": "2024-01-19T13:00:00Z", "end_time": "2024-01-19T14:00:00Z", "date": "2024-01-19T13:00:00Z", "image": "https://habibapp.com/media/habibnet/event_image.jpg", "center": 1}}}, "400": {"description": "Validation error", "examples": {"application/json": {"title": ["This field is required."], "image": ["This field is required."]}}}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Not the owner", "examples": {"application/json": {"detail": "You do not have permission to create events for this center."}}}, "404": {"description": "Center not found"}}, "tags": ["habibnet"]}, "parameters": [{"name": "center_id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/provider/center/{center_id}/events/{event_id}/": {"patch": {"operationId": "habibnet_provider_center_events_partial_update", "description": "\nUpdate an existing event for a center owned by the provider (PATCH only - partial update).\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Event must belong to the specified center\n\n### Notes:\n- This endpoint supports partial updates (PATCH)\n- Only provided fields will be updated\n- Image can be updated by uploading via `/upload-tmp-media` endpoint first\n\n### Example Request:\n```json\n{\n \"title\": \"Updated Friday Prayer\",\n \"description\": \"Updated description for the weekly Friday prayer\",\n \"start_time\": \"2024-01-19T13:30:00Z\"\n}\n```\n\n### Response Structure:\nReturns the updated event with all current details.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"type": "object", "properties": {"title": {"description": "Event title", "type": "string", "example": "Updated Friday Prayer", "maxLength": 119}, "description": {"description": "Event description", "type": "string", "example": "Updated description for the weekly Friday prayer"}, "time": {"description": "Event time in text format", "type": "string", "example": "1:30 PM", "maxLength": 255}, "start_time": {"description": "Event start time", "type": "string", "format": "date-time", "example": "2024-01-19T13:30:00Z"}, "end_time": {"description": "Event end time", "type": "string", "format": "date-time", "example": "2024-01-19T14:30:00Z"}, "date": {"description": "Event date", "type": "string", "format": "date-time", "example": "2024-01-19T13:30:00Z"}, "image": {"description": "New event image path from temporary upload", "type": "string", "example": "/static/tmp/xyz-new-event-image.jpg"}}}}, {"name": "center_id", "in": "path", "description": "ID of the center", "required": true, "type": "integer"}, {"name": "event_id", "in": "path", "description": "ID of the event to update", "required": true, "type": "integer"}], "responses": {"200": {"description": "Event updated successfully", "schema": {"type": "object", "properties": {"id": {"description": "Event ID", "type": "integer"}, "title": {"description": "Event title", "type": "string"}, "description": {"description": "Event description", "type": "string"}, "time": {"description": "Event time", "type": "string"}, "start_time": {"description": "Start time", "type": "string", "format": "date-time"}, "end_time": {"description": "End time", "type": "string", "format": "date-time"}, "date": {"description": "Event date", "type": "string", "format": "date-time"}, "image": {"description": "Event image URL", "type": "string"}, "center": {"description": "Center ID", "type": "integer"}}}, "examples": {"application/json": {"id": 1, "title": "Updated Friday Prayer", "description": "Updated description for the weekly Friday prayer", "time": "1:30 PM", "start_time": "2024-01-19T13:30:00Z", "end_time": "2024-01-19T14:30:00Z", "date": "2024-01-19T13:30:00Z", "image": "https://habibapp.com/media/habibnet/event_image.jpg", "center": 1}}}, "400": {"description": "Validation error", "examples": {"application/json": {"title": ["Ensure this field has no more than 119 characters."]}}}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Not the owner", "examples": {"application/json": {"detail": "You do not have permission to update events for this center."}}}, "404": {"description": "Event or center not found", "examples": {"application/json": {"detail": "Not found."}}}}, "tags": ["habibnet"]}, "parameters": [{"name": "center_id", "in": "path", "required": true, "type": "string"}, {"name": "event_id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/provider/center/{center_id}/events/{event_id}/delete/": {"delete": {"operationId": "habibnet_provider_center_events_delete_delete", "description": "\nDelete an event for a center owned by the provider.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Event must belong to the specified center\n\n### Notes:\n- This action is permanent and cannot be undone\n- The event will be completely removed from the system\n\n### Response:\nReturns 204 No Content on successful deletion.\n", "parameters": [{"name": "center_id", "in": "path", "description": "ID of the center", "required": true, "type": "integer"}, {"name": "event_id", "in": "path", "description": "ID of the event to delete", "required": true, "type": "integer"}], "responses": {"204": {"description": "Event deleted successfully (No Content)"}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Not the owner", "examples": {"application/json": {"detail": "You do not have permission to delete events for this center."}}}, "404": {"description": "Event or center not found", "examples": {"application/json": {"detail": "Not found."}}}}, "tags": ["habibnet"]}, "parameters": [{"name": "center_id", "in": "path", "required": true, "type": "string"}, {"name": "event_id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/provider/center/{center_id}/images/{image_id}/": {"delete": {"operationId": "habibnet_provider_center_images_delete", "description": "\nDelete a specific image from a center's gallery.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Image must belong to the specified center\n\n### URL Parameters:\n- `center_id`: ID of the center\n- `image_id`: ID of the image to delete\n\n### Example Response:\n```json\n{\n \"detail\": \"Image deleted successfully\"\n}\n```\n\n### Notes:\n- This permanently deletes the image from storage\n- Cannot be undone\n- The image file is removed from the server\n", "parameters": [{"name": "center_id", "in": "path", "description": "ID of the center", "required": true, "type": "integer"}, {"name": "image_id", "in": "path", "description": "ID of the image to delete", "required": true, "type": "integer"}], "responses": {"204": {"description": "Image deleted successfully"}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Not the owner", "examples": {"application/json": {"detail": "You do not have permission to delete this image."}}}, "404": {"description": "Image or center not found", "examples": {"application/json": {"detail": "Image not found or does not belong to this center."}}}}, "tags": ["habibnet"]}, "parameters": [{"name": "center_id", "in": "path", "required": true, "type": "string"}, {"name": "image_id", "in": "path", "required": true, "type": "string"}]}, "/habibnet/provider/center/{id}/": {"patch": {"operationId": "habibnet_provider_center_partial_update", "description": "\nUpdate an existing center (PATCH only - partial update).\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Only the provider who created the center can update it\n\n### Notes:\n- This endpoint supports partial updates (PATCH)\n- Only provided fields will be updated\n- Images can be added but not removed via this endpoint (use DELETE endpoint for image removal)\n\n### Example Request:\n```json\n{\n \"slogan\": \"Updated slogan for the center\",\n \"about_center\": \"Updated description with more details\",\n \"working_hours\": {\n \"monday\": \"8:00 AM - 10:00 PM\",\n \"friday\": \"8:00 AM - 11:00 PM\"\n }\n}\n```\n\n### Response Structure:\nReturns the updated center with all current details.\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"type": "object", "properties": {"avatar": {"description": "New avatar image path from temporary upload", "type": "string"}, "name": {"description": "Center name", "type": "string"}, "slogan": {"description": "Center slogan", "type": "string"}, "center_type": {"description": "Type of center", "type": "string", "enum": ["islamic_center", "library", "mosque", "shia_center"]}, "about_center": {"description": "About the center", "type": "string"}, "working_hours": {"description": "Working hours", "type": "object"}, "social_medias": {"description": "Social media links", "type": "array", "items": {"type": "object", "properties": {"platform": {"type": "string"}, "url": {"type": "string"}}}}, "address": {"description": "Physical address", "type": "string"}, "lat": {"description": "Latitude", "type": "number"}, "lon": {"description": "Longitude", "type": "number"}, "images": {"description": "New images to add", "type": "array", "items": {"type": "object", "properties": {"image": {"type": "string"}, "priority": {"type": "integer", "default": 10}}}}}}}], "responses": {"200": {"description": "Center updated successfully", "schema": {"type": "object", "properties": {"id": {"type": "integer"}, "avatar": {"type": "string"}, "name": {"type": "string"}, "slogan": {"type": "string"}, "center_type": {"type": "string"}, "about_center": {"type": "string"}, "working_hours": {"type": "object"}, "social_medias": {"type": "array", "items": {"type": "object"}}, "address": {"type": "string"}, "lat": {"type": "number"}, "lon": {"type": "number"}, "images": {"type": "array", "items": {"type": "object"}}, "status": {"type": "string"}, "created_at": {"type": "string", "format": "date-time"}, "updated_at": {"type": "string", "format": "date-time"}}}, "examples": {"application/json": {"id": 1, "avatar": "https://habibapp.com/media/habibnet/avatars/center_avatar.jpg", "name": "Islamic Center of New York", "slogan": "Updated slogan for the center", "center_type": "islamic_center", "about_center": "Updated description with more details", "working_hours": {"monday": "8:00 AM - 10:00 PM", "friday": "8:00 AM - 11:00 PM"}, "social_medias": [{"platform": "facebook", "url": "https://facebook.com/center"}], "address": "123 Main Street, New York, NY 10001", "lat": 40.7128, "lon": -74.006, "images": [], "status": "pending", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T14:20:00Z"}}}, "400": {"description": "Validation error"}, "401": {"description": "Authentication required"}, "403": {"description": "Permission denied - Not the owner", "examples": {"application/json": {"detail": "You do not have permission to update this center."}}}, "404": {"description": "Center not found"}}, "tags": ["habibnet"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this center.", "required": true, "type": "integer"}]}, "/habibnet/provider/profile/": {"post": {"operationId": "habibnet_provider_profile_create", "summary": "API endpoint for creating center provider profiles.", "description": "This view handles provider requests for centers in Habibnet.\nUsers can request to become providers with two types:\n- management: Part of the center's management team\n- connected: Connected with the center's team", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/CenterProviderProfile"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/CenterProviderProfile"}}}, "tags": ["habibnet"]}, "parameters": []}, "/habit/challenge/list/": {"get": {"operationId": "habit_challenge_list_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ChallengeList"}}}}}}, "tags": ["habit"]}, "parameters": []}, "/habit/challenge/{id}/": {"get": {"operationId": "habit_challenge_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ChallengeDetail"}}}, "tags": ["habit"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Challenge.", "required": true, "type": "integer"}]}, "/habit/challenge/{id}/join/": {"post": {"operationId": "habit_challenge_join_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["habit"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/habit/checklist/create/": {"post": {"operationId": "habit_checklist_create_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserChecklistItem"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/UserChecklistItem"}}}, "tags": ["habit"]}, "parameters": []}, "/habit/checklist/list/": {"get": {"operationId": "habit_checklist_list_list", "description": "category (prayer, quran, duas, worship, challenge, general, custom, all)", "parameters": [{"name": "category", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/UserChecklistItem"}}}}}}, "tags": ["habit"]}, "parameters": []}, "/habit/checklist/mark-completed/": {"get": {"operationId": "habit_checklist_mark-completed_list", "description": "\n### ثبت وضعیت تکمیل چک لیست\nاین API وضعیت تکمیل یک چک لیست را برای تاریخ مشخص ثبت میکند. در صورت تکرار درخواست، وضعیت قبلی با تأیید جدید بهروغرسان میشود.\n\n| **فیلد** | **نوع** | **ضروری** | **توضیحات** |\n|----------|---------|-----------|-------------|\n| `checklist_id` | `integer` | بله | شناسه یکتای چک لیست |\n| `date` | `string` | نه | تاریخ در فرمت `YYYY-MM-DD` (پیشفرض: امروز) |\n| `day_of_week` | `string` | بله | روز هفته (مقدارهای مجاز: `monday`, `tuesday`, ..., `sunday`) |\n\n#### پاسخ:\n- **200 OK**: وضعیت تکمیل چک لیست\n- **400 Bad Request**: پارامترهای ورودی نامعتبر\n- **404 Not Found**: چک لیست موردنظر وجود ندارد\n- **500 Internal Server Error**: خطا در پردازش درخواست\n\n#### مثال پاسخ:\n```json\n{\n \"title\": \"تمرین ورزشی\",\n \"completed\": true\n}\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "date", "in": "query", "description": "Date in YYYY-MM-DD format", "required": true, "type": "string", "default": "2026-07-01"}, {"name": "checklist_id", "in": "query", "description": "Checklist ID", "required": true, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ChecklistEntryList"}}}, "tags": ["habit"]}, "parameters": []}, "/habit/checklist/report/": {"get": {"operationId": "habit_checklist_report_list", "description": "\n### آمار تکمیل چک لیست\nاین API آمار تکمیل چک لیست برای دوره های 7، 30 روز و یک سال گذشته را میگرداند. نتایج بر اساس روزهای فعال چک لیست محاسبه میشوند.\n\n| **فیلد** | **نوع** | **ضروری** | **توضیحات** |\n|----------|---------|-----------|-------------|\n| `checklist_id` | `integer` | بله | شناسه یکتای چک لیست |\n| `date` | `string` | نه | تاریخ در فرمت `YYYY-MM-DD` (پیشفرض: امروز) |\n| `day_of_week` | `string` | بله | روز هفته (مقدارهای مجاز: `monday`, `tuesday`, ..., `sunday`) |\n\n#### پاسخ:\n- **200 OK**: آمار تکمیل در فرمت زیر\n- **400 Bad Request**: پارامترهای ورودی نامعتبر\n- **404 Not Found**: چک لیست موردنظر وجود ندارد\n- **500 Internal Server Error**: خطا در پردازش درخواست\n\n#### مثال پاسخ:\n```json\n{\n \"7_days\": {\n \"total_days\": 5,\n \"completed_days\": 3,\n \"percentage\": 60.0\n },\n \"30_days\": {\n \"total_days\": 20,\n \"completed_days\": 15,\n \"percentage\": 75.0\n },\n \"year\": {\n \"total_days\": 365,\n \"completed_days\": 300,\n \"percentage\": 82.2\n }\n}\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "checklist_id", "in": "query", "description": "Checklist ID", "required": true, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ChecklistStats"}}}, "tags": ["habit"]}, "parameters": []}, "/habit/checklist/{id}/delete/": {"delete": {"operationId": "habit_checklist_delete_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["habit"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this User Checklist Item.", "required": true, "type": "integer"}]}, "/habit/checklist/{id}/detail/": {"get": {"operationId": "habit_checklist_detail_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ChecklistDetail"}}}, "tags": ["habit"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/habit/checklist/{id}/update/": {"put": {"operationId": "habit_checklist_update_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserChecklistItem"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserChecklistItem"}}}, "tags": ["habit"]}, "patch": {"operationId": "habit_checklist_update_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserChecklistItem"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserChecklistItem"}}}, "tags": ["habit"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this User Checklist Item.", "required": true, "type": "integer"}]}, "/habit/info/": {"get": {"operationId": "habit_info_list", "summary": "Main Page", "description": "\n### لیست چک لیست های فعال\nاین API لیست چک لیست های فعال کاربر را برای یک روز هفته و تاریخ خاص میگرداند. تنها چک لیست هایی که در بازه زمانی فعالیت و روزهای مجاز هستند نمایش داده میشوند.\n\n| **فیلد** | **نوع** | **ضروری** | **توضیحات** |\n|----------|---------|-----------|-------------|\n| `date` | `string` | نه | تاریخ در فرمت `YYYY-MM-DD` (پیشفرض: امروز) |\n| `day_of_week` | `string` | بله | روز هفته (مقدارهای مجاز: `monday`, `tuesday`, ..., `sunday`) |\n\n#### پاسخ:\n- **200 OK**: لیست چک لیست ها با وضعیت تکمیل\n- **400 Bad Request**: پارامترهای ورودی نامعتبر\n- **500 Internal Server Error**: خطا در پردازش درخواست\n\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "date", "in": "query", "description": "Date in YYYY-MM-DD format", "required": true, "type": "string", "default": "2026-07-01"}], "responses": {"200": {"description": ""}}, "tags": ["habit"]}, "parameters": []}, "/habit/reminder/info/": {"get": {"operationId": "habit_reminder_info_list", "description": "\n### اطلاعات یادآوری چک لیست\nاین API وضعیت یادآوری چک لیست کاربر را بررسی میکند و در صورت وجود یادآوری فعال، اطلاعات کامل آن را برمیگرداند.\n\n#### منطق کسب و کار:\n- بررسی وجود یادآوری چک لیست برای کاربر جاری\n- اگر یادآوری وجود داشته باشد و وضعیت آن فعال باشد: `has_active_reminder: true` و اطلاعات کامل یادآوری\n- اگر یادآوری وجود نداشته باشد یا وضعیت آن غیرفعال باشد: `has_active_reminder: false` و `reminder: null`\n\n#### پاسخ:\n- **200 OK**: اطلاعات یادآوری با موفقیت دریافت شد\n\n#### مثال پاسخ (یادآوری فعال):\n```json\n{\n \"has_active_reminder\": true,\n \"reminder\": {\n \"id\": 123,\n \"service_name\": \"habit\",\n \"object_id\": \"\",\n \"text\": \"Daily Checklist Reminder\",\n \"created_at\": \"2024-01-15T10:30:00Z\",\n \"call_time\": \"2024-01-16T09:00:00Z\",\n \"is_sent\": false,\n \"is_read\": false,\n \"status\": true,\n \"notif_data\": null\n }\n}\n```\n\n#### مثال پاسخ (بدون یادآوری فعال):\n```json\n{\n \"has_active_reminder\": false,\n \"reminder\": null\n}\n```\n", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "اطلاعات یادآوری با موفقیت دریافت شد", "schema": {"type": "object", "properties": {"has_active_reminder": {"description": "آیا یادآوری فعال وجود دارد", "type": "boolean"}, "reminder": {"description": "اطلاعات کامل یادآوری در صورت فعال بودن، در غیر این صورت null", "type": "object", "nullable": true}}}}}, "tags": ["habit"]}, "parameters": []}, "/habit/reminder/update/": {"put": {"operationId": "habit_reminder_update_update", "description": "API endpoint for updating habit reminder status.\nCreates reminder if it doesn't exist, updates if it exists.", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["habit"]}, "patch": {"operationId": "habit_reminder_update_partial_update", "description": "\nPartially update or create a habit reminder with specified status and optional call time.\n\n### Request Structure (PATCH):\n```json\n{\n \"status\": true, // Required: boolean - Whether reminder is active\n \"call_time\": \"09:30\" // Optional: string - Time in HH:MM format (24-hour)\n}\n```\n\n### Behavior:\n- If reminder doesn't exist: Creates new reminder with provided fields\n- If reminder exists: Updates only the provided fields (partial update)\n- call_time only updates when valid time format is provided (HH:MM)\n- Invalid, empty, or null call_time values are ignored (field remains unchanged)\n\n### Examples:\n- `{\"status\": true}` - Only update status, keep existing call_time\n- `{\"status\": false, \"call_time\": \"14:30\"}` - Update status and set call_time to 14:30\n- `{\"status\": false, \"call_time\": \"\"}` - Only update status, ignore empty call_time\n- `{\"status\": false, \"call_time\": null}` - Only update status, ignore null call_time\n- `{\"status\": true, \"call_time\": \"invalid\"}` - Only update status, ignore invalid time\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["status"], "type": "object", "properties": {"status": {"description": "Whether the habit reminder is active or not", "type": "boolean"}, "call_time": {"description": "Time when reminder should be triggered. Format: \"HH:MM\" (24-hour format). Optional - leave empty to clear.", "type": "string", "example": "09:30"}}}}], "responses": {"200": {"description": "Reminder status updated successfully", "schema": {"type": "object", "properties": {"message": {"type": "string"}, "status": {"type": "boolean"}}}}, "201": {"description": "Reminder created with specified status", "schema": {"type": "object", "properties": {"message": {"type": "string"}, "status": {"type": "boolean"}}}}, "400": {"description": "Invalid request parameters", "schema": {"type": "object", "properties": {"detail": {"type": "string"}}}}}, "tags": ["habit"]}, "parameters": []}, "/hadis/categories/": {"get": {"operationId": "hadis_categories_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/HadisCategory"}}}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/categories/{category}/": {"get": {"operationId": "hadis_categories_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Hadis"}}}}}}, "tags": ["hadis"]}, "parameters": [{"name": "category", "in": "path", "required": true, "type": "string"}]}, "/hadis/events/": {"get": {"operationId": "hadis_events_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/interests-items/": {"get": {"operationId": "hadis_interests-items_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Interest"}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/narrators/": {"get": {"operationId": "hadis_narrators_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Narrator"}}}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/narrators/{id}/": {"get": {"operationId": "hadis_narrators_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Hadis"}}}}}}, "tags": ["hadis"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hadis/resources/": {"get": {"operationId": "hadis_resources_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Resources"}}}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/search/{query}/": {"get": {"operationId": "hadis_search_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Hadis"}}}}}}, "tags": ["hadis"]}, "parameters": [{"name": "query", "in": "path", "required": true, "type": "string"}]}, "/hadis/stats/": {"get": {"operationId": "hadis_stats_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/trends/": {"get": {"operationId": "hadis_trends_list", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Trend"}}}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/trends/{trend}/": {"get": {"operationId": "hadis_trends_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Hadis"}}}}}}, "tags": ["hadis"]}, "parameters": [{"name": "trend", "in": "path", "required": true, "type": "string"}]}, "/hadis/user-hadises/": {"get": {"operationId": "hadis_user-hadises_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Hadis"}}}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/user-interests/": {"get": {"operationId": "hadis_user-interests_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserInterest"}}}, "tags": ["hadis"]}, "put": {"operationId": "hadis_user-interests_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserInterest"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserInterest"}}}, "tags": ["hadis"]}, "patch": {"operationId": "hadis_user-interests_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UserInterest"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UserInterest"}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/v2/categories/": {"get": {"operationId": "hadis_v2_categories_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/v2/hadis/": {"get": {"operationId": "hadis_v2_hadis_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/HadisSerializerV2"}}}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/v2/narrators/": {"get": {"operationId": "hadis_v2_narrators_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/NarratorSerializerV2"}}}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/v2/user-daily/": {"get": {"operationId": "hadis_v2_user-daily_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/v2/user-hadises/": {"get": {"operationId": "hadis_v2_user-hadises_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["hadis"]}, "parameters": []}, "/hadis/{id}/": {"get": {"operationId": "hadis_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Hadis"}}}, "tags": ["hadis"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this hadis.", "required": true, "type": "integer"}]}, "/hussainya/albums-search/": {"get": {"operationId": "hussainya_albums-search_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code", "type": "string"}, {"name": "s", "in": "query", "description": "Search term", "type": "string"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/AlbumList"}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/albums/": {"get": {"operationId": "hussainya_albums_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "topic_id", "in": "query", "description": "Filter by Topic ID", "type": "integer"}, {"name": "singer_slug", "in": "query", "description": "Filter by singer slug", "type": "string"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "search", "in": "query", "description": "Search term", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/AlbumList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/albums//": {"get": {"operationId": "hussainya_albums_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "topic_id", "in": "query", "description": "Filter by Topic ID", "type": "integer"}, {"name": "singer_slug", "in": "query", "description": "Filter by singer slug", "type": "string"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "search", "in": "query", "description": "Search term", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/AlbumList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/albums//{id}/": {"get": {"operationId": "hussainya_albums__read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/albums/{id}/": {"get": {"operationId": "hussainya_albums_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/albums/{id}/details/": {"get": {"operationId": "hussainya_albums_details_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/AlbumList"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/collections/": {"get": {"operationId": "hussainya_collections_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/CollectionList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/collections//": {"get": {"operationId": "hussainya_collections_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/CollectionList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/collections//{id}/": {"get": {"operationId": "hussainya_collections__read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/CollectionDetail"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/collections/{id}/": {"get": {"operationId": "hussainya_collections_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/CollectionDetail"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/albums/": {"get": {"operationId": "hussainya_dashboard_albums_list", "summary": "GET — لیست البوم‌ها با فیلترها\nPOST — ایجاد البوم جدید", "description": "Query params (GET):\n search جستجو در translations (icontains)\n status active | draft\n language_code کدهای زبان جداشده با کاما (fa,ar)\n order hijri → مرتب‌سازی بر اساس نزدیکیِ تاریخ قمری (get_albums_by_hijri_date)؛\n در غیر این صورت ترتیب پیش‌فرض (پین‌شده‌ها، سپس جدیدترین ساخت)\n page / page_size", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardAlbumRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_albums_create", "summary": "GET — لیست البوم‌ها با فیلترها\nPOST — ایجاد البوم جدید", "description": "Query params (GET):\n search جستجو در translations (icontains)\n status active | draft\n language_code کدهای زبان جداشده با کاما (fa,ar)\n order hijri → مرتب‌سازی بر اساس نزدیکیِ تاریخ قمری (get_albums_by_hijri_date)؛\n در غیر این صورت ترتیب پیش‌فرض (پین‌شده‌ها، سپس جدیدترین ساخت)\n page / page_size", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardAlbumInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardAlbumInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/albums/{id}/": {"get": {"operationId": "hussainya_dashboard_albums_read", "description": "GET /hussainya/dashboard/albums//\nPATCH /hussainya/dashboard/albums//\nDELETE /hussainya/dashboard/albums//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardAlbumRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_albums_partial_update", "description": "GET /hussainya/dashboard/albums//\nPATCH /hussainya/dashboard/albums//\nDELETE /hussainya/dashboard/albums//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardAlbumInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardAlbumInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_albums_delete", "description": "GET /hussainya/dashboard/albums//\nPATCH /hussainya/dashboard/albums//\nDELETE /hussainya/dashboard/albums//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/autocomplete/albums/": {"get": {"operationId": "hussainya_dashboard_autocomplete_albums_list", "description": "GET /hussainya/dashboard/autocomplete/albums/", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/_AlbumAutocomplete"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/autocomplete/genres/": {"get": {"operationId": "hussainya_dashboard_autocomplete_genres_list", "description": "GET /hussainya/dashboard/autocomplete/genres/", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/_GenreAutocomplete"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/autocomplete/publishers/": {"get": {"operationId": "hussainya_dashboard_autocomplete_publishers_list", "description": "GET /hussainya/dashboard/autocomplete/publishers/", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/_PublisherAutocomplete"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/autocomplete/singers/": {"get": {"operationId": "hussainya_dashboard_autocomplete_singers_list", "summary": "GET /hussainya/dashboard/autocomplete/singers/", "description": "Query params اضافه:\n singer_type madah | lecturer (پیش‌فرض: همه)", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/_SingerAutocomplete"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/autocomplete/songs/": {"get": {"operationId": "hussainya_dashboard_autocomplete_songs_list", "summary": "GET /hussainya/dashboard/autocomplete/songs/", "description": "پیکرِ آهنگِ فرم «بفرمایید روضه» — جستجوی صفحه‌بندی‌شده در عنوان/اسلاگ.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/_SongAutocomplete"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/autocomplete/tags/": {"get": {"operationId": "hussainya_dashboard_autocomplete_tags_list", "description": "GET /hussainya/dashboard/autocomplete/tags/", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/_TagAutocomplete"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/collections/": {"get": {"operationId": "hussainya_dashboard_collections_list", "summary": "GET — لیست مجموعه‌ها با فیلترها\nPOST — ایجاد مجموعهٔ جدید", "description": "Query params (GET):\n search جستجو در title (JSONField icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size\n\nترتیب: pin_to_top اول، سپس بقیه بر اساس نزدیکیِ تاریخ قمری به امروز.\nget_collections_by_hijri_date یک list برمی‌گرداند؛ DashboardPageNumberPagination\nبا list هم کار می‌کند (عیناً مثل البوم‌ها).", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardCollectionRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_collections_create", "summary": "GET — لیست مجموعه‌ها با فیلترها\nPOST — ایجاد مجموعهٔ جدید", "description": "Query params (GET):\n search جستجو در title (JSONField icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size\n\nترتیب: pin_to_top اول، سپس بقیه بر اساس نزدیکیِ تاریخ قمری به امروز.\nget_collections_by_hijri_date یک list برمی‌گرداند؛ DashboardPageNumberPagination\nبا list هم کار می‌کند (عیناً مثل البوم‌ها).", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardCollectionInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardCollectionInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/collections/{id}/": {"get": {"operationId": "hussainya_dashboard_collections_read", "description": "GET /hussainya/dashboard/collections//\nPATCH /hussainya/dashboard/collections//\nDELETE /hussainya/dashboard/collections//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardCollectionRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_collections_partial_update", "description": "GET /hussainya/dashboard/collections//\nPATCH /hussainya/dashboard/collections//\nDELETE /hussainya/dashboard/collections//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardCollectionInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardCollectionInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_collections_delete", "description": "GET /hussainya/dashboard/collections//\nPATCH /hussainya/dashboard/collections//\nDELETE /hussainya/dashboard/collections//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/collections/{id}/songs/": {"get": {"operationId": "hussainya_dashboard_collections_songs_list", "summary": "GET /hussainya/dashboard/collections//songs/?page=&page_size=", "description": "آهنگ‌های متصل به یک مجموعه — به ترتیب ordering آهنگ و id نزولی.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/discover/": {"post": {"operationId": "hussainya_dashboard_discover_create", "description": "On-demand discovery of a YouTube channel/page into ImportItems.", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/genres/": {"get": {"operationId": "hussainya_dashboard_genres_list", "summary": "GET — لیست ژانرها با فیلترها\nPOST — ایجاد ژانر جدید", "description": "Query params (GET):\n search جستجو در title/slug (icontains)\n limit / offset", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardGenreRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_genres_create", "summary": "GET — لیست ژانرها با فیلترها\nPOST — ایجاد ژانر جدید", "description": "Query params (GET):\n search جستجو در title/slug (icontains)\n limit / offset", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardGenreInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardGenreInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/genres/{id}/": {"get": {"operationId": "hussainya_dashboard_genres_read", "description": "GET /hussainya/dashboard/genres//\nPATCH /hussainya/dashboard/genres//\nDELETE /hussainya/dashboard/genres//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardGenreRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_genres_partial_update", "description": "GET /hussainya/dashboard/genres//\nPATCH /hussainya/dashboard/genres//\nDELETE /hussainya/dashboard/genres//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardGenreInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardGenreInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_genres_delete", "description": "GET /hussainya/dashboard/genres//\nPATCH /hussainya/dashboard/genres//\nDELETE /hussainya/dashboard/genres//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/home/albums/": {"get": {"operationId": "hussainya_dashboard_home_albums_list", "description": "GET /hussainya/dashboard/home/albums/?language_code=fa,ar", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/home/lives/": {"get": {"operationId": "hussainya_dashboard_home_lives_list", "description": "GET /hussainya/dashboard/home/lives/?language_code=fa,ar", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/home/maddahs/": {"get": {"operationId": "hussainya_dashboard_home_maddahs_list", "description": "GET /hussainya/dashboard/home/maddahs/?language_code=fa,ar&page=N&page_size=M", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SingersList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/home/popular/": {"get": {"operationId": "hussainya_dashboard_home_popular_list", "summary": "GET /hussainya/dashboard/home/popular/?language_code=fa,ar&page=N&page_size=M", "description": "محبوب‌ترین آهنگ‌ها برای گریدِ داشبورد، صفحه‌بندی‌شده (infinite scroll).\nAdmin-only؛ از ``language_code`` (تک‌زبانه یا کاما-سپریت) پشتیبانی می‌کند.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/home/speakers/": {"get": {"operationId": "hussainya_dashboard_home_speakers_list", "description": "GET /hussainya/dashboard/home/speakers/?language_code=fa,ar&page=N&page_size=M", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SingersList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/import-items/": {"get": {"operationId": "hussainya_dashboard_import-items_list", "description": "GET صف importها با فیلتر؛ POST ثبت لینک مستقیم و dispatch دریافت متادیتا.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ImportItemRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_import-items_create", "description": "GET صف importها با فیلتر؛ POST ثبت لینک مستقیم و dispatch دریافت متادیتا.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ImportItemCreate"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/ImportItemCreate"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/import-items/{id}/": {"get": {"operationId": "hussainya_dashboard_import-items_read", "description": "GET جزئیات؛ PATCH اصلاح متادیتای AI؛ DELETE حذف.", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ImportItemDetail"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_import-items_partial_update", "description": "GET جزئیات؛ PATCH اصلاح متادیتای AI؛ DELETE حذف.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ImportItemMetadata"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ImportItemMetadata"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_import-items_delete", "description": "GET جزئیات؛ PATCH اصلاح متادیتای AI؛ DELETE حذف.", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this import item.", "required": true, "type": "integer"}]}, "/hussainya/dashboard/import-items/{id}/cancel/": {"post": {"operationId": "hussainya_dashboard_import-items_cancel_create", "description": "Cancel an item so it is excluded from the active queue.", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/import-items/{id}/publish/": {"post": {"operationId": "hussainya_dashboard_import-items_publish_create", "description": "Manual publish — used for channel/scheduled items after admin approval.", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/import-items/{id}/retry/": {"post": {"operationId": "hussainya_dashboard_import-items_retry_create", "description": "Re-dispatch metadata fetch for a failed/stuck item.", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/import-jobs/": {"post": {"operationId": "hussainya_dashboard_import-jobs_create", "summary": "Batch link submission from the dashboard ``Add links`` panel.", "description": "Direct links create one ImportItem each (carrying the admin's manual\nmetadata + locked fields) and dispatch metadata fetch; channel/page links\nkick off discovery. Detection falls back to the server when source/kind is\nnot supplied by the client.", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/please/": {"get": {"operationId": "hussainya_dashboard_please_list", "summary": "GET — لیست روضه‌ها با فیلترها\nPOST — ایجاد روضهٔ جدید", "description": "Query params (GET):\n search جستجو در translations/live_title (icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardPleaseRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_please_create", "summary": "GET — لیست روضه‌ها با فیلترها\nPOST — ایجاد روضهٔ جدید", "description": "Query params (GET):\n search جستجو در translations/live_title (icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardPleaseInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardPleaseInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/please/{id}/": {"get": {"operationId": "hussainya_dashboard_please_read", "description": "GET /hussainya/dashboard/please//\nPATCH /hussainya/dashboard/please//\nDELETE /hussainya/dashboard/please//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardPleaseRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_please_partial_update", "description": "GET /hussainya/dashboard/please//\nPATCH /hussainya/dashboard/please//\nDELETE /hussainya/dashboard/please//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardPleaseInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardPleaseInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_please_delete", "description": "GET /hussainya/dashboard/please//\nPATCH /hussainya/dashboard/please//\nDELETE /hussainya/dashboard/please//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/please/{id}/songs/": {"get": {"operationId": "hussainya_dashboard_please_songs_list", "summary": "GET /hussainya/dashboard/please//songs/?page=&page_size=", "description": "آهنگ‌های متصل به یک روضه — به ترتیب priority و در شکل پخش‌پذیر\n(`SongsListSerializer`، همان شکل آهنگ‌های پنل آلبوم) برای پنل جزئیات.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/publishers/": {"get": {"operationId": "hussainya_dashboard_publishers_list", "summary": "GET — لیست ناشران با فیلترها\nPOST — ایجاد ناشر جدید", "description": "Query params (GET):\n search جستجو در name (icontains)\n type YT | IT | WS | TG | AP\n language_code کدهای زبان جداشده با کاما (fa,ar)\n page / page_size", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardPublisherRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_publishers_create", "summary": "GET — لیست ناشران با فیلترها\nPOST — ایجاد ناشر جدید", "description": "Query params (GET):\n search جستجو در name (icontains)\n type YT | IT | WS | TG | AP\n language_code کدهای زبان جداشده با کاما (fa,ar)\n page / page_size", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardPublisherInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardPublisherInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/publishers/{id}/": {"get": {"operationId": "hussainya_dashboard_publishers_read", "description": "GET /hussainya/dashboard/publishers//\nPATCH /hussainya/dashboard/publishers//\nDELETE /hussainya/dashboard/publishers//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardPublisherRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_publishers_partial_update", "description": "GET /hussainya/dashboard/publishers//\nPATCH /hussainya/dashboard/publishers//\nDELETE /hussainya/dashboard/publishers//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardPublisherInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardPublisherInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_publishers_delete", "description": "GET /hussainya/dashboard/publishers//\nPATCH /hussainya/dashboard/publishers//\nDELETE /hussainya/dashboard/publishers//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/runs/": {"get": {"operationId": "hussainya_dashboard_runs_list", "description": "History of discovery runs.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ImportRunRow"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/search/": {"get": {"operationId": "hussainya_dashboard_search_list", "description": "GET /hussainya/dashboard/search/?q=&types=&limit=", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/singers/": {"get": {"operationId": "hussainya_dashboard_singers_list", "summary": "Management list + create for dashboard maddahs/speakers.", "description": "GET /hussainya/dashboard/singers/ → لیست با فیلترها\nPOST /hussainya/dashboard/singers/ → ایجاد مداح/سخنران جدید\n\nQuery params (GET):\n - singer_type: all | madah | lecturer\n - status: all | active | draft\n - language_code: comma-separated language codes, e.g. fa,ar\n - search: text matched against translations JSON\n - page / page_size", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardSinger"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_singers_create", "summary": "Management list + create for dashboard maddahs/speakers.", "description": "GET /hussainya/dashboard/singers/ → لیست با فیلترها\nPOST /hussainya/dashboard/singers/ → ایجاد مداح/سخنران جدید\n\nQuery params (GET):\n - singer_type: all | madah | lecturer\n - status: all | active | draft\n - language_code: comma-separated language codes, e.g. fa,ar\n - search: text matched against translations JSON\n - page / page_size", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardSingerInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardSingerInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/singers/{identifier}/": {"get": {"operationId": "hussainya_dashboard_singers_read", "summary": "Detail / update / delete for one dashboard singer/provider.", "description": "GET /hussainya/dashboard/singers//\nPATCH /hussainya/dashboard/singers//\nDELETE /hussainya/dashboard/singers//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardSinger"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_singers_partial_update", "summary": "Detail / update / delete for one dashboard singer/provider.", "description": "GET /hussainya/dashboard/singers//\nPATCH /hussainya/dashboard/singers//\nDELETE /hussainya/dashboard/singers//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardSingerInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardSingerInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_singers_delete", "summary": "Detail / update / delete for one dashboard singer/provider.", "description": "GET /hussainya/dashboard/singers//\nPATCH /hussainya/dashboard/singers//\nDELETE /hussainya/dashboard/singers//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "identifier", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/songs/": {"get": {"operationId": "hussainya_dashboard_songs_list", "summary": "GET — لیست آهنگ‌ها با فیلترها\nPOST — ایجاد آهنگ جدید", "description": "Query params (GET):\n search جستجو در عنوان (JSONField)\n genre id ژانر\n song_type audio | video | youtube\n singers idهای خواننده، جداشده با کاما (فیلتر دقیق)\n status active | draft\n singer_type madah | lecturer (فیلتر از طریق سینگرها)\n language_code کد زبان با کاما (fa,ar)\n page / page_size", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardSongRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_songs_create", "summary": "GET — لیست آهنگ‌ها با فیلترها\nPOST — ایجاد آهنگ جدید", "description": "Query params (GET):\n search جستجو در عنوان (JSONField)\n genre id ژانر\n song_type audio | video | youtube\n singers idهای خواننده، جداشده با کاما (فیلتر دقیق)\n status active | draft\n singer_type madah | lecturer (فیلتر از طریق سینگرها)\n language_code کد زبان با کاما (fa,ar)\n page / page_size", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardSongInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardSongInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/songs/{identifier}/": {"get": {"operationId": "hussainya_dashboard_songs_read", "description": "GET /hussainya/dashboard/songs//\nPATCH /hussainya/dashboard/songs//\nDELETE /hussainya/dashboard/songs//\n\nشناسه می‌تواند id عددی (از جدول مدیریت) یا slug (از کارت‌های صفحهٔ خانه/جستجو)\nباشد؛ هم‌رفتار با DashboardSingerDetailView. این‌طور پنل آهنگ همیشه با یک API\nواحد دیتای کامل (تصویر + فایل) را می‌گیرد، چه از جدول باز شود چه از خانه.", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardSongRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_songs_partial_update", "description": "GET /hussainya/dashboard/songs//\nPATCH /hussainya/dashboard/songs//\nDELETE /hussainya/dashboard/songs//\n\nشناسه می‌تواند id عددی (از جدول مدیریت) یا slug (از کارت‌های صفحهٔ خانه/جستجو)\nباشد؛ هم‌رفتار با DashboardSingerDetailView. این‌طور پنل آهنگ همیشه با یک API\nواحد دیتای کامل (تصویر + فایل) را می‌گیرد، چه از جدول باز شود چه از خانه.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardSongInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardSongInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_songs_delete", "description": "GET /hussainya/dashboard/songs//\nPATCH /hussainya/dashboard/songs//\nDELETE /hussainya/dashboard/songs//\n\nشناسه می‌تواند id عددی (از جدول مدیریت) یا slug (از کارت‌های صفحهٔ خانه/جستجو)\nباشد؛ هم‌رفتار با DashboardSingerDetailView. این‌طور پنل آهنگ همیشه با یک API\nواحد دیتای کامل (تصویر + فایل) را می‌گیرد، چه از جدول باز شود چه از خانه.", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "identifier", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/source-tasks/": {"get": {"operationId": "hussainya_dashboard_source-tasks_list", "description": "CRUD list/create for periodic channel watchers.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ImportSourceTaskRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_source-tasks_create", "description": "CRUD list/create for periodic channel watchers.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ImportSourceTaskInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/ImportSourceTaskInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/source-tasks/{id}/": {"get": {"operationId": "hussainya_dashboard_source-tasks_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ImportSourceTaskRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_source-tasks_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ImportSourceTaskInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ImportSourceTaskInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_source-tasks_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this import source task.", "required": true, "type": "integer"}]}, "/hussainya/dashboard/source-tasks/{id}/run-now/": {"post": {"operationId": "hussainya_dashboard_source-tasks_run-now_create", "description": "Trigger a periodic task's discovery immediately (admin 'run now').", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/tags/": {"get": {"operationId": "hussainya_dashboard_tags_list", "summary": "GET — لیست تگ‌ها با فیلترها\nPOST — ایجاد تگ جدید", "description": "Query params (GET):\n search جستجو در title/translations\n page / page_size", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DashboardTagRow"}}}}}}, "tags": ["hussainya"]}, "post": {"operationId": "hussainya_dashboard_tags_create", "summary": "GET — لیست تگ‌ها با فیلترها\nPOST — ایجاد تگ جدید", "description": "Query params (GET):\n search جستجو در title/translations\n page / page_size", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardTagInput"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/DashboardTagInput"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/dashboard/tags/{id}/": {"get": {"operationId": "hussainya_dashboard_tags_read", "description": "GET /hussainya/dashboard/tags//\nPATCH /hussainya/dashboard/tags//\nDELETE /hussainya/dashboard/tags//", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardTagRow"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_dashboard_tags_partial_update", "description": "GET /hussainya/dashboard/tags//\nPATCH /hussainya/dashboard/tags//\nDELETE /hussainya/dashboard/tags//", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/DashboardTagInput"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DashboardTagInput"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_dashboard_tags_delete", "description": "GET /hussainya/dashboard/tags//\nPATCH /hussainya/dashboard/tags//\nDELETE /hussainya/dashboard/tags//", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/dashboard/upload-media/": {"post": {"operationId": "hussainya_dashboard_upload-media_create", "description": "آپلود فایل موقت برای فرم‌های داشبورد — admin-only.", "parameters": [{"name": "file", "in": "formData", "required": true, "type": "file"}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/_Upload"}}}, "consumes": ["multipart/form-data", "application/x-www-form-urlencoded"], "tags": ["hussainya"]}, "parameters": []}, "/hussainya/genre-list/": {"get": {"operationId": "hussainya_genre-list_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/get-youtube-info/": {"post": {"operationId": "hussainya_get-youtube-info_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"type": "object", "properties": {"youtube_link": {"type": "string"}}}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/YoutubeInfo"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/lives/": {"get": {"operationId": "hussainya_lives_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ShrineLive"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/playlist/": {"get": {"operationId": "hussainya_playlist_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/playlist//": {"get": {"operationId": "hussainya_playlist_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/provider/profile/": {"post": {"operationId": "hussainya_provider_profile_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/HussainiyaProviderProfileSerializer"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/HussainiyaProviderProfileSerializer"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/provider/songs/": {"get": {"operationId": "hussainya_provider_songs_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/provider/songs/create/": {"post": {"operationId": "hussainya_provider_songs_create_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/CreateSong"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/CreateSong"}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/provider/songs/{slug}/": {"put": {"operationId": "hussainya_provider_songs_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UpdateSong"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UpdateSong"}}}, "tags": ["hussainya"]}, "patch": {"operationId": "hussainya_provider_songs_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/UpdateSong"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/UpdateSong"}}}, "tags": ["hussainya"]}, "delete": {"operationId": "hussainya_provider_songs_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/publishers/": {"get": {"operationId": "hussainya_publishers_list", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Publisher"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/publishers//": {"get": {"operationId": "hussainya_publishers_list", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Publisher"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/publishers//{id}/": {"get": {"operationId": "hussainya_publishers__read", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "ordering", "in": "query", "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", "type": "string", "enum": ["like_counts", "-like_counts", "view_count", "-view_count", "created_at", "-created_at", "published_date", "-published_date"]}, {"name": "song_type", "in": "query", "description": "Filter by song type (audio, video, youtube)", "type": "string", "enum": ["audio", "video", "youtube"]}, {"name": "genre_id", "in": "query", "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", "type": "string"}, {"name": "random", "in": "query", "description": "Filter Random Palyer", "type": "boolean"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/publishers/{id}/": {"get": {"operationId": "hussainya_publishers_read", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "ordering", "in": "query", "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", "type": "string", "enum": ["like_counts", "-like_counts", "view_count", "-view_count", "created_at", "-created_at", "published_date", "-published_date"]}, {"name": "song_type", "in": "query", "description": "Filter by song type (audio, video, youtube)", "type": "string", "enum": ["audio", "video", "youtube"]}, {"name": "genre_id", "in": "query", "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", "type": "string"}, {"name": "random", "in": "query", "description": "Filter Random Palyer", "type": "boolean"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/pwa/collections/": {"get": {"operationId": "hussainya_pwa_collections_list", "summary": "Unified collection list for the PWA home (``pwa/collections``).", "description": "Returns one flat list where the **user's own** collections\n(``PlaylistCollection``) come first, followed by the **public**\ncollections (``Collection``). The response shape is identical for both\nsources — ``{id, title, songs}`` — with no ``type`` field.", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/pwa/home/": {"get": {"operationId": "hussainya_pwa_home_list", "summary": "PWA home — the same payload as ``HomePageV3`` but only the\nmadah / lecturer / event sections.", "description": "These three sections carry no per-user data (the singer/album serializers\nhave no ``is_liked``/``is_playlist`` fields), so the payload is fully\nshareable. It is cached per language under its own key and served without\nthe per-user ``personalize`` step.\n\nEach section also exposes a stable ``key`` alongside the (translated)\n``title`` so the client can identify sections without depending on the\nlocalized title string.", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/pwa/playlist/collections/": {"get": {"operationId": "hussainya_pwa_playlist_collections_list", "summary": "Collection list for the PWA **playlist tab** (``pwa/playlist/collections``).", "description": "Differs from ``PWACollectionsView`` (home) in three ways:\n * **lightweight** — metadata only, no embedded songs, so it is cheap and\n paginated;\n * **keeps empty collections** — a freshly created user collection with no\n songs must still appear;\n * **paginated** — ``DashboardPageNumberPagination`` (``page``/``page_size``).", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/PlaylistTabCollection"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/pwa/playlist/collections/{cid}/songs/": {"get": {"operationId": "hussainya_pwa_playlist_collections_songs_list", "summary": "Songs of a single playlist-tab collection — unified across both sources.", "description": "The ``cid`` path arg is the **prefixed** id used everywhere in the PWA:\n * ``u`` → user collection (``PlaylistCollection`` via ``Playlist``);\n * ``p`` → public collection (``Collection.get_songs``).\n\nBoth branches are language-ordered (same priority as the home popular row),\nannotated with per-user ``is_liked``, prefetched against N+1, paginated, and\nserialized with ``SongsListSerializer``. An empty collection returns an empty\npage (200), never 404.", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "page_size", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "cid", "in": "path", "required": true, "type": "string"}]}, "/hussainya/singers-search/": {"get": {"operationId": "hussainya_singers-search_list", "description": "", "parameters": [{"name": "s", "in": "query", "description": "Search", "type": "string"}, {"name": "language_code", "in": "query", "description": "Language Code", "type": "string"}], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/singers/": {"get": {"operationId": "hussainya_singers_list", "description": "Advanced Singer List API with PostgreSQL-optimized search functionality", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "singer_type", "in": "query", "description": "Singer Type", "type": "string", "enum": ["lecturer", "madah", "singer"]}, {"name": "search", "in": "query", "description": "Search term", "type": "string"}, {"name": "album_id", "in": "query", "description": "Album ID", "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SingersList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/singers//": {"get": {"operationId": "hussainya_singers_list", "description": "Advanced Singer List API with PostgreSQL-optimized search functionality", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "singer_type", "in": "query", "description": "Singer Type", "type": "string", "enum": ["lecturer", "madah", "singer"]}, {"name": "search", "in": "query", "description": "Search term", "type": "string"}, {"name": "album_id", "in": "query", "description": "Album ID", "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SingersList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/singers//{slug}/": {"get": {"operationId": "hussainya_singers__read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SingerSong"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/singers/{slug}/": {"get": {"operationId": "hussainya_singers_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SingerSong"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/": {"get": {"operationId": "hussainya_songs_list", "description": "ordering : ('like_count', 'view_count','created_at', 'published_date')", "parameters": [{"name": "song_type", "in": "query", "description": "Filter by song type (audio, video, youtube)", "type": "string", "enum": ["audio", "video", "youtube"]}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "ordering", "in": "query", "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", "type": "string", "enum": ["like_counts", "-like_counts", "view_count", "-view_count", "created_at", "-created_at", "published_date", "-published_date"]}, {"name": "genre_id", "in": "query", "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", "type": "string"}, {"name": "random", "in": "query", "description": "Filter Random Palyer", "type": "boolean"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/songs//": {"get": {"operationId": "hussainya_songs_list", "description": "ordering : ('like_count', 'view_count','created_at', 'published_date')", "parameters": [{"name": "song_type", "in": "query", "description": "Filter by song type (audio, video, youtube)", "type": "string", "enum": ["audio", "video", "youtube"]}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "ordering", "in": "query", "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", "type": "string", "enum": ["like_counts", "-like_counts", "view_count", "-view_count", "created_at", "-created_at", "published_date", "-published_date"]}, {"name": "genre_id", "in": "query", "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", "type": "string"}, {"name": "random", "in": "query", "description": "Filter Random Palyer", "type": "boolean"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/songs//download/{slug}/": {"get": {"operationId": "hussainya_songs__download_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs//increase-view/{slug}/": {"get": {"operationId": "hussainya_songs__increase-view_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs//like/{slug}/": {"get": {"operationId": "hussainya_songs__like_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs//unlike/{slug}/": {"get": {"operationId": "hussainya_songs__unlike_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs//{slug}/": {"get": {"operationId": "hussainya_songs__read", "description": "song details api\n-- params: song slug", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SongDetail"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/add-to-playlist/{slug}/": {"get": {"operationId": "hussainya_songs_add-to-playlist_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/download/{slug}/": {"get": {"operationId": "hussainya_songs_download_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/increase-view/{slug}/": {"get": {"operationId": "hussainya_songs_increase-view_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/like/{slug}/": {"get": {"operationId": "hussainya_songs_like_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/recent/": {"get": {"operationId": "hussainya_songs_recent_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "days", "in": "query", "description": "Number of days to filter recent songs", "type": "integer", "default": 60}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/songs/remove-from-playlist/{slug}/": {"get": {"operationId": "hussainya_songs_remove-from-playlist_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/unlike/{slug}/": {"get": {"operationId": "hussainya_songs_unlike_read", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/songs/{slug}/": {"get": {"operationId": "hussainya_songs_read", "description": "song details api\n-- params: song slug", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/SongDetail"}}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/statistics/": {"get": {"operationId": "hussainya_statistics_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/statistics//": {"get": {"operationId": "hussainya_statistics_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/topics/{topic_id}/albums/": {"get": {"operationId": "hussainya_topics_albums_list", "description": "Return albums belonging to a specific topic using topic_id in path.", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, ar)", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/AlbumList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "topic_id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/albums//{id}/": {"get": {"operationId": "hussainya_v2_albums__read", "description": "", "parameters": [{"name": "singer_type", "in": "query", "description": "Type of singers to filter (lecture, madah, singer)", "type": "string", "enum": ["lecturer", "madah", "singer"]}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "type", "in": "query", "description": "Type of songs to filter (audio, video, youtube)", "type": "string", "enum": ["audio", "video", "youtube"]}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "singer_slug", "in": "query", "description": "Comma-separated SingerSlug (e.g, mahmoud-karimi-2, huseyn-taheri) Slugs", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/albums/{id}/": {"get": {"operationId": "hussainya_v2_albums_read", "description": "", "parameters": [{"name": "singer_type", "in": "query", "description": "Type of singers to filter (lecture, madah, singer)", "type": "string", "enum": ["lecturer", "madah", "singer"]}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "type", "in": "query", "description": "Type of songs to filter (audio, video, youtube)", "type": "string", "enum": ["audio", "video", "youtube"]}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}, {"name": "singer_slug", "in": "query", "description": "Comma-separated SingerSlug (e.g, mahmoud-karimi-2, huseyn-taheri) Slugs", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/collections//{id}/": {"get": {"operationId": "hussainya_v2_collections__read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/collections/{id}/": {"get": {"operationId": "hussainya_v2_collections_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/home/": {"get": {"operationId": "hussainya_v2_home_list", "description": "home page API", "parameters": [{"name": "hijri-date", "in": "query", "description": "eg. 01/09 (MONTH/DAY) ", "type": "string"}], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/v2/playlist/add/": {"post": {"operationId": "hussainya_v2_playlist_add_create", "description": "افزودن آهنگ به پلی لیست در کالکشن", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/v2/playlist/collections/create/": {"post": {"operationId": "hussainya_v2_playlist_collections_create_create", "description": "ایجاد کالکشن جدید", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/v2/playlist/collections/list/": {"get": {"operationId": "hussainya_v2_playlist_collections_list_list", "description": "لیست کالکشن‌های کاربر با قابلیت سرچ", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/hussainya/v2/playlist/collections/{collection_id}/delete/": {"delete": {"operationId": "hussainya_v2_playlist_collections_delete_delete", "description": "حذف کالکشن", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "collection_id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/playlist/collections/{collection_id}/songs/": {"get": {"operationId": "hussainya_v2_playlist_collections_songs_list", "description": "لیست آهنگ‌های یک کالکشن با قابلیت سرچ", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "collection_id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/playlist/collections/{collection_id}/update/": {"patch": {"operationId": "hussainya_v2_playlist_collections_update_partial_update", "description": "آپدیت نام کالکشن", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": [{"name": "collection_id", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/singers//{slug}/": {"get": {"operationId": "hussainya_v2_singers__read", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "album_id", "in": "query", "description": "Comma-separated Album IDs(e.g, 733, 530)", "type": "string"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v2/singers/{slug}/": {"get": {"operationId": "hussainya_v2_singers_read", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "album_id", "in": "query", "description": "Comma-separated Album IDs(e.g, 733, 530)", "type": "string"}, {"name": "language_code", "in": "query", "description": "Language Code (e.g., en, fa, es)", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/SongsList"}}}}}}, "tags": ["hussainya"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/hussainya/v3/home/": {"get": {"operationId": "hussainya_v3_home_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["hussainya"]}, "parameters": []}, "/important-notices/": {"get": {"operationId": "important-notices_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/ImportantNotice"}}}}}}, "tags": ["important-notices"]}, "parameters": []}, "/khatm/groups/": {"get": {"operationId": "khatm_groups_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "Filter to show only the groups page", "type": "string", "enum": ["created", "joined"]}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/GroupKhatm"}}}}}}, "tags": ["khatm"]}, "post": {"operationId": "khatm_groups_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GroupKhatm"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/GroupKhatm"}}}, "tags": ["khatm"]}, "parameters": []}, "/khatm/groups/{slug}/": {"get": {"operationId": "khatm_groups_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/GroupKhatm"}}}, "tags": ["khatm"]}, "put": {"operationId": "khatm_groups_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GroupKhatm"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/GroupKhatm"}}}, "tags": ["khatm"]}, "patch": {"operationId": "khatm_groups_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/GroupKhatm"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/GroupKhatm"}}}, "tags": ["khatm"]}, "delete": {"operationId": "khatm_groups_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["khatm"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string", "format": "slug", "pattern": "^[-\\w]+$"}]}, "/khatm/groups/{slug}/join/": {"post": {"operationId": "khatm_groups_join_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["pages_count"], "type": "object", "properties": {"pages_count": {"description": "Number of pages to read", "type": "integer"}}}}], "responses": {"201": {"description": "", "schema": {"required": ["pages_count"], "type": "object", "properties": {"pages_count": {"description": "Number of pages to read", "type": "integer"}}}}}, "tags": ["khatm"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/khatm/groups/{slug}/read-page/": {"put": {"operationId": "khatm_groups_read-page_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReadPage"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ReadPage"}}}, "tags": ["khatm"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/khatm/individuals/": {"get": {"operationId": "khatm_individuals_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/IndividualKhatm"}}}}, "tags": ["khatm"]}, "post": {"operationId": "khatm_individuals_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/IndividualKhatm"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/IndividualKhatm"}}}, "tags": ["khatm"]}, "parameters": []}, "/khatm/individuals/{slug}/": {"put": {"operationId": "khatm_individuals_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/IndividualKhatmUpdate"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/IndividualKhatmUpdate"}}}, "tags": ["khatm"]}, "patch": {"operationId": "khatm_individuals_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/IndividualKhatmUpdate"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/IndividualKhatmUpdate"}}}, "tags": ["khatm"]}, "delete": {"operationId": "khatm_individuals_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["khatm"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string", "format": "slug", "pattern": "^[-\\w]+$"}]}, "/khatm/individuals/{slug}/read-page/": {"put": {"operationId": "khatm_individuals_read-page_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/IndividualReadPage"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/IndividualReadPage"}}}, "tags": ["khatm"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/khatm/joined-groups/": {"get": {"operationId": "khatm_joined-groups_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/UserGroupKhatm"}}}}, "tags": ["khatm"]}, "parameters": []}, "/library/banner-bottom/": {"get": {"operationId": "library_banner-bottom_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/BannerList"}}}}, "tags": ["library"]}, "parameters": []}, "/library/banner/": {"get": {"operationId": "library_banner_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/BannerList"}}}}, "tags": ["library"]}, "parameters": []}, "/library/banner/{id}/": {"get": {"operationId": "library_banner_read", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookList"}}}}}}, "tags": ["library"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/library/bookmark/": {"get": {"operationId": "library_bookmark_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookmarkSerializers"}}}}}}, "tags": ["library"]}, "post": {"operationId": "library_bookmark_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/BookmarkSerializers"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/BookmarkSerializers"}}}, "tags": ["library"]}, "parameters": []}, "/library/bookmark/remove/{slug}/": {"post": {"operationId": "library_bookmark_remove_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/": {"get": {"operationId": "library_books_list", "description": "", "parameters": [{"name": "audio", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "nonfree", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "size", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "publisher", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "authors", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "category", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "order", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookList"}}}}}}, "tags": ["library"]}, "parameters": []}, "/library/books/editorsuggestions/": {"get": {"operationId": "library_books_editorsuggestions_list", "description": "", "parameters": [{"name": "audio", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "nonfree", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "size", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "publisher", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "authors", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "category", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "order", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/BookListSerializerEditorSuggestion"}}}}, "tags": ["library"]}, "parameters": []}, "/library/books/rate/{slug}/": {"post": {"operationId": "library_books_rate_create", "summary": "Rate a book", "description": "Allows users to rate a book and optionally provide a note about the book.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["rate"], "type": "object", "properties": {"rate": {"description": "Rating for the book (0 to 10)", "type": "integer", "example": 8}, "note": {"description": "Optional note about the book (max 512 characters)", "type": "string", "example": "This book was amazing!"}}}}, {"name": "slug", "in": "path", "description": "Slug of the book to be rated", "required": true, "type": "string"}], "responses": {"200": {"description": "Rate submitted successfully", "examples": {"application/json": {"status": true, "message": "rate submitted"}}}, "400": {"description": "Invalid input or book not found", "examples": {"application/json": {"status": false, "message": "rate must be between 0 and 10"}}}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/user-downloads/": {"get": {"operationId": "library_books_user-downloads_list", "summary": "Redesign v2", "description": "", "parameters": [{"name": "audio", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "nonfree", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "size", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "publisher", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "authors", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "category", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "order", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookListV2"}}}}}}, "tags": ["library"]}, "parameters": []}, "/library/books/{slug}/": {"get": {"operationId": "library_books_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/BookDetail"}}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/{slug}/download/": {"post": {"operationId": "library_books_download_create", "summary": "Redesign v2", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/{slug}/purchase/": {"post": {"operationId": "library_books_purchase_create", "description": "", "parameters": [], "responses": {"201": {"description": ""}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/{slug}/rates/": {"get": {"operationId": "library_books_rates_list", "summary": "Redesign v2", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/UserRate"}}}}}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/{slug}/related/": {"get": {"operationId": "library_books_related_list", "description": "", "parameters": [{"name": "audio", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "nonfree", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "size", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "publisher", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "authors", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "category", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "order", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookList"}}}}}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/books/{slug}/v2/": {"get": {"operationId": "library_books_v2_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/BookDetail"}}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/category/": {"get": {"operationId": "library_category_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Category"}}}}}}, "tags": ["library"]}, "parameters": []}, "/library/getFilters/": {"get": {"operationId": "library_getFilters_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/publish/authors-list/": {"get": {"operationId": "library_publish_authors-list_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/publish/categories-list/": {"get": {"operationId": "library_publish_categories-list_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/publish/create/": {"post": {"operationId": "library_publish_create_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/CreateBook"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/CreateBook"}}}, "tags": ["library"]}, "parameters": []}, "/library/publish/narrators-list/": {"get": {"operationId": "library_publish_narrators-list_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/publish/tags-search/": {"get": {"operationId": "library_publish_tags-search_list", "description": "", "parameters": [{"name": "s", "in": "query", "description": "Search by name", "type": "string"}], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/publish/translators-list/": {"get": {"operationId": "library_publish_translators-list_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/publishers/": {"get": {"operationId": "library_publishers_list", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/PublisherList"}}}}}}, "tags": ["library"]}, "parameters": []}, "/library/statistics/": {"get": {"operationId": "library_statistics_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["library"]}, "parameters": []}, "/library/v2/banner/{id}/": {"get": {"operationId": "library_v2_banner_read", "summary": "Redesign v2", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookListV2"}}}}}}, "tags": ["library"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/library/v2/books/": {"get": {"operationId": "library_v2_books_list", "description": "", "parameters": [{"name": "audio", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "nonfree", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "size", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "publisher", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "authors", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "category", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "order", "in": "query", "description": "", "required": false, "type": "string"}, {"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/BookListV2"}}}}}}, "tags": ["library"]}, "parameters": []}, "/library/v2/books/{slug}/": {"get": {"operationId": "library_v2_books_read", "summary": "Redesign v2", "description": "\n# 📘 Scenario 1\n اگر مقدار قیمت \n price کتاب\n برابر با صفر بود آن کتاب رایگان است در غیر این صورت اگر بیشتر از صفر بود\n دو مقدار discount_percentage و final_price\n هم بایستی در نظر گرفته شود که نشان دهنده مقدار درصد تخفیف و قیمت نهایی با تخفیف محاسبه شده است\n\n# 📘 Scenario 2\n اگر کاربر قصد خرید یا دانلود کتاب را داشت بایستی قبل از آن api \n دانلود کتاب فراخوانی شود \n library/books/ slug book /download/\n\n سپس اگر کتاب غیر رایگان بود به api مربوطه در سرویس حبیب کوین\n برای پرداخت هزینه کوین کتاب بایستی فراخوانی شود که مقدار نام سرویس برابر با \n book است\n و مقدار ابجکت ایدی برابر با ایدی این کتاب است \n\n## (دقت داشته باشید که اگر کتاب غیر رایگان بود ابتدا بایستی خریداری شود سپس دانلود شود)\n\n\n\n\n# مقادیر\n\n برمیگردان جزعیات یک کتاب را به وسیله اسلاگ آن کتاب,\n مقدار is_bookmark مشخص میکند کاربر این کتاب را بوک مارک کرده است bool,\n مقدار is_download مشخص میکند کاربر این کتاب را دانلود کرده است bool,\n\n مقدار user_rate که یک ابجکت از rate که مشخص کننده rate همین کتاب است به همراه مقدار user_rate که مشخص کننده مقدار rate است که کاربر داده است و ممکن است null هم باشد که ساختار آن مانند:\n\n ```json\n \"rates\": {\n \"rate\": 4,\n \"user_rate\": {\n \"note\": \"This book was amazing!\",\n \"rate\": 3\n }\n ```\n\n\n", "parameters": [], "responses": {"200": {"description": "Successful retrieval of book details.", "schema": {"$ref": "#/definitions/BookDetailV2"}}, "401": {"description": "Unauthorized. Authentication credentials were not provided or are invalid."}, "404": {"description": "Not Found. The book with the given slug does not exist."}}, "tags": ["library"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/library/writers/": {"get": {"operationId": "library_writers_list", "description": "", "parameters": [{"name": "search", "in": "query", "description": "A search term.", "required": false, "type": "string"}, {"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/AuthorList"}}}}}}, "tags": ["library"]}, "parameters": []}, "/mafatih-categories/": {"get": {"operationId": "mafatih-categories_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/MafatihCategories"}}}}, "tags": ["mafatih-categories"]}, "parameters": []}, "/mafatih-categories/v2/": {"get": {"operationId": "mafatih-categories_v2_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/DuaCategories"}}}}, "tags": ["mafatih-categories"]}, "parameters": []}, "/mafatih-dua-parts/": {"get": {"operationId": "mafatih-dua-parts_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MafatihDuaPart"}}}}}}, "tags": ["mafatih-dua-parts"]}, "parameters": []}, "/mafatih-dua-parts/v2/": {"get": {"operationId": "mafatih-dua-parts_v2_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DuaPartSerializer"}}}}}}, "tags": ["mafatih-dua-parts"]}, "parameters": []}, "/mafatih-duas/": {"get": {"operationId": "mafatih-duas_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MafatihDua"}}}}}}, "tags": ["mafatih-duas"]}, "parameters": []}, "/mafatih-duas/audios/{id}/": {"get": {"operationId": "mafatih-duas_audios_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DuaAudioDetail"}}}, "tags": ["mafatih-duas"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/mafatih-duas/dhikrs/": {"get": {"operationId": "mafatih-duas_dhikrs_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["mafatih-duas"]}, "parameters": []}, "/mafatih-duas/famous/": {"get": {"operationId": "mafatih-duas_famous_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["mafatih-duas"]}, "parameters": []}, "/mafatih-duas/location/": {"get": {"operationId": "mafatih-duas_location_list", "description": "Retrieve nearby duas based on the user's location.\nThis view takes the user's latitude and longitude as input and returns a list of duas within 20 kilometers,\nsorted by distance. Additionally, duas within 2 kilometers are prioritized based on the priority field.", "parameters": [{"name": "lat", "in": "query", "description": "Latitude of the location lat = {Mashhad : 36.2605, Karbala : 32.6160326} ", "type": "number"}, {"name": "lon", "in": "query", "description": "Longitude of the location lon = {Mashhad : 59.6168, Karbala : 44.0244229} ", "type": "number"}], "responses": {"200": {"description": ""}}, "tags": ["mafatih-duas"]}, "parameters": []}, "/mafatih-duas/v2/": {"get": {"operationId": "mafatih-duas_v2_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MafatihDuaSerializerV2"}}}}}}, "tags": ["mafatih-duas"]}, "parameters": []}, "/mafatih-duas/v3/": {"get": {"operationId": "mafatih-duas_v3_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/MafatihDuaSerializerV3"}}}}}}, "tags": ["mafatih-duas"]}, "parameters": []}, "/mafatih-duas/{id}/audios/": {"get": {"operationId": "mafatih-duas_audios_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DuaAudioList"}}}}}}, "tags": ["mafatih-duas"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/mafatih/{mafatih_dua_id}/reciters/": {"get": {"operationId": "mafatih_reciters_list", "description": "Retrieve a list of unique reciters for a given MafatihDua.", "parameters": [{"name": "show_all", "in": "query", "description": "If true, returns all reciters, otherwise returns only reciters related to the specified MafatihDua.", "type": "boolean", "default": false}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"type": "object", "properties": {"name": {"description": "Name of the reciter", "type": "string"}, "avatar": {"description": "URL of the reciter's avatar", "type": "string"}}}}}}, "tags": ["mafatih"]}, "parameters": [{"name": "mafatih_dua_id", "in": "path", "required": true, "type": "string"}]}, "/masaels/": {"get": {"operationId": "masaels_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Masael"}}}}, "tags": ["masaels"]}, "parameters": []}, "/masaels/marjaa-guide/": {"get": {"operationId": "masaels_marjaa-guide_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/MarjaaGuide"}}}}, "tags": ["masaels"]}, "parameters": []}, "/masaels/v2/": {"get": {"operationId": "masaels_v2_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/MasaelSerializerV2"}}}}, "tags": ["masaels"]}, "parameters": []}, "/notespace/create/": {"post": {"operationId": "notespace_create_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Note"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Note"}}}, "tags": ["notespace"]}, "parameters": []}, "/notespace/create/feedback/": {"post": {"operationId": "notespace_create_feedback_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/NoteFeedback"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/NoteFeedback"}}}, "tags": ["notespace"]}, "parameters": []}, "/notespace/feedbak/{note_id}/delete/": {"delete": {"operationId": "notespace_feedbak_delete_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["notespace"]}, "parameters": [{"name": "note_id", "in": "path", "required": true, "type": "string"}]}, "/notespace/list/{service}/": {"get": {"operationId": "notespace_list_read", "description": "Retrieve a list of Notes for a specific service and optionally a specific object.", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "service", "in": "path", "description": "Service type", "type": "string", "enum": ["quran", "mafatih", "hadis", "habit"], "required": true}, {"name": "object_id", "in": "query", "description": "Comma-separated list of Object IDs(e.g 1,2,5,...)", "required": false, "type": "string", "default": "1,2,4"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Note"}}}}}}, "tags": ["notespace"]}, "parameters": [{"name": "service", "in": "path", "required": true, "type": "string"}]}, "/notespace/list/{service}/{object_id}/": {"get": {"operationId": "notespace_list_read", "description": "Retrieve a list Note", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "service", "in": "path", "description": "Service type", "type": "string", "enum": ["quran", "mafatih", "hadis", "habit"], "required": true}, {"name": "object_id", "in": "path", "description": "Object ID for the note", "type": "integer", "required": true}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Note"}}}}}}, "tags": ["notespace"]}, "parameters": [{"name": "service", "in": "path", "required": true, "type": "string"}, {"name": "object_id", "in": "path", "required": true, "type": "integer"}]}, "/notespace/{id}/delete/": {"delete": {"operationId": "notespace_delete_delete", "description": "", "parameters": [], "responses": {"204": {"description": ""}}, "tags": ["notespace"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Note.", "required": true, "type": "integer"}]}, "/notespace/{id}/update/": {"put": {"operationId": "notespace_update_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Note"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Note"}}}, "tags": ["notespace"]}, "patch": {"operationId": "notespace_update_partial_update", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Note"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/Note"}}}, "tags": ["notespace"]}, "parameters": [{"name": "id", "in": "path", "description": "A unique integer value identifying this Note.", "required": true, "type": "integer"}]}, "/payment/methods/": {"get": {"operationId": "payment_methods_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["payment"]}, "parameters": []}, "/plans/": {"get": {"operationId": "plans_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Plan"}}}}}}, "tags": ["plans"]}, "parameters": []}, "/plans/subscribe/": {"post": {"operationId": "plans_subscribe_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Subscribe"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Subscribe"}}}, "tags": ["plans"]}, "parameters": []}, "/plans/subscription-history/": {"get": {"operationId": "plans_subscription-history_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Subscribe"}}}}}}, "tags": ["plans"]}, "parameters": []}, "/quran-juz/": {"get": {"operationId": "quran-juz_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranPart"}}}}}}, "tags": ["quran-juz"]}, "parameters": []}, "/quran-page/": {"get": {"operationId": "quran-page_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranPart"}}}}}}, "tags": ["quran-page"]}, "parameters": []}, "/quran-qaris/": {"get": {"operationId": "quran-qaris_list", "description": "", "parameters": [{"name": "type", "in": "query", "type": "string", "enum": ["reciter", "translation"]}], "responses": {"200": {"description": ""}}, "tags": ["quran-qaris"]}, "parameters": []}, "/quran-qaris/v2/": {"get": {"operationId": "quran-qaris_v2_list", "description": "", "parameters": [{"name": "type", "in": "query", "type": "string", "enum": ["reciter", "translation"]}], "responses": {"200": {"description": ""}}, "tags": ["quran-qaris"]}, "parameters": []}, "/quran-surahs-translation/": {"get": {"operationId": "quran-surahs-translation_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranSuraTranslation"}}}}}}, "tags": ["quran-surahs-translation"]}, "parameters": []}, "/quran-surahs/": {"get": {"operationId": "quran-surahs_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranSura"}}}}}}, "tags": ["quran-surahs"]}, "parameters": []}, "/quran-translators/": {"get": {"operationId": "quran-translators_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/QuranTranslators"}}}}, "tags": ["quran-translators"]}, "parameters": []}, "/quran-verses-localization/": {"get": {"operationId": "quran-verses-localization_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "translator_en", "in": "query", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranVerseLocalization"}}}}}}, "tags": ["quran-verses-localization"]}, "parameters": []}, "/quran-verses-translation/": {"get": {"operationId": "quran-verses-translation_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "translator_en", "in": "query", "type": "string"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranVerseTranslation"}}}}}}, "tags": ["quran-verses-translation"]}, "parameters": []}, "/quran-verses/": {"get": {"operationId": "quran-verses_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranVerse"}}}}}}, "tags": ["quran-verses"]}, "parameters": []}, "/quran-word-translation/": {"get": {"operationId": "quran-word-translation_list", "description": "", "parameters": [{"name": "surah_index", "in": "query", "type": "number"}, {"name": "verse_index", "in": "query", "type": "number"}, {"name": "language_code", "in": "query", "type": "string", "default": "en"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/QuranWordTranslation"}}}}, "tags": ["quran-word-translation"]}, "parameters": []}, "/religious_times/adhans/": {"get": {"operationId": "religious_times_adhans_list", "description": "adhan list api", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Adhan"}}}}}}, "tags": ["religious_times"]}, "parameters": []}, "/religious_times/pre-adhans/": {"get": {"operationId": "religious_times_pre-adhans_list", "description": "adhan list api", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Adhan"}}}}}}, "tags": ["religious_times"]}, "parameters": []}, "/reminders/": {"get": {"operationId": "reminders_list", "summary": "Get list of reminders for the authenticated user.", "description": "### Example JSON Response:\n```json\n{\n \"count\": 10,\n \"next\": \"http://example.com/api/reminders/?page=2\",\n \"previous\": null,\n \"results\": [\n {\n \"id\": 1,\n \"service_name\": \"meet\",\n \"object_id\": \"123\",\n \"text\": \"Don't forget about the meeting tomorrow\",\n \"created_at\": \"2024-01-15T10:30:00Z\",\n \"call_time\": \"2024-01-16T09:00:00Z\",\n \"is_sent\": false,\n \"is_read\": false,\n \"status\": true,\n }\n ]\n}\n```", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "service_name", "in": "query", "description": "Filter reminders by service name (e.g., 'meet', 'dua', etc.)", "required": false, "type": "string"}, {"name": "is_sent", "in": "query", "description": "Filter reminders by sent status", "required": false, "type": "boolean"}, {"name": "is_read", "in": "query", "description": "Filter reminders by read status", "required": false, "type": "boolean"}, {"name": "status", "in": "query", "description": "Filter reminders by active status", "required": false, "type": "boolean"}], "responses": {"200": {"description": "List of user reminders", "schema": {"type": "array", "items": {"$ref": "#/definitions/Reminder"}}}}, "tags": ["reminders"]}, "parameters": []}, "/reminders/{id}/": {"put": {"operationId": "reminders_update", "description": "Update reminder status fields (same as PATCH).", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/ReminderUpdate"}}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ReminderUpdate"}}}, "tags": ["reminders"]}, "patch": {"operationId": "reminders_partial_update", "summary": "Update reminder status fields.", "description": "### Example Request:\n```json\n{\n \"status\": false\n}\n```\n\n### Example Response:\n```json\n{\n\n \"status\": false\n}\n```", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"description": "At least one field must be provided", "required": [], "type": "object", "properties": {"status": {"description": "General status of the reminder", "type": "boolean"}}}}], "responses": {"200": {"description": "Reminder updated successfully", "schema": {"$ref": "#/definitions/ReminderUpdate"}}, "400": {"description": "Bad request - validation errors"}, "404": {"description": "Reminder not found"}, "403": {"description": "Permission denied - reminder belongs to another user"}}, "tags": ["reminders"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/report/": {"post": {"operationId": "report_create", "description": "", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"$ref": "#/definitions/Report"}}], "responses": {"201": {"description": "", "schema": {"$ref": "#/definitions/Report"}}}, "tags": ["report"]}, "parameters": []}, "/report/subjects/": {"get": {"operationId": "report_subjects_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Subject"}}}}}}, "tags": ["report"]}, "parameters": []}, "/service-versions/": {"get": {"operationId": "service-versions_list", "description": "\n# 📘 Scenario\nدر حبیب دیتا های بعضی از سرویس ها به صورت یک جا گرفته و ذخیره میشوند سمت کلاینت \nممکن است در مرور زمان این دیتا ها بر اساس محتوا تغییراتی داشته باشند بنابر این\nدر اینجا ما میتوانی به هر سرویس شماره ورژنی اختصاص دهیم بر اساس زبان\n(به طور مثال در احکام زبان فارسی ترجمه ای آپدیت میشود و بایستی داده جدیدی به کاربر نمایش دهیم)\nبنابر این میتوانیم به طور تخمینی یک زمانی را تعیین کنیم که این ای پی ای فراخوانی شود \nو اگر شماره ورژن سرویسی افزایش پیدا کرده بود آن دیتا را مجددا درخواست کنیم \nو بایستی برای هر کلاینت این شماره ورژن های سرویس را ذخیره و در هر بار مقایسه کنیم\n\n---\n\n## 🚀 درخواست API\n\nکاربر باید احراز هویت شده باشد و زبان درخواست از طریق `LANGUAGE_CODE` در تنظیمات کاربر مشخص می‌شود. این API تنها نسخه‌های مرتبط با زبان کاربر را باز می‌گرداند.\n\n\n## 📊 پاسخ‌ها\n\n| کد وضعیت | توضیحات |\n|----------|------------------------------------------------------------|\n| `200` | موفقیت‌آمیز - لیستی از آخرین نسخه‌های سرویس‌ها برمی‌گرداند |\n\n---\n\n## 📄 نمونه پاسخ موفقیت‌آمیز\n\n```json\n[\n {\n \"service\": \"ahkam\",\n \"version_number\": \"1.3\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-11-01T12:34:56Z\",\n \"app_intros\": [\n {\n \"title\": \"خوش آمدید به سرویس احکام\",\n \"summary\": \"این سرویس شامل احکام شرعی است\",\n \"image\": \"https://example.com/images/intro1.jpg\",\n \"priority\": 1\n },\n {\n \"title\": \"نحوه استفاده\",\n \"summary\": \"برای استفاده از سرویس احکام...\",\n \"image\": \"https://example.com/images/intro2.jpg\",\n \"priority\": 2\n }\n ],\n \"service_intros\": [\n {\n \"title\": \"به‌روزرسانی جدید\",\n \"summary\": \"در این نسخه ویژگی‌های جدیدی اضافه شده است\",\n \"image\": \"https://example.com/images/update1.jpg\",\n \"priority\": 1\n }\n ]\n },\n {\n \"service\": \"quran\",\n \"version_number\": \"2.1\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-10-20T10:24:36Z\",\n \"app_intros\": [],\n \"service_intros\": []\n }\n]\n```\n\n### 📋 توضیحات فیلدها\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `service` | string | شناسه (slug) سرویس |\n| `version_number` | string | شماره نسخه سرویس (مثال: \"1.3\") |\n| `language` | object | اطلاعات زبان شامل `code` و `name` |\n| `created_at` | datetime | تاریخ ایجاد نسخه |\n| `app_intros` | array | لیست اسلایدهای معرفی استاتیک (Onboarding) که برای تمام نسخه‌های سرویس یکسان است |\n| `service_intros` | array | لیست اسلایدهای معرفی مخصوص این نسخه (Update Note) |\n\n### 📝 ساختار هر آیتم در `app_intros` و `service_intros`:\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `title` | string | عنوان ترجمه شده بر اساس زبان درخواست |\n| `summary` | string | خلاصه ترجمه شده بر اساس زبان درخواست |\n| `image` | string\\|null | URL تصویر یا null در صورت عدم وجود |\n| `priority` | integer | اولویت نمایش (کمتر = اولویت بیشتر) |\n\n**نکته:** فیلدهای `title` و `summary` به صورت خودکار بر اساس زبان درخواست (`LANGUAGE_CODE`) ترجمه می‌شوند و فقط مقدار ترجمه شده (string) برگردانده می‌شود، نه دیکشنری کامل ترجمه‌ها.\n", "parameters": [{"name": "Authorization", "in": "header", "description": "Bearer token for authentication", "type": "string"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/ServiceVersion"}}}}, "tags": ["service-versions"]}, "parameters": []}, "/service-versions/v2/": {"get": {"operationId": "service-versions_v2_list", "description": "\n# 📘 Scenario\nدر حبیب دیتا های بعضی از سرویس ها به صورت یک جا گرفته و ذخیره میشوند سمت کلاینت \nممکن است در مرور زمان این دیتا ها بر اساس محتوا تغییراتی داشته باشند بنابر این\nدر اینجا ما میتوانی به هر سرویس شماره ورژنی اختصاص دهیم بر اساس زبان\n(به طور مثال در احکام زبان فارسی ترجمه ای آپدیت میشود و بایستی داده جدیدی به کاربر نمایش دهیم)\nبنابر این میتوانیم به طور تخمینی یک زمانی را تعیین کنیم که این ای پی ای فراخوانی شود \nو اگر شماره ورژن سرویسی افزایش پیدا کرده بود آن دیتا را مجددا درخواست کنیم \nو بایستی برای هر کلاینت این شماره ورژن های سرویس را ذخیره و در هر بار مقایسه کنیم\n\n---\n\n## 🚀 درخواست API\n\nکاربر باید احراز هویت شده باشد و زبان درخواست از طریق `LANGUAGE_CODE` در تنظیمات کاربر مشخص می‌شود. این API تنها نسخه‌های مرتبط با زبان کاربر را باز می‌گرداند.\n\n\n## 📊 پاسخ‌ها\n\n| کد وضعیت | توضیحات |\n|----------|------------------------------------------------------------|\n| `200` | موفقیت‌آمیز - لیستی از آخرین نسخه‌های سرویس‌ها برمی‌گرداند |\n\n---\n\n## 📄 نمونه پاسخ موفقیت‌آمیز\n\n```json\n[\n {\n \"service\": \"ahkam\",\n \"version_number\": \"1.3\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-11-01T12:34:56Z\",\n \"app_intros\": [\n {\n \"title\": \"خوش آمدید به سرویس احکام\",\n \"summary\": \"این سرویس شامل احکام شرعی است\",\n \"image\": \"https://example.com/images/intro1.jpg\",\n \"priority\": 1\n },\n {\n \"title\": \"نحوه استفاده\",\n \"summary\": \"برای استفاده از سرویس احکام...\",\n \"image\": \"https://example.com/images/intro2.jpg\",\n \"priority\": 2\n }\n ],\n \"service_intros\": [\n {\n \"title\": \"به‌روزرسانی جدید\",\n \"summary\": \"در این نسخه ویژگی‌های جدیدی اضافه شده است\",\n \"image\": \"https://example.com/images/update1.jpg\",\n \"priority\": 1\n }\n ]\n },\n {\n \"service\": \"quran\",\n \"version_number\": \"2.1\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-10-20T10:24:36Z\",\n \"app_intros\": [],\n \"service_intros\": []\n }\n]\n```\n\n### 📋 توضیحات فیلدها\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `service` | string | شناسه (slug) سرویس |\n| `version_number` | string | شماره نسخه سرویس (مثال: \"1.3\") |\n| `language` | object | اطلاعات زبان شامل `code` و `name` |\n| `created_at` | datetime | تاریخ ایجاد نسخه |\n| `app_intros` | array | لیست اسلایدهای معرفی استاتیک (Onboarding) که برای تمام نسخه‌های سرویس یکسان است |\n| `service_intros` | array | لیست اسلایدهای معرفی مخصوص این نسخه (Update Note) |\n\n### 📝 ساختار هر آیتم در `app_intros` و `service_intros`:\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `title` | string | عنوان ترجمه شده بر اساس زبان درخواست |\n| `summary` | string | خلاصه ترجمه شده بر اساس زبان درخواست |\n| `image` | string\\|null | URL تصویر یا null در صورت عدم وجود |\n| `priority` | integer | اولویت نمایش (کمتر = اولویت بیشتر) |\n\n**نکته:** فیلدهای `title` و `summary` به صورت خودکار بر اساس زبان درخواست (`LANGUAGE_CODE`) ترجمه می‌شوند و فقط مقدار ترجمه شده (string) برگردانده می‌شود، نه دیکشنری کامل ترجمه‌ها.\n", "parameters": [{"name": "Authorization", "in": "header", "description": "Bearer token for authentication", "type": "string"}], "responses": {"200": {"description": "Service versions with startup modal", "schema": {"type": "object", "properties": {"versions": {"type": "array", "items": {"type": "object"}}, "startup_modal": {"type": "object", "properties": {"id": {"type": "integer"}, "html_content": {"description": "Rendered HTML form content", "type": "string"}, "width_percentage": {"description": "Modal width in percentage", "type": "integer"}, "height_percentage": {"description": "Modal height in percentage", "type": "integer"}, "is_forced": {"type": "boolean"}}, "nullable": true}}}}}, "tags": ["service-versions"]}, "parameters": []}, "/share-app/": {"get": {"operationId": "share-app_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/ShareApp"}}}, "tags": ["share-app"]}, "parameters": []}, "/tafsir/book/{book}/{surah}/{verse}/": {"get": {"operationId": "tafsir_book_read", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/TafsirVerses"}}}, "tags": ["tafsir"]}, "parameters": [{"name": "book", "in": "path", "required": true, "type": "string"}, {"name": "surah", "in": "path", "required": true, "type": "string"}, {"name": "verse", "in": "path", "required": true, "type": "string"}]}, "/tafsir/books/": {"get": {"operationId": "tafsir_books_list", "description": "", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/TafsirBook"}}}}, "tags": ["tafsir"]}, "parameters": []}, "/upload-tmp-media/": {"post": {"operationId": "upload-tmp-media_create", "description": "upload file...", "parameters": [{"name": "file", "in": "formData", "required": true, "type": "file"}], "responses": {"200": {"description": "", "schema": {"type": "object", "properties": {"success": {"type": "boolean", "default": true}, "path": {"description": "url path of file", "type": "string"}, "apath": {"description": "absolute path of file", "type": "string"}, "name": {"type": "string"}, "size": {"type": "string"}}}}, "400": {"description": "", "schema": {"type": "object", "properties": {"success": {"type": "boolean", "default": false}, "reason": {"type": "string"}}}}}, "consumes": ["multipart/form-data"], "tags": ["upload-tmp-media"]}, "parameters": []}, "/v1/languages/": {"get": {"operationId": "v1_languages_list", "description": "language list api", "parameters": [], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Language"}}}}, "tags": ["v1"]}, "parameters": []}, "/wallet/info/": {"get": {"operationId": "wallet_info_list", "description": "Retrieve wallet details for the authenticated user, including balance in coins and USD", "parameters": [], "responses": {"200": {"description": "Wallet details", "examples": {"application/json": {"id": 1, "currency": "USD", "balance_coin_count": 100, "balance_amount": 10.0, "coin_amount": {"coin": 10, "amount": 1.0}}}}, "400": {"description": "User does not have any active publishers."}, "404": {"description": "Wallet not found."}}, "tags": ["wallet"]}, "parameters": []}, "/wallet/transactions/": {"get": {"operationId": "wallet_transactions_list", "description": "List all income transactions", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Transaction"}}}}, "tags": ["wallet"]}, "parameters": []}, "/wallet/wallet/withdrawal-requests/create/": {"post": {"operationId": "wallet_wallet_withdrawal-requests_create_create", "description": "Creates a withdrawal request for the authenticated user.", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": ["coin_count"], "type": "object", "properties": {"coin_count": {"description": "Number of coins to withdraw", "type": "integer"}}}}], "responses": {"201": {"description": "Withdrawal request created successfully", "examples": {"application/json": {"detail": "Withdrawal request created successfully.", "request_id": 1, "status": "pending", "amount": 5.0, "coin_count": 50, "currency": "USD"}}}, "400": {"description": "Bad request due to validation error or insufficient balance", "examples": {"application/json": {"detail": "Insufficient balance to create debit request."}}}, "404": {"description": "Wallet not found", "examples": {"application/json": {"detail": "User does not have a wallet."}}}}, "tags": ["wallet"]}, "parameters": []}, "/wallet/withdrawal-requests/": {"get": {"operationId": "wallet_withdrawal-requests_list", "description": "List all withdrawal requests for the authenticated user", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/WithdrawalRequest"}}}}, "tags": ["wallet"]}, "parameters": []}, "/web/donate/v2/": {"get": {"operationId": "web_donate_v2_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": ""}}, "tags": ["web"]}, "parameters": []}, "/web/donate/v2/create/": {"post": {"operationId": "web_donate_v2_create_create", "description": "\n**Donation Creation API**\n\nCreate a donation record and receive a payment link. This API is designed to never fail and always returns a working donation link without any errors.\n\n**Key Features:**\n- Error-free operation - never returns HTTP errors\n- All fields are completely optional with intelligent defaults\n- Automatic payment method selection based on user location\n- Support for multiple payment gateways\n- Backward compatibility with existing integrations\n\n**Smart Defaults:**\n- **donate_type**: Defaults to 'once' if not provided or invalid\n- **price**: Defaults to '10.00' if not provided or invalid\n- **id**: Auto-selected based on user location (CloudTips for Russian users, Stripe for others)\n- **phone_number**: Optional field, stored if provided, otherwise null\n\n**Payment Methods:**\n- **Stripe**: International payment gateway with predefined donation links\n- **CloudTips**: Russian payment gateway for Russian users\n\n**Localization Logic:**\n- Russian users (language_code=ru OR user.country=RU) default to CloudTips\n- All other users default to Stripe payment gateway\n- Fallback to default donation links for custom amounts\n\n**Business Logic:**\n- Creates donation record in database (optional, doesn't affect response)\n- Optionally stores donor's phone number for contact purposes\n- Maps donation amounts to predefined Stripe payment links\n- Uses fallback links for unmapped amounts\n- Always returns HTTP 200 with working payment link\n\n**Authentication**: Not required - Public API\n**Permissions**: None - Accessible to all users\n", "parameters": [{"name": "data", "in": "body", "required": true, "schema": {"required": [], "type": "object", "properties": {"donate_type": {"description": "Type of donation - either 'monthly' for recurring donations or 'once' for one-time donations. This field is completely optional and will default to 'once' if not provided or if an invalid value is sent.", "type": "string", "enum": ["monthly", "once"]}, "price": {"description": "Donation amount as a string (e.g., '5.00', '10.00', '20.00'). This field is completely optional and will default to '10.00' if not provided or if an invalid value is sent.", "type": "string"}, "id": {"description": "Payment gateway identifier. This field is completely optional. If not provided, the system will automatically choose 'stripe' for non-Russian users and 'cloudtips' for Russian users (detected by language_code=ru or user country=RU). If an invalid value is provided, it defaults to 'stripe'.", "type": "string", "enum": ["stripe", "cloudtips"]}, "phone_number": {"description": "Optional phone number for the donor. This field is completely optional and can be omitted. If provided, it will be stored with the donation record.", "type": "string"}}, "example": {"donate_type": "once", "price": "15.00", "id": "stripe", "phone_number": "+1234567890"}}}], "responses": {"200": {"description": "Donation link created successfully. This API is guaranteed to always return HTTP 200 status with a working donation link, regardless of the input provided. Even if no data is sent in the request body, the API will respond with appropriate defaults.", "examples": {"application/json": {"complete_request": {"summary": "Complete Request with Phone Number", "description": "Response when all fields including phone_number are provided", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/bIYdSDgiK7Pwh0ccMN"}}, "request_with_phone": {"summary": "Request Example with Phone", "description": "Example showing phone_number parameter usage", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/9AQ01N5E68TAbFS002"}}, "empty_request_default": {"summary": "Empty Request (Default)", "description": "Response when no fields are provided - uses intelligent defaults", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV"}}, "empty_request_russian_user": {"summary": "Empty Request (Russian User)", "description": "Response for Russian users when no fields are provided", "value": {"donate_user": 1, "donate_link": "https://pay.cloudtips.ru/p/d5881ddf"}}, "cloudtips_payment": {"summary": "CloudTips Payment", "description": "Response when CloudTips payment method is selected", "value": {"donate_user": 1, "donate_link": "https://pay.cloudtips.ru/p/d5881ddf"}}, "invalid_data_fallback": {"summary": "Invalid Data Fallback", "description": "Response when invalid data is provided - normalized to defaults", "value": {"donate_user": 1, "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV"}}}}}}, "tags": ["Donate"]}, "parameters": []}, "/web/duas/robots.txt": {"get": {"operationId": "web_duas_robots.txt_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["web"]}, "parameters": []}, "/web/duas/{slug}/complete/": {"get": {"operationId": "web_duas_complete_read", "description": "دریافت کامل یک دعا با تمام بخش‌ها (بدون pagination) برای استفاده آفلاین", "parameters": [{"name": "slug", "in": "path", "description": "Slug دعا", "required": true, "type": "string"}], "responses": {"200": {"description": "", "schema": {"$ref": "#/definitions/DuaCompleteSerializer"}}, "404": {"description": "دعا یافت نشد"}}, "tags": ["web"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/web/mafatih-categories/": {"get": {"operationId": "web_mafatih-categories_list", "description": "", "parameters": [{"name": "language_code", "in": "query", "type": "string"}], "responses": {"200": {"description": "", "schema": {"type": "array", "items": {"$ref": "#/definitions/Web_DuaCategoriesSerializer"}}}}, "tags": ["web"]}, "parameters": []}, "/web/mafatih-duas/": {"get": {"operationId": "web_mafatih-duas_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}, {"name": "category", "in": "query", "description": "ID دسته‌بندی برای فیلتر دعاها", "type": "integer"}, {"name": "search", "in": "query", "description": "جستجو بر اساس عنوان دعاها", "type": "string"}, {"name": "today", "in": "query", "description": "", "type": "string"}, {"name": "famous", "in": "query", "description": "", "type": "string"}, {"name": "lat", "in": "query", "description": "Latitude of the location lat = {Mashhad : 36.2605, Karbala : 32.6160326} ", "type": "number"}, {"name": "lon", "in": "query", "description": "Longitude of the location lon = {Mashhad : 59.6168, Karbala : 44.0244229} ", "type": "number"}, {"name": "not_synced", "in": "query", "description": "", "type": "boolean"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Web_DuaSerializer"}}}}}}, "tags": ["web"]}, "parameters": []}, "/web/mafatih-duas/dhikrs/": {"get": {"operationId": "web_mafatih-duas_dhikrs_list", "description": "", "parameters": [], "responses": {"200": {"description": ""}}, "tags": ["web"]}, "parameters": []}, "/web/mafatih-duas/{id}/parts/": {"get": {"operationId": "web_mafatih-duas_parts_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Web_DuaPartSerializer"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/web/mafatih-duas/{slug}/parts/": {"get": {"operationId": "web_mafatih-duas_parts_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/Web_DuaPartSerializer"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/web/mafatih/{id}/audios/": {"get": {"operationId": "web_mafatih_audios_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/WebDuaAudio"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/web/mafatih/{id}/reciters/": {"get": {"operationId": "web_mafatih_reciters_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DuaReciter"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "id", "in": "path", "required": true, "type": "string"}]}, "/web/mafatih/{slug}/audios/": {"get": {"operationId": "web_mafatih_audios_list", "description": "", "parameters": [{"name": "page", "in": "query", "description": "A page number within the paginated result set.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/WebDuaAudio"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/web/mafatih/{slug}/reciters/": {"get": {"operationId": "web_mafatih_reciters_list", "description": "", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/DuaReciter"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "slug", "in": "path", "required": true, "type": "string"}]}, "/web/quran-qaris/": {"get": {"operationId": "web_quran-qaris_list", "description": "", "parameters": [{"name": "type", "in": "query", "type": "string", "enum": ["reciter", "translation"]}], "responses": {"200": {"description": ""}}, "tags": ["web"]}, "parameters": []}, "/web/quran-surah/{surah_id}/": {"get": {"operationId": "web_quran-surah_read", "description": "API view that returns all verses from a specific Surah with translations\nbased on the language_code query parameter", "parameters": [{"name": "limit", "in": "query", "description": "Number of results to return per page.", "required": false, "type": "integer"}, {"name": "offset", "in": "query", "description": "The initial index from which to return the results.", "required": false, "type": "integer"}, {"name": "language_code", "in": "query", "type": "string", "default": "en"}], "responses": {"200": {"description": "", "schema": {"required": ["count", "results"], "type": "object", "properties": {"count": {"type": "integer"}, "next": {"type": "string", "format": "uri", "x-nullable": true}, "previous": {"type": "string", "format": "uri", "x-nullable": true}, "results": {"type": "array", "items": {"$ref": "#/definitions/QuranSurahDetailVerse"}}}}}}, "tags": ["web"]}, "parameters": [{"name": "surah_id", "in": "path", "required": true, "type": "string"}]}}, "definitions": {"Supporter": {"required": ["title"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "url": {"title": "Url", "description": "https://example.com", "type": "string", "maxLength": 255, "x-nullable": true}, "logo": {"title": "Logo", "type": "string", "readOnly": true}}}, "AboutService": {"required": ["description", "language", "service", "supporters"], "type": "object", "properties": {"description": {"title": "Description", "type": "string", "minLength": 1}, "language": {"title": "Language", "type": "string", "minLength": 1}, "service": {"title": "Service", "type": "string", "enum": ["main", "hussainiyah", "quran", "mafatih", "qiblah", "ahkam", "calendar", "talk", "meet", "library", "hadis", "account"]}, "supporters": {"type": "array", "items": {"$ref": "#/definitions/Supporter"}}}}, "Activity": {"required": ["usage_duration"], "type": "object", "properties": {"service": {"title": "Service", "type": "string", "maxLength": 100, "x-nullable": true}, "usage_duration": {"title": "Usage duration", "type": "string"}, "entered_at": {"title": "Entered at", "type": "string", "format": "date-time"}, "additional_info": {"title": "Additional info", "type": "object"}}}, "AppleAuth": {"required": ["id_token", "server_auth_token", "mobile_device_id"], "type": "object", "properties": {"id_token": {"title": "Id token", "type": "string", "maxLength": 9000, "minLength": 1}, "server_auth_token": {"title": "Server auth token", "type": "string", "maxLength": 9000, "minLength": 1}, "mobile_device_id": {"title": "Mobile device id", "type": "string", "maxLength": 255, "minLength": 1}, "name": {"title": "Name", "type": "string", "maxLength": 255, "x-nullable": true}, "avatar": {"title": "~ Avatar", "type": "string", "x-nullable": true}, "fcm": {"title": "Fcm", "type": "string", "x-nullable": true}, "publisher_in": {"title": "Publisher in", "type": "string", "readOnly": true}, "token": {"title": "Token", "type": "string", "readOnly": true, "minLength": 1}}}, "GoogleAuth": {"required": ["email", "name", "mobile_device_id", "server_auth_token", "id_token"], "type": "object", "properties": {"email": {"title": "Email", "type": "string", "x-nullable": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "x-nullable": true}, "mobile_device_id": {"title": "Mobile device id", "type": "string", "maxLength": 500, "x-nullable": true}, "avatar": {"title": "~ Avatar", "type": "string", "x-nullable": true}, "server_auth_token": {"title": "Server auth token", "type": "string", "maxLength": 9000, "minLength": 1}, "id_token": {"title": "Id token", "type": "string", "maxLength": 9000, "minLength": 1}, "fcm": {"title": "Fcm", "type": "string", "x-nullable": true}, "publisher_in": {"title": "Publisher in", "type": "string", "readOnly": true}}}, "GuestUser": {"required": ["mobile_device_id"], "type": "object", "properties": {"lat": {"title": "Lat", "type": "string", "maxLength": 255, "x-nullable": true}, "lon": {"title": "Lon", "type": "string", "maxLength": 255, "x-nullable": true}, "mobile_device_id": {"title": "Mobile device id", "type": "string", "x-nullable": true}, "language": {"title": "Language", "type": "string", "x-nullable": true}, "cpu_type": {"title": "Cpu type", "type": "string", "maxLength": 64, "x-nullable": true}, "model_name": {"title": "Model name", "type": "string", "maxLength": 120, "x-nullable": true}, "os_platform": {"title": "Os platform", "type": "string", "maxLength": 120, "x-nullable": true}, "screen_size": {"title": "Screen size", "type": "string", "maxLength": 120, "x-nullable": true}, "device_brand": {"title": "Device brand", "type": "string", "maxLength": 120, "x-nullable": true}, "timezone": {"title": "Timezone", "type": "string", "x-nullable": true}, "api_version": {"title": "Api version", "type": "string", "x-nullable": true}, "fcm": {"title": "Firebase token", "type": "string", "maxLength": 255, "x-nullable": true}, "location_method": {"title": "Location method", "type": "string", "x-nullable": true}}}, "PhoneAuth": {"required": ["phone_number", "mobile_device_id"], "type": "object", "properties": {"phone_number": {"title": "Phone number", "type": "string", "maxLength": 254, "x-nullable": true}, "lat": {"title": "Lat", "type": "string", "maxLength": 255, "x-nullable": true}, "lon": {"title": "Lon", "type": "string", "maxLength": 255, "x-nullable": true}, "mobile_device_id": {"title": "Mobile device id", "type": "string", "maxLength": 500, "x-nullable": true}, "cpu_type": {"title": "Cpu type", "type": "string", "maxLength": 64, "x-nullable": true}, "model_name": {"title": "Model name", "type": "string", "maxLength": 120, "x-nullable": true}, "os_platform": {"title": "Os platform", "type": "string", "maxLength": 120, "x-nullable": true}, "screen_size": {"title": "Screen size", "type": "string", "maxLength": 120, "x-nullable": true}, "device_brand": {"title": "Device brand", "type": "string", "maxLength": 120, "x-nullable": true}, "timezone": {"title": "Timezone", "type": "string", "x-nullable": true}, "api_version": {"title": "Api version", "type": "string", "x-nullable": true}, "fcm": {"title": "Fcm", "type": "string", "x-nullable": true}, "location_method": {"title": "Location method", "type": "string", "x-nullable": true}}}, "MergeAccount": {"required": ["method", "value"], "type": "object", "properties": {"method": {"title": "Method", "type": "string", "enum": ["phone", "email"]}, "value": {"title": "Value", "type": "string", "minLength": 1}}}, "MergeVerify": {"required": ["phone_number", "code"], "type": "object", "properties": {"phone_number": {"title": "Phone number", "type": "string", "minLength": 1}, "code": {"title": "Code", "type": "string", "minLength": 1}}}, "UserProfile": {"type": "object", "properties": {"name": {"title": "Name", "type": "string", "minLength": 1}, "avatar": {"title": "Avatar", "type": "string", "x-nullable": true}, "email": {"title": "Email", "type": "string", "format": "email", "readOnly": true, "minLength": 1}, "phone_number": {"title": "Phone number", "type": "string", "readOnly": true, "minLength": 1}}}, "PhoneVerify": {"required": ["phone_number", "user_id", "code"], "type": "object", "properties": {"phone_number": {"title": "Phone number", "type": "string", "maxLength": 254, "x-nullable": true}, "user_id": {"title": "User id", "type": "string", "maxLength": 10, "minLength": 1}, "code": {"title": "Code", "type": "string", "maxLength": 5, "minLength": 1}}}, "IPGeolocation": {"type": "object", "properties": {"ip": {"title": "Ip", "type": "string", "readOnly": true, "minLength": 1}, "country": {"title": "Country", "type": "string", "readOnly": true, "maxLength": 100, "x-nullable": true}, "country_code": {"title": "Country code", "type": "string", "readOnly": true, "maxLength": 10, "x-nullable": true}, "city": {"title": "City", "type": "string", "readOnly": true, "maxLength": 100, "x-nullable": true}, "latitude": {"title": "Latitude", "type": "number", "readOnly": true, "x-nullable": true}, "longitude": {"title": "Longitude", "type": "number", "readOnly": true, "x-nullable": true}, "accuracy_radius": {"title": "Accuracy radius", "type": "integer", "readOnly": true, "x-nullable": true}, "time_zone": {"title": "Time zone", "type": "string", "readOnly": true, "maxLength": 100, "x-nullable": true}, "postal_code": {"title": "Postal code", "type": "string", "readOnly": true, "maxLength": 20, "x-nullable": true}}}, "ReverseGeolocationResponse": {"type": "object", "properties": {"latitude": {"title": "Latitude", "type": "number", "readOnly": true}, "longitude": {"title": "Longitude", "type": "number", "readOnly": true}, "city": {"title": "City", "type": "string", "readOnly": true, "maxLength": 100, "minLength": 1, "x-nullable": true}, "country": {"title": "Country", "type": "string", "readOnly": true, "maxLength": 100, "minLength": 1, "x-nullable": true}, "country_code": {"title": "Country code", "type": "string", "readOnly": true, "maxLength": 10, "minLength": 1, "x-nullable": true}, "accuracy_radius": {"title": "Accuracy radius", "type": "integer", "readOnly": true, "x-nullable": true}, "time_zone": {"title": "Time zone", "type": "string", "readOnly": true, "maxLength": 100, "x-nullable": true}, "postal_code": {"title": "Postal code", "type": "string", "readOnly": true, "maxLength": 20, "x-nullable": true}}}, "LocationHistory": {"required": ["lat", "lon"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "lat": {"title": "Lat", "type": "number"}, "lon": {"title": "Lon", "type": "number"}, "country": {"title": "Country", "type": "string", "maxLength": 255, "x-nullable": true}, "city": {"title": "City", "type": "string", "maxLength": 255, "x-nullable": true}, "selected_manually": {"title": "Selected manually", "type": "boolean", "x-nullable": true}, "ip": {"title": "Ip", "type": "string", "maxLength": 255, "minLength": 1, "x-nullable": true}, "timezone": {"title": "Timezone", "type": "string", "maxLength": 60, "x-nullable": true}}}, "UserNotification": {"required": ["service", "title", "message"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "service": {"title": "Service", "type": "string", "minLength": 1}, "title": {"title": "Title", "type": "string", "minLength": 1}, "message": {"title": "Message", "type": "string", "minLength": 1}, "data": {"title": "Data", "type": "string", "readOnly": true}, "image": {"title": "Image", "type": "string", "readOnly": true}, "is_read": {"title": "Is Read", "type": "boolean"}, "created_at": {"title": "Created At", "type": "string", "format": "date-time", "readOnly": true}, "notif_data": {"title": "Notif data", "type": "string", "readOnly": true}}}, "Provider": {"required": ["public_name", "description", "service", "birthdate", "phone_number", "wa_number"], "type": "object", "properties": {"public_name": {"title": "Public name", "type": "string", "maxLength": 255, "minLength": 1}, "description": {"title": "Description", "type": "string", "minLength": 1}, "service": {"title": "Service", "type": "string", "enum": ["hussainiya", "net", "library", "talk", "shop", "travel", "meet", "habibnet"]}, "birthdate": {"title": "Birthdate", "type": "string", "format": "date"}, "phone_number": {"title": "Phone number", "type": "string", "minLength": 1}, "wa_number": {"title": "Wa number", "type": "string", "minLength": 1}, "social_medias": {"title": "Social medias", "description": "[{\"type\": \"instagram\", \"link\": \"https://www.instagram.com\"}]", "type": "object", "default": []}, "status": {"title": "Status", "type": "string", "enum": ["pending", "rejected", "accepted"], "readOnly": true}}}, "UserSettings": {"type": "object", "properties": {"settings": {"title": "Settings", "type": "string", "x-nullable": true}, "is_reminder": {"title": "Reminder Active", "type": "boolean"}, "notification_settings": {"description": "List of notification services: hussainiyah, meet, talk, library", "type": "array", "items": {"type": "string", "minLength": 1}, "default": ["hussainiyah", "meet", "talk", "library"]}}}, "ReviewList": {"required": ["platform", "review_id", "last_modified_ts", "app_identifier"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "platform": {"title": "Platform", "type": "string", "enum": ["google_play", "app_store", "whatsapp", "telegram", "habib_talk"]}, "review_id": {"title": "Review id", "type": "string", "maxLength": 255, "minLength": 1}, "author_name": {"title": "Author name", "type": "string", "maxLength": 255, "x-nullable": true}, "text": {"title": "Text", "type": "string"}, "review_status": {"title": "Review status", "type": "string", "enum": ["pending", "responded", "escalated", "resolved"]}, "needs_human_intervention": {"title": "Needs human intervention", "type": "boolean"}, "last_modified_ts": {"title": "Last modified ts", "type": "integer", "maximum": 9223372036854775807, "minimum": -9223372036854775808}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "user_identifier": {"title": "User identifier", "description": "Phone number for WhatsApp, Chat ID for Telegram, etc.", "type": "string", "maxLength": 255}, "app_identifier": {"title": "App identifier", "description": "Package name, bundle ID یا شناسه کانال/گروه بسته به پلتفرم", "type": "string", "maxLength": 255, "minLength": 1}, "rating": {"title": "Rating", "type": "integer", "maximum": 32767, "minimum": 0, "x-nullable": true}}}, "ReviewDetail": {"required": ["platform", "app_identifier", "review_id", "last_modified_ts"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "platform": {"title": "Platform", "type": "string", "enum": ["google_play", "app_store", "whatsapp", "telegram", "habib_talk"]}, "app_identifier": {"title": "App identifier", "description": "Package name, bundle ID یا شناسه کانال/گروه بسته به پلتفرم", "type": "string", "maxLength": 255, "minLength": 1}, "user_identifier": {"title": "User identifier", "description": "Phone number for WhatsApp, Chat ID for Telegram, etc.", "type": "string", "maxLength": 255}, "review_id": {"title": "Review id", "type": "string", "maxLength": 255, "minLength": 1}, "author_name": {"title": "Author name", "type": "string", "maxLength": 255, "x-nullable": true}, "rating": {"title": "Rating", "type": "integer", "maximum": 32767, "minimum": 0, "x-nullable": true}, "title": {"title": "Title", "type": "string", "maxLength": 255}, "text": {"title": "Text", "type": "string"}, "device": {"title": "Device", "type": "string", "maxLength": 255}, "reviewer_language": {"title": "Reviewer language", "type": "string", "maxLength": 10}, "android_os_version": {"title": "Android os version", "type": "integer", "maximum": 32767, "minimum": 0, "x-nullable": true}, "app_version_code": {"title": "App version code", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "app_version_name": {"title": "App version name", "type": "string", "maxLength": 50}, "device_product_name": {"title": "Device product name", "type": "string", "maxLength": 255}, "device_manufacturer": {"title": "Device manufacturer", "type": "string", "maxLength": 100}, "device_class": {"title": "Device class", "type": "string", "maxLength": 50}, "screen_width_px": {"title": "Screen width px", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "screen_height_px": {"title": "Screen height px", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "screen_density_dpi": {"title": "Screen density dpi", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "ram_mb": {"title": "Ram mb", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "last_modified_ts": {"title": "Last modified ts", "type": "integer", "maximum": 9223372036854775807, "minimum": -9223372036854775808}, "raw_data": {"title": "Raw data", "type": "object", "x-nullable": true}, "sent_to_telegram": {"title": "Sent to telegram", "type": "boolean"}, "category": {"title": "Category", "type": "string", "enum": ["appreciation", "inspiring", "feature_request", "bug_report", "account_issue", "financial_issue", "content_complaint", "critical", "general_question", "spam", "other"]}, "review_status": {"title": "Review status", "type": "string", "enum": ["pending", "responded", "escalated", "resolved"]}, "needs_human_intervention": {"title": "Needs human intervention", "type": "boolean"}, "prevent_auto_reply": {"title": "غیرفعال‌سازی پاسخ خودکار (بلاک مکالمه اتوماتیک)", "type": "boolean"}, "conversation_history": {"title": "Conversation history", "description": "List of message dicts for this user's entire conversation", "type": "object"}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}}}, "talk_provider_profile": {"required": ["languages", "avatar"], "type": "object", "properties": {"full_name": {"title": "Full name", "type": "string", "maxLength": 254, "minLength": 1, "x-nullable": true}, "bio": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}, "birthdate": {"title": "Birthdate", "type": "string", "format": "date", "x-nullable": true}, "email": {"title": "Email", "type": "string", "format": "email", "maxLength": 254, "x-nullable": true}, "wa_number": {"title": "Whatsapp number", "type": "string", "maxLength": 255, "x-nullable": true}, "institution_name": {"title": "Name", "description": "Name of the institute", "type": "string", "maxLength": 255, "x-nullable": true}, "languages": {"type": "array", "items": {"type": "string"}}, "avatar": {"title": "Avatar", "type": "string", "minLength": 1}, "social_medias": {"title": "Social medias", "description": "Provider social media profiles", "type": "object"}}}, "BookmarkSerializers": {"required": ["service", "content_id"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "related_object": {"title": "Related object", "type": "string", "readOnly": true}, "service": {"title": "Service", "type": "string", "maxLength": 255, "minLength": 1}, "content_id": {"title": "Content id", "type": "string", "maxLength": 255, "minLength": 1}, "text": {"title": "Text", "type": "string", "x-nullable": true}, "status": {"title": "Status", "type": "boolean", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}, "user": {"title": "User", "type": "integer", "readOnly": true}}}, "Calendar": {"required": ["type"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "countries": {"title": "Countries", "type": "string", "readOnly": true}, "type": {"title": "Type", "type": "string", "minLength": 1}, "event_type": {"title": "Event type", "type": "string", "enum": ["national", "international", "religious"], "x-nullable": true}, "holiday_in_countries": {"title": "Holiday in countries", "type": "string", "readOnly": true}, "dates": {"title": "Dates", "type": "string", "readOnly": true}, "is_yearly": {"title": "Is yearly", "description": "check this field if event is annually", "type": "boolean"}, "has_occasion_detail": {"title": "Has occasion detail", "type": "string", "readOnly": true}}}, "Language": {"required": ["name", "code"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "maxLength": 64, "minLength": 1}, "code": {"title": "Code", "type": "string", "maxLength": 2, "minLength": 1}}}, "MasaelCategories": {"required": ["language"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "masael_index": {"title": "Masael index", "type": "string", "readOnly": true}, "language": {"$ref": "#/definitions/Language"}, "children": {"title": "Children", "type": "string", "readOnly": true}}}, "CheckupParameterDetailSerializerV2": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "readOnly": true}, "hadith": {"title": "Hadith", "type": "string", "readOnly": true}}}, "CommandHelp": {"required": ["service"], "type": "object", "properties": {"service": {"title": "Service", "type": "string", "enum": ["hussainiyah", "library", "Talk", "meet", "mafatih", "hadith", "quran", "ahkam", "coin", "calendar", "qiblah", "elalHabib", "main"]}, "description": {"title": "Description", "type": "string", "readOnly": true}}}, "CommandSuggestion": {"required": ["language_code"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "x-nullable": true}, "language_code": {"title": "Language code", "description": "Language code (e.g., en, fa)", "type": "string", "maxLength": 10, "minLength": 1}}}, "DonateUser": {"required": ["amount"], "type": "object", "properties": {"amount": {"title": "Amount", "type": "string", "format": "decimal"}, "phone": {"title": "Phone", "type": "string", "maxLength": 255, "x-nullable": true}, "pay_method": {"title": "Pay method", "type": "string", "enum": ["paypal", "vtb", "stripe"], "default": "stripe"}}}, "DontKillApp": {"required": ["brand", "sdk_version", "description"], "type": "object", "properties": {"brand": {"type": "array", "items": {"title": "Brand", "type": "string", "maxLength": 100, "minLength": 1}}, "sdk_version": {"type": "array", "items": {"title": "Sdk version", "type": "integer", "maximum": 35, "minimum": 0}}, "description": {"title": "Description", "type": "string", "minLength": 1}}}, "EightmagCategories": {"required": ["name"], "type": "object", "properties": {"url": {"title": "Url", "type": "string", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 512, "minLength": 1}, "thumbnails": {"title": "Thumbnails", "type": "string", "readOnly": true}, "children": {"title": "Children", "type": "string", "readOnly": true}}}, "EightmagCategoriesInList": {"required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "maxLength": 512, "minLength": 1}, "url": {"title": "Url", "type": "string", "readOnly": true}}}, "EightmagList": {"required": ["title"], "type": "object", "properties": {"url": {"title": "Url", "type": "string", "readOnly": true}, "categories": {"type": "array", "items": {"$ref": "#/definitions/EightmagCategoriesInList"}, "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "event": {"$ref": "#/definitions/Calendar"}, "created_at": {"title": "Created at", "type": "string", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "summary": {"title": "Summary", "description": "we use it for seo and short description of post", "type": "string", "x-nullable": true}, "as_special": {"title": "As special", "description": "enable as special blog for showing in home page", "type": "boolean"}, "pin_top": {"title": "Pin top", "description": "چسباندن پست به بالا", "type": "boolean"}, "status": {"title": "Status", "description": "model status to be shown or not", "type": "boolean"}, "author": {"title": "Author", "type": "string", "maxLength": 119, "minLength": 1, "x-nullable": true}, "like_count": {"title": "Like count", "type": "integer", "maximum": 2147483647, "minimum": 0}, "source": {"title": "Source", "type": "integer", "x-nullable": true}, "publisher": {"title": "Publisher", "type": "integer", "x-nullable": true}}}, "EightmagDetails": {"required": ["title", "content"], "type": "object", "properties": {"url": {"title": "Url", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "categories": {"type": "array", "items": {"$ref": "#/definitions/EightmagCategoriesInList"}, "readOnly": true}, "author": {"title": "Author", "type": "string", "readOnly": true}, "event": {"$ref": "#/definitions/Calendar"}, "title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "content": {"title": "Content", "type": "string", "minLength": 1}, "summary": {"title": "Summary", "description": "we use it for seo and short description of post", "type": "string", "x-nullable": true}, "as_special": {"title": "As special", "description": "enable as special blog for showing in home page", "type": "boolean"}, "pin_top": {"title": "Pin top", "description": "چسباندن پست به بالا", "type": "boolean"}, "status": {"title": "Status", "description": "model status to be shown or not", "type": "boolean"}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "like_count": {"title": "Like count", "type": "integer", "maximum": 2147483647, "minimum": 0}, "source": {"title": "Source", "type": "integer", "x-nullable": true}, "publisher": {"title": "Publisher", "type": "integer", "x-nullable": true}}}, "ElalHabib": {"type": "object", "properties": {"title": {"title": "نام موکب", "type": "object"}, "nationalities": {"type": "array", "items": {"type": "string", "x-nullable": true}, "default": [], "x-nullable": true}, "capacity": {"title": "ظرفیت اسکان", "type": "integer", "maximum": 32767, "minimum": 0, "x-nullable": true}, "options": {"title": "Options", "type": "string", "readOnly": true}, "after_amood": {"title": "After amood", "type": "string", "readOnly": true}, "events": {"title": "Events", "type": "string", "readOnly": true}, "description": {"title": "توضیحات", "type": "string", "x-nullable": true}}}, "ElalHabibSingerInList": {"required": ["slug"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 255, "minLength": 1}}}, "DiscountCodeUsage": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "discount_code": {"title": "Discount code", "type": "string", "readOnly": true, "minLength": 1}, "user_username": {"title": "User username", "type": "string", "readOnly": true, "minLength": 1}, "service_name": {"title": "Service name", "type": "string", "readOnly": true, "minLength": 1}, "object_id": {"title": "Object ID", "type": "integer", "readOnly": true}, "original_price": {"title": "Original Price", "type": "string", "format": "decimal", "readOnly": true}, "discounted_price": {"title": "Discounted Price", "type": "string", "format": "decimal", "readOnly": true}, "discount_amount": {"title": "Discount Amount", "type": "string", "format": "decimal", "readOnly": true}, "used_at": {"title": "Used At", "type": "string", "format": "date-time", "readOnly": true}}}, "Package": {"required": ["coin_count", "price"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "package_type": {"title": "Package type", "type": "string", "enum": ["normal", "timely", "evently"]}, "coin_count": {"title": "Coin count", "type": "integer", "maximum": 32767, "minimum": 0}, "purchase_id": {"title": "Purchase ID", "description": "Unique identifier for products purchased on Google Play and App Store, used for tracking transactions.", "type": "string", "maxLength": 55, "x-nullable": true}, "price": {"title": "Price", "type": "string", "format": "decimal"}, "off_price": {"title": "Off price", "description": "Optional", "type": "string", "format": "decimal", "x-nullable": true}, "discount_percentage": {"title": "Discount percentage", "type": "string", "readOnly": true}, "expiration_duration_days": {"title": "Expiration duration days", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "event_name": {"title": "Event name", "type": "string", "maxLength": 100, "x-nullable": true}}}, "Support": {"required": ["type", "description", "whatsapp_number"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "user": {"title": "User", "type": "integer", "readOnly": true}, "type": {"title": "Type", "type": "string", "enum": ["technical", "billing", "general"]}, "description": {"title": "Description", "type": "string", "minLength": 1}, "whatsapp_number": {"title": "Whatsapp number", "type": "string", "maxLength": 15, "minLength": 1}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}, "service": {"title": "Service", "type": "string", "minLength": 1}}}, "Transactions": {"required": ["payment_method", "price", "coin_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "status": {"title": "Status", "type": "string", "enum": ["pending", "success", "failed"]}, "payment_method": {"title": "Payment method", "type": "string", "maxLength": 20, "minLength": 1}, "price": {"title": "Price", "type": "integer"}, "coin_count": {"title": "Coin count", "type": "integer"}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}, "package": {"$ref": "#/definitions/Package"}}}, "UserCoinUsage": {"required": ["package", "coin_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "package": {"$ref": "#/definitions/Package"}, "service_details": {"title": "Service details", "type": "object", "readOnly": true}, "at_time": {"title": "At time", "type": "string", "format": "date-time", "readOnly": true}, "coin_count": {"title": "Coin count", "type": "integer", "maximum": 32767, "minimum": 0}}}, "UserPackage": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "coin_count": {"title": "Coin count", "type": "integer", "readOnly": true}, "price": {"title": "Price", "type": "integer", "readOnly": true}, "used_count": {"title": "Used count", "type": "integer", "readOnly": true}, "remaining_count": {"title": "Remaining count", "type": "integer", "readOnly": true}, "package": {"$ref": "#/definitions/Package"}}}, "MeetSerializer": {"required": ["name", "online_users_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "description": "Name of the meet", "type": "string", "maxLength": 255, "minLength": 1}, "description": {"title": "Description", "description": "Description of the meet", "type": "string", "x-nullable": true}, "next_session_subject": {"title": "Next Session Subject", "description": "Subject of the next session", "type": "string", "maxLength": 255, "x-nullable": true}, "next_session_schedule": {"title": "Next Session Schedule", "description": "Scheduled date and time for the next session", "type": "string", "format": "date-time", "x-nullable": true}, "is_suggested": {"title": "Is Suggested", "description": "Is this meet suggested?", "type": "boolean"}, "provider": {"title": "Provider", "type": "string", "readOnly": true}, "is_free": {"title": "Is Free", "description": "Is this meet free?", "type": "boolean"}, "price": {"title": "Price", "description": "Price of the meet if it is not free", "type": "string", "format": "decimal", "x-nullable": true}, "is_live": {"title": "Is Live", "description": "Is the meet currently live?", "type": "boolean"}, "is_closed": {"title": "Is closed", "type": "string", "readOnly": true}, "online_users_count": {"title": "Online users count", "type": "integer"}, "language": {"title": "Language", "type": "string", "readOnly": true}, "categories": {"title": "Categories", "description": "Categories related to the meet", "type": "string", "maxLength": 255, "x-nullable": true}, "organizer": {"title": "Organizer", "type": "string", "readOnly": true}, "is_provider": {"title": "Is provider", "type": "string", "readOnly": true}, "has_access": {"title": "Has access", "type": "string", "readOnly": true}, "is_reminder": {"title": "Is reminder", "type": "string", "readOnly": true}, "live_session_id": {"title": "Live session id", "type": "string", "readOnly": true}, "has_archive": {"title": "Has archive", "type": "string", "readOnly": true}, "has_recordings": {"title": "Has recordings", "type": "string", "readOnly": true}, "access": {"title": "Access", "description": "Access type of the meet (public or private)", "type": "string", "enum": ["public", "private"]}, "password": {"title": "Password", "description": "Password for private meets", "type": "string", "maxLength": 50, "x-nullable": true}}}, "MeetCreate": {"required": ["name", "language"], "type": "object", "properties": {"name": {"title": "Name", "description": "Name of the meet", "type": "string", "maxLength": 255, "minLength": 1}, "price": {"title": "Price", "type": "string", "format": "decimal", "default": "0.00", "x-nullable": true}, "language": {"title": "Language", "type": "string", "minLength": 1}, "description": {"title": "Description", "description": "Description of the meet", "type": "string", "x-nullable": true}, "is_free": {"title": "Is Free", "description": "Is this meet free?", "type": "boolean"}}}, "MeetCreateV2": {"required": ["name", "language"], "type": "object", "properties": {"name": {"title": "Name", "description": "Name of the meet", "type": "string", "maxLength": 255, "minLength": 1}, "price": {"title": "Price", "type": "string", "format": "decimal", "default": "0.00", "x-nullable": true}, "language": {"title": "Language", "type": "string", "minLength": 1}, "description": {"title": "Description", "description": "Description of the meet", "type": "string", "x-nullable": true}, "is_free": {"title": "Is Free", "description": "Is this meet free?", "type": "boolean"}, "access": {"title": "Access", "type": "string", "enum": ["public", "private"], "default": "public"}, "password": {"title": "Password", "type": "string", "maxLength": 50, "x-nullable": true}}}, "MeetProviderProfile": {"required": ["languages"], "type": "object", "properties": {"full_name": {"title": "Full name", "type": "string", "maxLength": 254, "minLength": 1, "x-nullable": true}, "bio": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}, "birthdate": {"title": "Birthdate", "type": "string", "format": "date", "x-nullable": true}, "email": {"title": "Email", "type": "string", "format": "email", "maxLength": 254, "x-nullable": true}, "wa_number": {"title": "Whatsapp number", "type": "string", "maxLength": 255, "x-nullable": true}, "institution_name": {"title": "Name", "description": "Name of the institute", "type": "string", "maxLength": 255, "x-nullable": true}, "languages": {"type": "array", "items": {"type": "string"}}, "avatar": {"title": "Avatar", "type": "string", "minLength": 1}, "social_medias": {"title": "Social medias", "description": "Provider social media profiles", "type": "object"}}}, "ProviderMeetSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "email": {"title": "Email", "type": "string", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "bio": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}, "slogn": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}}}, "ProviderDetailMeetSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "email": {"title": "Email", "type": "string", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "slogn": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}, "bio": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}, "other_provider_services": {"title": "Other provider services", "type": "string", "readOnly": true}}}, "MeetProviderRoom": {"required": ["name", "reminder_count", "purchase_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "description": "Name of the meet", "type": "string", "maxLength": 255, "minLength": 1}, "next_session_subject": {"title": "Next Session Subject", "description": "Subject of the next session", "type": "string", "maxLength": 255, "x-nullable": true}, "next_session_schedule": {"title": "Next Session Schedule", "description": "Scheduled date and time for the next session", "type": "string", "format": "date-time", "x-nullable": true}, "language": {"title": "Language", "type": "string", "readOnly": true}, "is_free": {"title": "Is Free", "description": "Is this meet free?", "type": "boolean"}, "price": {"title": "Price", "description": "Price of the meet if it is not free", "type": "string", "format": "decimal", "x-nullable": true}, "is_closed": {"title": "Is closed", "type": "string", "readOnly": true}, "description": {"title": "Description", "description": "Description of the meet", "type": "string", "x-nullable": true}, "provider": {"title": "Provider", "type": "string", "readOnly": true}, "reminder_count": {"title": "Reminder count", "type": "integer"}, "categories": {"title": "Categories", "description": "Categories related to the meet", "type": "string", "maxLength": 255, "x-nullable": true}, "purchase_count": {"title": "Purchase count", "type": "integer"}, "archive_count": {"title": "Archive count", "type": "string", "readOnly": true}, "is_active": {"title": "Is Active", "description": "Is this meet currently active?", "type": "boolean"}, "status": {"title": "Status", "type": "string", "readOnly": true}, "access": {"title": "Access", "type": "string", "enum": ["public", "private"], "readOnly": true}, "password": {"title": "Password", "type": "string", "readOnly": true, "maxLength": 50, "minLength": 1, "x-nullable": true}}}, "MeetDetailSerializer": {"required": ["name", "online_users_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "description": "Name of the meet", "type": "string", "maxLength": 255, "minLength": 1}, "description": {"title": "Description", "description": "Description of the meet", "type": "string", "x-nullable": true}, "next_session_subject": {"title": "Next Session Subject", "description": "Subject of the next session", "type": "string", "maxLength": 255, "x-nullable": true}, "next_session_schedule": {"title": "Next Session Schedule", "description": "Scheduled date and time for the next session", "type": "string", "format": "date-time", "x-nullable": true}, "is_suggested": {"title": "Is Suggested", "description": "Is this meet suggested?", "type": "boolean"}, "provider": {"title": "Provider", "type": "string", "readOnly": true}, "is_free": {"title": "Is Free", "description": "Is this meet free?", "type": "boolean"}, "price": {"title": "Price", "description": "Price of the meet if it is not free", "type": "string", "format": "decimal", "x-nullable": true}, "is_live": {"title": "Is Live", "description": "Is the meet currently live?", "type": "boolean"}, "is_closed": {"title": "Is closed", "type": "string", "readOnly": true}, "online_users_count": {"title": "Online users count", "type": "integer"}, "language": {"title": "Language", "type": "string", "readOnly": true}, "categories": {"title": "Categories", "description": "Categories related to the meet", "type": "string", "maxLength": 255, "x-nullable": true}, "organizer": {"title": "Organizer", "type": "string", "readOnly": true}, "is_provider": {"title": "Is provider", "type": "string", "readOnly": true}, "live_session_id": {"title": "Live session id", "type": "string", "readOnly": true}, "has_archive": {"title": "Has archive", "type": "string", "readOnly": true}, "recordings": {"title": "Recordings", "type": "string", "readOnly": true}, "access": {"title": "Access", "type": "string", "enum": ["public", "private"]}, "password": {"title": "Password", "type": "string", "maxLength": 50, "x-nullable": true}, "has_recording": {"title": "Has recording", "type": "string", "readOnly": true}}}, "SessionArchiveSerializer": {"required": ["recorded_file", "session_id"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "meet": {"title": "Meet", "description": "The meet this session belongs to", "type": "integer", "readOnly": true}, "started_at": {"title": "Started At", "description": "Session start time", "type": "string", "format": "date-time", "readOnly": true}, "ended_at": {"title": "Ended At", "description": "Session end time", "type": "string", "format": "date-time", "readOnly": true, "x-nullable": true}, "recorded_file": {"title": "Recorded file", "type": "string", "minLength": 1}, "subject": {"title": "Subject", "description": "Subject of the session", "type": "string", "readOnly": true, "minLength": 1, "x-nullable": true}, "session_id": {"title": "Session id", "type": "integer"}}}, "ReportSerializer": {"required": ["report_type"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "meet_id": {"title": "Meet id", "type": "integer", "readOnly": true}, "description": {"title": "Description", "description": "Description of the report", "type": "string", "x-nullable": true}, "report_type": {"title": "Type", "description": "Type of the report", "type": "string", "enum": ["bug", "feedback", "other"]}}}, "SessionCreate": {"required": ["name", "is_start"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "minLength": 1}, "date_time": {"title": "Date time", "description": "Enter the date and time in the format YYYY-MM-DD HH:MM:SS", "type": "string", "format": "date-time", "x-nullable": true}, "is_start": {"title": "Is start", "type": "boolean"}}}, "SessionRecordingCreateUpdateSerializer": {"required": ["session", "file", "recording_type"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "description": "Title of the recording", "type": "string", "maxLength": 255, "x-nullable": true}, "session": {"title": "Session", "type": "integer"}, "file": {"title": "File", "type": "string", "minLength": 1}, "file_time": {"title": "File Duration", "description": "Duration of the recording file", "type": "string", "x-nullable": true}, "recording_type": {"title": "Recording type", "type": "string", "enum": ["voice", "video"]}, "thumbnail": {"title": "Thumbnail", "type": "string", "minLength": 1, "x-nullable": true}, "created_at": {"title": "Created At", "description": "Time the recording was created", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated At", "description": "The datetime when the recording was last updated", "type": "string", "format": "date-time", "readOnly": true}}}, "SessionFileUpload": {"type": "object", "properties": {"recorded_file": {"title": "Recorded File", "description": "File of the recorded session", "type": "string", "readOnly": true, "x-nullable": true, "format": "uri"}}}, "CenterTag": {"required": ["id", "name"], "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "object"}}}, "CenterList": {"required": ["name", "slogan"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}, "slogan": {"title": "Slogan", "type": "string", "maxLength": 255, "minLength": 1}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "tags": {"type": "array", "items": {"$ref": "#/definitions/CenterTag"}, "readOnly": true}, "country": {"title": "Country", "type": "string", "maxLength": 255, "x-nullable": true}, "city": {"title": "City", "type": "string", "maxLength": 255, "x-nullable": true}, "lat": {"title": "Lat", "type": "number", "x-nullable": true}, "lon": {"title": "Lon", "type": "number", "x-nullable": true}, "distance": {"title": "Distance", "type": "string", "readOnly": true}, "is_bookmarked": {"title": "Is bookmarked", "type": "string", "readOnly": true}}}, "CenterDetail": {"required": ["name", "slogan"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}, "slogan": {"title": "Slogan", "type": "string", "maxLength": 255, "minLength": 1}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "header_image": {"title": "Header image", "type": "string", "readOnly": true}, "tags": {"type": "array", "items": {"$ref": "#/definitions/CenterTag"}, "readOnly": true}, "country": {"title": "Country", "type": "string", "maxLength": 255, "x-nullable": true}, "city": {"title": "City", "type": "string", "maxLength": 255, "x-nullable": true}, "lat": {"title": "Lat", "type": "number", "x-nullable": true}, "lon": {"title": "Lon", "type": "number", "x-nullable": true}, "address": {"title": "Address", "type": "string", "maxLength": 512, "x-nullable": true}, "website": {"title": "Website", "type": "string", "maxLength": 190, "x-nullable": true}, "phone_numbers": {"title": "Phone numbers", "type": "string", "maxLength": 512, "x-nullable": true}, "principal_name": {"title": "Principal name", "type": "string", "maxLength": 255, "x-nullable": true}, "working_hours": {"title": "Working hours", "type": "object"}, "social_medias": {"title": "Social medias", "type": "object"}, "congregations_prayers": {"title": "Congregations prayers", "type": "object"}, "imam_name": {"title": "Imam name", "type": "string", "maxLength": 255, "x-nullable": true}, "about_center": {"title": "About center", "type": "string", "x-nullable": true}, "google_map_link": {"title": "Google map link", "type": "string", "maxLength": 512, "x-nullable": true}, "stars": {"title": "Stars", "type": "number", "x-nullable": true}, "gallery": {"title": "Gallery", "type": "string", "readOnly": true}, "distance": {"title": "Distance", "type": "string", "readOnly": true}, "is_bookmarked": {"title": "Is bookmarked", "type": "string", "readOnly": true}}}, "CenterEvent": {"required": ["title", "date", "description"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 119, "minLength": 1}, "start_time": {"title": "Start time", "type": "string", "format": "date-time", "x-nullable": true}, "end_time": {"title": "End time", "type": "string", "format": "date-time", "x-nullable": true}, "date": {"title": "Date", "type": "string", "format": "date-time"}, "description": {"title": "Description", "type": "string", "minLength": 1}, "image": {"title": "Image", "type": "string", "readOnly": true}}}, "CenterProviderProfile": {"required": ["provider_type", "full_name", "email", "whatsapp_number", "role"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "provider_type": {"title": "Provider type", "description": "Type of provider: management team member or connected team member", "type": "string", "enum": ["management", "connected"]}, "full_name": {"title": "Full name", "description": "Full name of the provider", "type": "string", "maxLength": 550, "minLength": 1}, "email": {"title": "Email", "description": "Email address of the provider", "type": "string", "format": "email", "maxLength": 254, "minLength": 1}, "whatsapp_number": {"title": "Whatsapp number", "description": "WhatsApp number (9-15 digits)", "type": "string", "maxLength": 55, "minLength": 1}, "role": {"title": "Role", "description": "Role or position of the provider", "type": "string", "maxLength": 255, "minLength": 1}, "management_contact_name": {"title": "Management contact name", "description": "Name of management contact (optional, typically for connected team members)", "type": "string", "maxLength": 550, "x-nullable": true}, "is_verified": {"title": "Is verified", "description": "Whether this provider profile has been verified", "type": "boolean", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}}}, "ChallengeList": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "image": {"title": "Image", "type": "string", "readOnly": true}, "summary": {"title": "Summary", "type": "string", "readOnly": true}, "is_unlimited": {"title": "Is unlimited", "type": "boolean"}, "duration_days": {"title": "Duration days", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "status": {"title": "Is it displayed?", "type": "boolean"}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "participant_count": {"title": "Participant count", "type": "string", "readOnly": true}, "is_participant": {"title": "Is participant", "type": "string", "readOnly": true}}}, "ChallengeDetail": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "image": {"title": "Image", "type": "string", "readOnly": true}, "summary": {"title": "Summary", "type": "string", "readOnly": true}, "is_unlimited": {"title": "Is unlimited", "type": "boolean"}, "duration_days": {"title": "Duration days", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "status": {"title": "Is it displayed?", "type": "boolean"}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "participant_count": {"title": "Participant count", "type": "string", "readOnly": true}, "is_participant": {"title": "Is participant", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "readOnly": true}}}, "UserChecklistItem": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true, "minLength": 1}, "is_active": {"title": "Is active", "type": "boolean"}, "custom_days": {"type": "array", "items": {"type": "string", "x-nullable": true}}, "has_details": {"title": "Has details", "type": "string", "readOnly": true}, "task_type": {"title": "Task type", "type": "string", "readOnly": true}}}, "ChecklistEntryList": {"required": ["id", "title", "completed"], "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string", "minLength": 1}, "completed": {"title": "Completed", "type": "boolean"}, "has_details": {"title": "Has details", "type": "boolean", "default": false}}}, "ChecklistStats": {"required": ["total_days", "completed_days", "percentage"], "type": "object", "properties": {"total_days": {"title": "Total days", "type": "integer"}, "completed_days": {"title": "Completed days", "type": "integer"}, "percentage": {"title": "Percentage", "type": "number"}}}, "ChecklistDetail": {"required": ["content"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "content": {"title": "Content", "type": "string", "minLength": 1}, "language": {"title": "Language", "type": "integer"}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}}}, "HadisCategory": {"type": "object", "properties": {"name": {"title": "Name", "type": "string", "readOnly": true}, "hadis_count": {"title": "Hadis count", "type": "string", "readOnly": true}, "thumbnails": {"title": "Thumbnails", "type": "string", "readOnly": true}, "children": {"title": "Children", "type": "string", "readOnly": true}}}, "Reference": {"type": "object", "properties": {"book": {"title": "Book", "type": "string", "readOnly": true, "x-nullable": true}, "ref_doc_numb": {"title": "Vol", "type": "string", "maxLength": 64, "x-nullable": true}, "ref_doc_page": {"title": "Page", "type": "string", "maxLength": 64, "x-nullable": true}, "ref_hadis_num": {"title": "Number", "type": "string", "maxLength": 64, "x-nullable": true}, "ref_text": {"title": "Text", "type": "string", "maxLength": 200, "x-nullable": true}}, "x-nullable": true}, "Hadis": {"required": ["number", "text", "total_grade", "level"], "type": "object", "properties": {"number": {"title": "Number", "type": "integer", "maximum": 2147483647, "minimum": 0}, "text": {"title": "Text", "type": "string", "minLength": 1}, "translation": {"title": "Translation", "type": "string", "readOnly": true}, "narrated_by": {"title": "Narrated by", "type": "string", "readOnly": true}, "references": {"type": "array", "items": {"$ref": "#/definitions/Reference"}, "readOnly": true, "x-nullable": true}, "total_grade": {"title": "Total grade", "type": "integer", "x-nullable": true}, "level": {"title": "Level", "type": "integer", "x-nullable": true}}}, "Interest": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "icon": {"title": "Icon name", "description": "Fontawesome icon name", "type": "string", "maxLength": 64, "x-nullable": true}}}, "Narrator": {"required": ["hadis_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "hadis_count": {"title": "Hadis count", "type": "integer", "x-nullable": true}, "photo": {"title": "Photo", "type": "string", "readOnly": true, "x-nullable": true, "format": "uri"}}}, "Resources": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "readOnly": true}}}, "Trend": {"type": "object", "properties": {"title": {"title": "Title", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "hadis_count": {"title": "Hadis count", "type": "string", "readOnly": true}, "hadis_id_list": {"title": "Hadis id list", "type": "string", "readOnly": true}}}, "UserInterest": {"required": ["interests_ids", "gender", "age"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "user": {"title": "User", "type": "string", "readOnly": true, "minLength": 1}, "interests": {"type": "array", "items": {"$ref": "#/definitions/Interest"}, "readOnly": true}, "interests_ids": {"type": "array", "items": {"type": "integer"}}, "gender": {"title": "Gender", "type": "string", "enum": ["male", "female"]}, "age": {"title": "Age", "type": "integer", "maximum": 32767, "minimum": 0}, "tend_to_marry": {"title": "Tend to marry", "type": "boolean", "x-nullable": true}, "marital_status": {"title": "Marital status", "type": "boolean", "x-nullable": true}, "has_children": {"title": "Has children", "type": "boolean", "x-nullable": true}}}, "HadisSerializerV2": {"required": ["number", "text", "total_grade", "level"], "type": "object", "properties": {"number": {"title": "Number", "type": "integer", "maximum": 2147483647, "minimum": 0}, "text": {"title": "Text", "type": "string", "minLength": 1}, "translation": {"title": "Translation", "type": "string", "readOnly": true}, "narrated_by": {"title": "Narrated by", "type": "string", "readOnly": true}, "references": {"type": "array", "items": {"$ref": "#/definitions/Reference"}, "readOnly": true, "x-nullable": true}, "total_grade": {"title": "Total grade", "type": "integer", "x-nullable": true}, "level": {"title": "Level", "type": "integer", "x-nullable": true}, "tags": {"title": "Tags", "type": "string", "readOnly": true}}}, "NarratorSerializerV2": {"required": ["hadis_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "hadis_count": {"title": "Hadis count", "type": "integer", "x-nullable": true}, "photo": {"title": "Photo", "type": "string", "readOnly": true, "x-nullable": true, "format": "uri"}, "hadis_index": {"title": "Hadis index", "type": "string", "readOnly": true}}}, "AlbumList": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "dates": {"title": "Dates", "type": "object"}, "view_count": {"title": "View count", "type": "integer", "maximum": 2147483647, "minimum": -2147483648}, "songs_count": {"title": "Songs count", "type": "integer", "readOnly": true, "x-nullable": true}, "singer_type_counts": {"title": "Singer type counts", "type": "string", "readOnly": true}}}, "SingersList": {"required": ["slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "singer_type": {"title": "Singer type", "type": "string", "enum": ["lecturer", "madah", "singer"]}, "songs_count": {"title": "Songs count", "type": "integer", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 255, "minLength": 1}, "languages": {"type": "array", "items": {"type": "string"}, "readOnly": true, "uniqueItems": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "lang": {"title": "Lang", "type": "string", "readOnly": true, "minLength": 1}}}, "GenreList": {"required": ["title"], "type": "object", "properties": {"slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "title": {"title": "Title", "type": "string", "maxLength": 119, "minLength": 1}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}}}, "Publisher": {"required": ["name", "songs_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "url": {"title": "Url", "type": "string", "format": "uri", "maxLength": 200, "x-nullable": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}, "description": {"title": "Description", "type": "string", "maxLength": 1024, "x-nullable": true}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "readOnly": true}, "type": {"title": "Type", "type": "string", "enum": ["YT", "IT", "WS", "TG", "AP"]}, "languages": {"type": "array", "items": {"$ref": "#/definitions/Language"}, "readOnly": true}, "songs_count": {"title": "Songs count", "type": "integer", "x-nullable": true}}}, "SongsList": {"required": ["slug"], "type": "object", "properties": {"relative_url": {"title": "Relative url", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 50, "minLength": 1}, "title": {"title": "Title", "type": "string", "readOnly": true}, "singers": {"type": "array", "items": {"$ref": "#/definitions/SingersList"}, "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "genre": {"$ref": "#/definitions/GenreList"}, "song_type": {"title": "Song type", "type": "string", "enum": ["audio", "video", "youtube"]}, "file": {"title": "File", "type": "string", "readOnly": true}, "published_date": {"title": "Published date", "type": "string", "format": "date", "x-nullable": true}, "subtitle_languages": {"type": "array", "items": {"$ref": "#/definitions/Language"}, "readOnly": true}, "language": {"type": "array", "items": {"$ref": "#/definitions/Language"}, "readOnly": true}, "publisher": {"$ref": "#/definitions/Publisher"}, "like_count": {"title": "Like count", "type": "string", "readOnly": true}, "view_count": {"title": "View count", "type": "integer", "maximum": 9223372036854775807, "minimum": 0}, "is_liked": {"title": "Is liked", "type": "string", "readOnly": true}, "is_youtube": {"title": "Is youtube", "type": "boolean", "readOnly": true}, "is_playlist": {"title": "Is playlist", "type": "string", "readOnly": true}}}, "CollectionList": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "collection_type": {"title": "Collection type", "type": "string", "enum": ["all", "audio", "video", "youtube"], "x-nullable": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "songs_count": {"title": "Songs count", "type": "integer", "readOnly": true, "x-nullable": true}, "songs": {"title": "Songs", "type": "string", "readOnly": true}}}, "CollectionDetail": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "collection_type": {"title": "Collection type", "type": "string", "enum": ["all", "audio", "video", "youtube"], "x-nullable": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "songs_count": {"title": "Songs count", "type": "integer", "readOnly": true, "x-nullable": true}, "songs": {"title": "Songs", "type": "string", "readOnly": true}}}, "DashboardAlbumRow": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "translations": {"title": "Title", "type": "object"}, "dates": {"title": "Dates", "type": "object"}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "status": {"title": "Status", "type": "boolean"}, "is_pinned": {"title": "Pinned", "type": "boolean"}, "view_count": {"title": "View count", "type": "integer", "maximum": 2147483647, "minimum": -2147483648}, "song_count": {"title": "Song count", "type": "integer", "readOnly": true}, "langs": {"title": "Langs", "type": "string", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}, "updated": {"title": "Updated", "type": "string", "format": "date-time", "readOnly": true}}}, "DashboardAlbumInput": {"type": "object", "properties": {"translations": {"title": "Title", "type": "object"}, "dates": {"title": "Dates", "type": "object"}, "status": {"title": "Status", "type": "boolean"}, "is_pinned": {"title": "Pinned", "type": "boolean"}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "x-nullable": true}}}, "_AlbumAutocomplete": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}}}, "_GenreAutocomplete": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}}}, "_PublisherAutocomplete": {"required": ["name"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}}}, "_SingerAutocomplete": {"required": ["slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 255, "minLength": 1}, "singer_type": {"title": "Singer type", "type": "string", "enum": ["lecturer", "madah", "singer"]}}}, "_SongAutocomplete": {"required": ["slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 50, "minLength": 1}}}, "_TagAutocomplete": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}}}, "DashboardCollectionRow": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "object"}, "title_display": {"title": "Title display", "type": "string", "readOnly": true}, "dates": {"title": "Dates", "type": "object"}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "status": {"title": "Status", "type": "boolean"}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "ordering": {"title": "Display order", "type": "integer", "maximum": 2147483647, "minimum": 0}, "song_count": {"title": "Song count", "type": "integer", "readOnly": true}, "songs": {"title": "Songs", "type": "string", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}, "updated": {"title": "Updated", "type": "string", "format": "date-time", "readOnly": true}}}, "DashboardCollectionInput": {"type": "object", "properties": {"title": {"title": "Title", "type": "object"}, "dates": {"title": "Dates", "type": "object"}, "status": {"title": "Status", "type": "boolean"}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "ordering": {"title": "Display order", "type": "integer", "maximum": 2147483647, "minimum": 0}, "songs": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "x-nullable": true}}}, "DashboardGenreRow": {"required": ["title"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 119, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "song_count": {"title": "Song count", "type": "integer", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}}}, "DashboardGenreInput": {"required": ["title"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 119, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$"}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "x-nullable": true}}}, "ImportItemRow": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "source": {"title": "Source", "type": "string", "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"], "readOnly": true}, "input_kind": {"title": "Input kind", "type": "string", "enum": ["direct_link", "channel_page"], "readOnly": true}, "origin": {"title": "Origin", "type": "string", "enum": ["direct_link", "channel_page", "scheduled_task"], "readOnly": true}, "source_url": {"title": "Source url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "canonical_url": {"title": "Canonical url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "external_id": {"title": "External id", "type": "string", "readOnly": true, "minLength": 1}, "title": {"title": "Title", "type": "string", "readOnly": true, "minLength": 1}, "singer_name": {"title": "Singer name", "type": "string", "readOnly": true, "minLength": 1}, "duration_seconds": {"title": "Duration seconds", "type": "integer", "readOnly": true, "x-nullable": true}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "source_published_at": {"title": "Source published at", "type": "string", "format": "date-time", "readOnly": true, "x-nullable": true}, "status": {"title": "Status", "type": "string", "enum": ["queued", "discovering", "downloading", "processing", "ai_detecting", "metadata_review", "ready_to_publish", "published", "duplicate", "failed", "cancelled"], "readOnly": true}, "stage": {"title": "Stage", "type": "string", "readOnly": true, "minLength": 1}, "progress": {"title": "Progress", "type": "integer", "readOnly": true}, "ai_status": {"title": "AI status", "type": "string", "enum": ["pending", "running", "success", "failed", "skipped"], "readOnly": true}, "ai_confidence": {"title": "AI confidence", "type": "number", "readOnly": true, "x-nullable": true}, "needs_metadata_review": {"title": "Needs metadata review", "type": "boolean", "readOnly": true}, "error_message": {"title": "Error message", "type": "string", "readOnly": true, "minLength": 1}, "song_id": {"title": "Song id", "type": "string", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}}}, "ImportItemCreate": {"required": ["source_url"], "type": "object", "properties": {"source_url": {"title": "Source url", "type": "string", "maxLength": 1024, "minLength": 1}}}, "ImportItemDetail": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "source": {"title": "Source", "type": "string", "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"], "readOnly": true}, "input_kind": {"title": "Input kind", "type": "string", "enum": ["direct_link", "channel_page"], "readOnly": true}, "origin": {"title": "Origin", "type": "string", "enum": ["direct_link", "channel_page", "scheduled_task"], "readOnly": true}, "source_url": {"title": "Source url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "canonical_url": {"title": "Canonical url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "external_id": {"title": "External id", "type": "string", "readOnly": true, "minLength": 1}, "title": {"title": "Title", "type": "string", "readOnly": true, "minLength": 1}, "singer_name": {"title": "Singer name", "type": "string", "readOnly": true, "minLength": 1}, "duration_seconds": {"title": "Duration seconds", "type": "integer", "readOnly": true, "x-nullable": true}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "source_published_at": {"title": "Source published at", "type": "string", "format": "date-time", "readOnly": true, "x-nullable": true}, "status": {"title": "Status", "type": "string", "enum": ["queued", "discovering", "downloading", "processing", "ai_detecting", "metadata_review", "ready_to_publish", "published", "duplicate", "failed", "cancelled"], "readOnly": true}, "stage": {"title": "Stage", "type": "string", "readOnly": true, "minLength": 1}, "progress": {"title": "Progress", "type": "integer", "readOnly": true}, "ai_status": {"title": "AI status", "type": "string", "enum": ["pending", "running", "success", "failed", "skipped"], "readOnly": true}, "ai_confidence": {"title": "AI confidence", "type": "number", "readOnly": true, "x-nullable": true}, "needs_metadata_review": {"title": "Needs metadata review", "type": "boolean", "readOnly": true}, "error_message": {"title": "Error message", "type": "string", "readOnly": true, "minLength": 1}, "song_id": {"title": "Song id", "type": "string", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}, "task_id": {"title": "Task id", "type": "string", "readOnly": true}, "run_id": {"title": "Run id", "type": "string", "readOnly": true}, "attempts": {"title": "Attempts", "type": "integer", "readOnly": true}, "max_attempts": {"title": "Max attempts", "type": "integer", "readOnly": true}, "resolved_metadata": {"title": "Resolved metadata", "type": "object", "readOnly": true}, "ai_metadata": {"title": "Ai metadata", "type": "object", "readOnly": true}, "raw_metadata": {"title": "Raw metadata", "type": "object", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}}}, "ImportItemMetadata": {"type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 512}, "singer_name": {"title": "Singer name", "type": "string", "maxLength": 255}, "ai_metadata": {"title": "Ai metadata", "type": "object"}, "needs_metadata_review": {"title": "Needs metadata review", "type": "boolean"}, "status": {"title": "Status", "type": "string", "enum": ["queued", "discovering", "downloading", "processing", "ai_detecting", "metadata_review", "ready_to_publish", "published", "duplicate", "failed", "cancelled"]}}}, "DashboardPleaseRow": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "translations": {"title": "Title", "type": "object"}, "live_title": {"title": "Live title", "type": "object"}, "dates": {"title": "Dates", "type": "object"}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "status": {"title": "Status", "type": "boolean"}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "is_active": {"title": "Active", "description": "Use this field to activate or deactivate this entry. If active, it will be shown to users.", "type": "boolean"}, "view_count": {"title": "View count", "type": "integer", "maximum": 2147483647, "minimum": -2147483648}, "song_count": {"title": "Song count", "type": "integer", "readOnly": true}, "songs": {"title": "Songs", "type": "string", "readOnly": true}, "live_stream_link": {"title": "Live link", "type": "string", "maxLength": 255, "x-nullable": true}, "langs": {"title": "Langs", "type": "string", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}, "updated": {"title": "Updated", "type": "string", "format": "date-time", "readOnly": true}}}, "DashboardPleaseInput": {"type": "object", "properties": {"translations": {"title": "Title", "type": "object"}, "live_title": {"title": "Live title", "type": "object"}, "dates": {"title": "Dates", "type": "object"}, "status": {"title": "Status", "type": "boolean"}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "is_active": {"title": "Active", "description": "Use this field to activate or deactivate this entry. If active, it will be shown to users.", "type": "boolean"}, "live_stream_link": {"title": "Live link", "type": "string", "maxLength": 255, "x-nullable": true}, "songs": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "x-nullable": true}}}, "DashboardPublisherRow": {"required": ["name"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}, "type": {"title": "Type", "type": "string", "enum": ["YT", "IT", "WS", "TG", "AP"]}, "url": {"title": "Url", "type": "string", "format": "uri", "maxLength": 200, "x-nullable": true}, "priority": {"title": "Priority", "type": "integer", "maximum": 2147483647, "minimum": 0}, "languages": {"title": "Languages", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "maxLength": 1024, "x-nullable": true}, "instagram": {"title": "Instagram", "type": "string", "maxLength": 255, "x-nullable": true}, "youtube": {"title": "Youtube", "type": "string", "maxLength": 255, "x-nullable": true}, "telegram": {"title": "Telegram", "type": "string", "maxLength": 255, "x-nullable": true}, "website": {"title": "Telegram", "type": "string", "maxLength": 255, "x-nullable": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}, "updated": {"title": "Updated", "type": "string", "format": "date-time", "readOnly": true}}}, "DashboardPublisherInput": {"required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}, "type": {"title": "Type", "type": "string", "enum": ["YT", "IT", "WS", "TG", "AP"]}, "url": {"title": "Url", "type": "string", "format": "uri", "maxLength": 200, "x-nullable": true}, "priority": {"title": "Priority", "type": "integer", "maximum": 2147483647, "minimum": 0}, "languages": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "description": {"title": "Description", "type": "string", "maxLength": 1024, "x-nullable": true}, "instagram": {"title": "Instagram", "type": "string", "maxLength": 255, "x-nullable": true}, "youtube": {"title": "Youtube", "type": "string", "maxLength": 255, "x-nullable": true}, "telegram": {"title": "Telegram", "type": "string", "maxLength": 255, "x-nullable": true}, "website": {"title": "Telegram", "type": "string", "maxLength": 255, "x-nullable": true}, "avatar_url": {"title": "Avatar url", "type": "string", "x-nullable": true}}}, "ImportRunRow": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "task_id": {"title": "Task id", "type": "string", "readOnly": true}, "source": {"title": "Source", "type": "string", "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"], "readOnly": true}, "source_url": {"title": "Source url", "type": "string", "format": "uri", "readOnly": true, "minLength": 1}, "scope": {"title": "Scope", "type": "object", "readOnly": true}, "status": {"title": "Status", "type": "string", "enum": ["running", "success", "failed", "cancelled"], "readOnly": true}, "discovered_count": {"title": "Discovered count", "type": "integer", "readOnly": true}, "created_count": {"title": "Created count", "type": "integer", "readOnly": true}, "duplicate_count": {"title": "Duplicate count", "type": "integer", "readOnly": true}, "failed_count": {"title": "Failed count", "type": "integer", "readOnly": true}, "summary": {"title": "Summary", "type": "string", "readOnly": true, "minLength": 1}, "error_message": {"title": "Error message", "type": "string", "readOnly": true, "minLength": 1}, "started_at": {"title": "Started at", "type": "string", "format": "date-time", "readOnly": true}, "finished_at": {"title": "Finished at", "type": "string", "format": "date-time", "readOnly": true, "x-nullable": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}}}, "DashboardSinger": {"required": ["slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "latin": {"title": "Latin", "type": "string", "readOnly": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}, "type": {"title": "Type", "type": "string", "readOnly": true}, "singer_type": {"title": "Singer type", "type": "string", "enum": ["lecturer", "madah", "singer"]}, "works": {"title": "Works", "type": "integer", "readOnly": true}, "langs": {"title": "Langs", "type": "string", "readOnly": true}, "sub_langs": {"title": "Sub langs", "type": "string", "readOnly": true}, "status": {"title": "Status", "type": "string", "readOnly": true}, "updated": {"title": "Updated", "type": "string", "readOnly": true}, "desc": {"title": "Desc", "type": "string", "readOnly": true}, "panelId": {"title": "Panelid", "type": "string", "readOnly": true, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 255, "minLength": 1}, "translations": {"title": "Name", "type": "object"}, "view_count": {"title": "View count", "type": "integer", "readOnly": true}, "is_pinned": {"title": "Pinned", "type": "boolean"}, "ordering": {"title": "Display order", "type": "integer", "maximum": 2147483647, "minimum": 0}, "priority": {"title": "Priority", "type": "integer", "maximum": 9223372036854775807, "minimum": 0}}}, "DashboardSingerInput": {"type": "object", "properties": {"translations": {"title": "Name", "type": "object"}, "singer_type": {"title": "Singer type", "type": "string", "enum": ["lecturer", "madah", "singer"]}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-\\w]+$"}, "biography": {"title": "Biography", "description": "could be empty", "type": "string", "x-nullable": true}, "status": {"title": "Status", "type": "boolean"}, "languages": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "sub_languages": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "is_pinned": {"title": "Pinned", "type": "boolean"}, "ordering": {"title": "Display order", "type": "integer", "maximum": 2147483647, "minimum": 0}, "priority": {"title": "Priority", "type": "integer", "maximum": 9223372036854775807, "minimum": 0}, "avatar_url": {"title": "Avatar url", "type": "string", "x-nullable": true}}}, "_GenreMin": {"required": ["title"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 119, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}}}, "_SingerMin": {"required": ["slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 255, "minLength": 1}}}, "_PublisherMin": {"required": ["name"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}}}, "_TagMin": {"required": ["title"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 119, "minLength": 1}}}, "DashboardSongRow": {"required": ["slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 50, "minLength": 1}, "types": {"title": "Types", "type": "string", "readOnly": true}, "genre": {"$ref": "#/definitions/_GenreMin"}, "singers": {"type": "array", "items": {"$ref": "#/definitions/_SingerMin"}, "readOnly": true}, "langs": {"title": "Langs", "type": "string", "readOnly": true}, "status": {"title": "Status", "type": "boolean"}, "publisher": {"$ref": "#/definitions/_PublisherMin"}, "published_date": {"title": "Published date", "type": "string", "format": "date", "x-nullable": true}, "tags": {"type": "array", "items": {"$ref": "#/definitions/_TagMin"}, "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "file": {"title": "File", "type": "string", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}, "updated": {"title": "Updated", "type": "string", "format": "date-time", "readOnly": true}, "is_pinned": {"title": "Pinned", "type": "boolean"}, "ordering": {"title": "Display order", "type": "integer", "maximum": 2147483647, "minimum": 0}}}, "DashboardSongInput": {"required": ["slug", "genre", "singers", "language"], "type": "object", "properties": {"title": {"title": "Title", "type": "object"}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 50, "minLength": 1}, "song_type": {"title": "Song type", "type": "string", "enum": ["audio", "video", "youtube"]}, "genre": {"title": "Genre", "type": "integer"}, "singers": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "albums": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "language": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "subtitle_languages": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "tags": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "publisher": {"title": "Publisher", "type": "integer", "x-nullable": true}, "status": {"title": "Status", "type": "boolean"}, "youtube_link": {"title": "Youtube link", "type": "string", "maxLength": 255, "x-nullable": true}, "audio_file_remote_server": {"title": "Audio file remote url", "type": "string", "format": "uri", "maxLength": 200, "x-nullable": true}, "file_remote_server": {"title": "File remote url", "description": "Upload file from remote server", "type": "string", "format": "uri", "maxLength": 200, "x-nullable": true}, "lyric": {"title": "Lyric", "description": "could be empty", "type": "string", "x-nullable": true}, "published_date": {"title": "Published date", "type": "string", "format": "date", "x-nullable": true}, "is_pinned": {"title": "Pinned", "type": "boolean"}, "ordering": {"title": "Display order", "type": "integer", "maximum": 2147483647, "minimum": 0}, "thumbnail_url": {"title": "Thumbnail url", "type": "string", "x-nullable": true}}}, "ImportSourceTaskRow": {"required": ["page_url"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 255}, "source": {"title": "Source", "type": "string", "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"]}, "page_url": {"title": "Page url", "type": "string", "format": "uri", "maxLength": 1024, "minLength": 1}, "external_id": {"title": "External id", "type": "string", "maxLength": 255}, "frequency_days": {"title": "Frequency days", "type": "integer", "maximum": 32767, "minimum": 0}, "run_time": {"title": "Run time", "type": "string"}, "max_items_per_run": {"title": "Max items per run", "type": "integer", "maximum": 32767, "minimum": 0}, "only_new_items": {"title": "Only new items", "type": "boolean"}, "ignore_duplicates": {"title": "Ignore duplicates", "type": "boolean"}, "auto_stop_on_errors": {"title": "Auto stop on errors", "type": "boolean"}, "notify_on_error": {"title": "Notify on error", "type": "boolean"}, "enabled": {"title": "Enabled", "type": "boolean"}, "last_run_at": {"title": "Last run at", "type": "string", "format": "date-time", "readOnly": true, "x-nullable": true}, "next_run_at": {"title": "Next run at", "type": "string", "format": "date-time", "readOnly": true, "x-nullable": true}, "last_run_status": {"title": "Last run status", "type": "string", "readOnly": true, "minLength": 1}, "new_items_last_run": {"title": "New items last run", "type": "integer", "readOnly": true}, "error_streak": {"title": "Error streak", "type": "integer", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}}}, "ImportSourceTaskInput": {"required": ["page_url"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255}, "source": {"title": "Source", "type": "string", "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"]}, "page_url": {"title": "Page url", "type": "string", "format": "uri", "maxLength": 1024, "minLength": 1}, "frequency_days": {"title": "Frequency days", "type": "integer", "maximum": 32767, "minimum": 0}, "run_time": {"title": "Run time", "type": "string"}, "max_items_per_run": {"title": "Max items per run", "type": "integer", "maximum": 32767, "minimum": 0}, "only_new_items": {"title": "Only new items", "type": "boolean"}, "ignore_duplicates": {"title": "Ignore duplicates", "type": "boolean"}, "auto_stop_on_errors": {"title": "Auto stop on errors", "type": "boolean"}, "notify_on_error": {"title": "Notify on error", "type": "boolean"}, "enabled": {"title": "Enabled", "type": "boolean"}}}, "DashboardTagRow": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "translations": {"title": "Translations", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "readOnly": true, "minLength": 1}, "song_count": {"title": "Song count", "type": "integer", "readOnly": true}, "letter": {"title": "Letter", "type": "string", "readOnly": true}}}, "DashboardTagInput": {"type": "object", "properties": {"translations": {"title": "Translations", "type": "object"}, "slug": {"title": "Slug", "type": "string"}}}, "_Upload": {"type": "object", "properties": {"file": {"title": "File", "type": "string", "readOnly": true, "format": "uri"}}}, "YoutubeInfo": {"required": ["youtube_link"], "type": "object", "properties": {"thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true, "minLength": 1}, "title": {"title": "Title", "type": "string", "readOnly": true, "minLength": 1}, "description": {"title": "Description", "type": "string", "readOnly": true, "minLength": 1}, "youtube_link": {"title": "Youtube link", "type": "string", "format": "uri", "minLength": 1}, "language_code": {"title": "Language code", "type": "string", "readOnly": true, "minLength": 1, "x-nullable": true}}}, "ShrineLive": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "live_title": {"title": "Live title", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "live_stream_link": {"title": "Live stream link", "type": "string", "readOnly": true}, "status": {"title": "Status", "type": "boolean"}, "pin_to_top": {"title": "Pin to top", "type": "boolean"}, "live_count": {"title": "Live count", "type": "string", "readOnly": true}}}, "HussainiyaProviderProfileSerializer": {"required": ["role", "languages", "avatar"], "type": "object", "properties": {"full_name": {"title": "Full name", "type": "string", "maxLength": 254, "minLength": 1, "x-nullable": true}, "bio": {"title": "Bio", "type": "string", "maxLength": 512, "x-nullable": true}, "role": {"title": "Role", "type": "string", "enum": ["lecturer", "madah", "singer"]}, "birthdate": {"title": "Birthdate", "type": "string", "format": "date", "x-nullable": true}, "email": {"title": "Email", "type": "string", "format": "email", "maxLength": 254, "x-nullable": true}, "wa_number": {"title": "Whatsapp number", "type": "string", "maxLength": 255, "x-nullable": true}, "institution_name": {"title": "Name", "description": "Name of the institute", "type": "string", "maxLength": 255, "x-nullable": true}, "languages": {"type": "array", "items": {"type": "string"}}, "avatar": {"title": "Avatar", "type": "string", "minLength": 1}, "social_medias": {"title": "Social medias", "description": "Provider social media profiles", "type": "object"}}}, "CreateSong": {"required": ["genre", "albums", "title", "language"], "type": "object", "properties": {"youtube_link": {"title": "Youtube link", "type": "string", "maxLength": 255, "x-nullable": true}, "file_path": {"title": "File path", "type": "string", "x-nullable": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "x-nullable": true}, "genre": {"title": "Genre", "type": "integer"}, "albums": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "title": {"type": "array", "items": {"type": "object", "required": ["title", "language_code"], "properties": {"title": {"title": "title", "type": "string"}, "language_code": {"title": "language code", "description": "eg. en, da", "type": "string"}}}}, "slug": {"title": "Slug", "type": "string", "readOnly": true}, "language": {"description": "eg. [en, fa, ...]", "type": "array", "items": {"type": "string", "minLength": 1}}}}, "UpdateSong": {"required": ["genre", "albums"], "type": "object", "properties": {"thumbnail": {"title": "Thumbnail", "type": "string", "x-nullable": true}, "genre": {"title": "Genre", "type": "integer"}, "albums": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "title": {"type": "array", "items": {"type": "object", "required": ["title", "language_code"], "properties": {"title": {"title": "title", "type": "string"}, "language_code": {"title": "language code", "description": "eg. en, da", "type": "string"}}}}, "language": {"description": "eg. [en, fa, ...]", "type": "array", "items": {"type": "string", "minLength": 1}}}}, "PlaylistTabCollection": {"required": ["id", "title", "song_count", "is_personal", "editable"], "type": "object", "properties": {"id": {"title": "Id", "type": "string", "minLength": 1}, "title": {"title": "Title", "type": "string", "minLength": 1, "x-nullable": true}, "song_count": {"title": "Song count", "type": "integer"}, "is_personal": {"title": "Is personal", "type": "boolean"}, "editable": {"title": "Editable", "type": "boolean"}}}, "SingerSong": {"required": ["slug"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "readOnly": true}, "singer_type": {"title": "Singer type", "type": "string", "enum": ["lecturer", "madah", "singer"]}, "songs_count": {"title": "Songs count", "type": "integer", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 255, "minLength": 1}, "languages": {"type": "array", "items": {"type": "string"}, "readOnly": true, "uniqueItems": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "songs": {"title": "Songs", "type": "string", "readOnly": true}}}, "Seo": {"type": "object", "properties": {"title": {"title": "Seo title", "description": "maximum length of page title is 70 characters and minimum length is 30", "type": "string", "maxLength": 140, "x-nullable": true}, "keywords": {"title": "Keywords", "description": "keywords in the content that make it possible for people to find the site via search engines", "type": "string", "maxLength": 255, "x-nullable": true}, "description": {"title": "Description", "description": "describes and summarizes the contents of the page for the benefit of users and search engines", "type": "string", "maxLength": 170, "x-nullable": true}}}, "SongDetail": {"required": ["slug"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "maxLength": 50, "minLength": 1}, "singers": {"type": "array", "items": {"$ref": "#/definitions/SingersList"}, "readOnly": true}, "file": {"title": "File", "type": "string", "readOnly": true}, "song_type": {"title": "Song type", "type": "string", "enum": ["audio", "video", "youtube"]}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "lyric": {"title": "Lyric", "description": "could be empty", "type": "string", "x-nullable": true}, "published_date": {"title": "Published date", "type": "string", "format": "date", "x-nullable": true}, "info": {"title": "Info", "type": "object", "x-nullable": true}, "genre": {"$ref": "#/definitions/GenreList"}, "view_count": {"title": "View count", "type": "integer", "maximum": 9223372036854775807, "minimum": 0}, "like_count": {"title": "Like count", "type": "string", "readOnly": true}, "language": {"type": "array", "items": {"$ref": "#/definitions/Language"}, "readOnly": true}, "is_playlist": {"title": "Is playlist", "type": "string", "readOnly": true}, "seo_fields": {"$ref": "#/definitions/Seo"}, "publisher": {"$ref": "#/definitions/Publisher"}, "is_liked": {"title": "Is liked", "type": "string", "readOnly": true}, "is_youtube": {"title": "Is youtube", "type": "string", "readOnly": true}, "youtube_audio_file": {"title": "Youtube audio file", "type": "string", "readOnly": true}}}, "ImportantNotice": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "x-nullable": true}, "subtitle": {"title": "Subtitle", "type": "string", "x-nullable": true}, "alert_color": {"title": "Alert color", "type": "string", "enum": ["#FF0000", "#FFFF00", "#00FF00", "#0000FF"], "x-nullable": true}, "alert_color_display": {"title": "Alert color display", "type": "string", "readOnly": true, "minLength": 1}, "small_image": {"title": "Small image", "type": "string", "readOnly": true, "x-nullable": true, "format": "uri"}, "target_route": {"title": "Target route", "type": "string", "maxLength": 255, "x-nullable": true}, "language": {"title": "Language", "type": "integer", "x-nullable": true}, "status": {"title": "Status", "type": "boolean"}}}, "GroupKhatm": {"required": ["group_type"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "minLength": 1}, "slug": {"title": "Slug", "type": "string", "readOnly": true}, "language_code": {"title": "Language code", "type": "string", "readOnly": true}, "language_name": {"title": "Language name", "type": "string", "readOnly": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "minLength": 1, "x-nullable": true}, "users_count": {"title": "Users count", "type": "string", "readOnly": true}, "current_round": {"title": "Current round", "type": "string", "readOnly": true}, "total_pages_read": {"title": "Total pages read", "type": "integer", "readOnly": true}, "created_by": {"title": "Created by", "type": "string", "readOnly": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "group_type": {"title": "Group type", "type": "string", "enum": ["public", "private"]}, "progress_percentage": {"title": "Progress percentage", "type": "string", "readOnly": true}, "pages": {"title": "Pages", "type": "string", "readOnly": true}}}, "ReadPage": {"required": ["page_user_id"], "type": "object", "properties": {"page_user_id": {"title": "Page user id", "type": "integer", "minimum": 1}, "last_page_read": {"title": "Last page read", "type": "integer", "readOnly": true}, "total_pages_read_group": {"title": "Total pages read group", "type": "integer", "readOnly": true}, "remaining_pages": {"title": "Remaining pages", "type": "string", "readOnly": true}}}, "IndividualKhatm": {"required": ["name", "session_type", "session_value"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "session_type": {"title": "Session type", "type": "string", "enum": ["page", "juz"]}, "session_value": {"title": "Session value", "type": "integer"}, "last_session_read": {"title": "Last session read", "type": "integer", "readOnly": true}, "total_sessions": {"title": "Total Sessions", "type": "integer", "readOnly": true}, "total_count_info": {"title": "Total count info", "type": "string", "readOnly": true}, "progress_percentage": {"title": "Progress percentage", "type": "string", "readOnly": true}, "total_pages_read": {"title": "Pages read", "type": "string", "readOnly": true}}}, "IndividualKhatmUpdate": {"required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string", "maxLength": 100, "minLength": 1}}}, "IndividualReadPage": {"required": ["session"], "type": "object", "properties": {"session": {"title": "Session", "type": "integer"}, "remaining_pages": {"title": "Remaining pages", "type": "integer", "readOnly": true}}}, "UserGroupKhatm": {"required": ["khatm", "from_page", "to_page", "pages_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "khatm": {"$ref": "#/definitions/GroupKhatm"}, "guest_fullname": {"title": "Guest fullname", "type": "string", "maxLength": 255, "x-nullable": true}, "guest_wa_number": {"title": "Guest whatsapp number", "type": "string", "maxLength": 255, "x-nullable": true}, "from_page": {"title": "From page", "type": "integer", "maximum": 32767, "minimum": 0}, "to_page": {"title": "To page", "type": "integer", "maximum": 32767, "minimum": 0}, "pages_count": {"title": "Pages count", "type": "integer", "maximum": 32767, "minimum": 0}, "last_page_read": {"title": "Last page read", "type": "integer", "maximum": 2147483647, "minimum": 0}, "created_at": {"title": "Joined at", "type": "string", "format": "date-time", "readOnly": true}}}, "BannerList": {"required": ["description"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "minLength": 1}, "covers": {"title": "Covers", "type": "string", "readOnly": true}}}, "Author": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}}}, "BookList": {"required": ["title", "author", "type"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "price": {"title": "Price (Coin)", "type": "string", "format": "decimal"}, "author": {"type": "array", "items": {"$ref": "#/definitions/Author"}}, "type": {"title": "Type", "type": "string", "minLength": 1}, "rates": {"title": "Rates", "type": "string", "readOnly": true}, "is_bookmark": {"title": "Is bookmark", "type": "boolean", "default": false}}}, "BookListSerializerEditorSuggestion": {"required": ["author"], "type": "object", "properties": {"slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "author": {"type": "array", "items": {"$ref": "#/definitions/Author"}}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "summary": {"title": "Summary", "description": "could be null", "type": "string", "maxLength": 512, "x-nullable": true}}}, "BookListV2": {"required": ["title", "author", "file_types"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "price": {"title": "Price (Coin)", "type": "string", "format": "decimal"}, "discount_percentage": {"title": "Discount Percentage", "description": "Discount percentage as an integer between 0 and 100", "type": "integer", "maximum": 2147483647, "minimum": 0}, "final_price": {"title": "Final Price (Coin)", "description": "This field is automatically calculated based on the discount percentage.", "type": "string", "format": "decimal"}, "author": {"type": "array", "items": {"$ref": "#/definitions/Author"}}, "file_types": {"type": "array", "items": {"type": "string", "minLength": 1}}, "rates": {"title": "Rates", "type": "string", "readOnly": true}, "is_bookmark": {"title": "Is bookmark", "type": "boolean", "default": false}}}, "BookFiles": {"required": ["title"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "file": {"title": "File", "type": "string", "readOnly": true, "format": "uri"}, "pages_count": {"title": "Number of Pages", "description": "eg. 34", "type": "string", "maxLength": 255, "minLength": 1, "x-nullable": true}}}, "BookPublisher": {"required": ["username", "name"], "type": "object", "properties": {"username": {"title": "Username", "type": "string", "minLength": 1, "x-nullable": true}, "name": {"title": "Name", "type": "string", "minLength": 1}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}}}, "BookDetail": {"required": ["title", "author", "type", "files", "language", "publisher"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "is_bookmark": {"title": "Is bookmark", "type": "boolean", "default": false}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "price": {"title": "Price (Coin)", "type": "string", "format": "decimal"}, "author": {"type": "array", "items": {"$ref": "#/definitions/Author"}}, "type": {"title": "Type", "type": "string", "minLength": 1}, "narrator": {"title": "Narrator", "type": "string", "readOnly": true}, "files": {"type": "array", "items": {"$ref": "#/definitions/BookFiles"}}, "pages_count": {"title": "Number of Pages", "description": "eg. 34", "type": "string", "maxLength": 255, "minLength": 1, "x-nullable": true}, "view_count": {"title": "View count", "type": "integer", "maximum": 9223372036854775807, "minimum": 0}, "download_count": {"title": "Download count", "type": "integer", "default": 9}, "language": {"type": "array", "items": {"$ref": "#/definitions/Language"}}, "summary": {"title": "Summary", "description": "could be null", "type": "string", "maxLength": 512, "x-nullable": true}, "publisher": {"$ref": "#/definitions/BookPublisher"}, "rates": {"title": "Rates", "type": "string", "readOnly": true}, "related": {"title": "Related", "type": "string", "readOnly": true}}}, "UserRate": {"type": "object", "properties": {"name": {"title": "Name", "type": "string", "readOnly": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "rate": {"title": "Rate", "type": "integer", "maximum": 32767, "minimum": 0, "x-nullable": true}, "note": {"title": "Note", "type": "string", "maxLength": 512, "x-nullable": true}, "date": {"title": "Date", "type": "string", "format": "date-time", "readOnly": true}}}, "Category": {"required": ["icon", "book_count"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "readOnly": true, "x-nullable": true}, "id": {"title": "ID", "type": "integer", "readOnly": true}, "icon": {"title": "Icon", "description": "fontawesome icon. eg. fa-book", "type": "string", "maxLength": 32, "minLength": 1}, "book_count": {"title": "Book count", "type": "integer", "x-nullable": true}}}, "Files": {"required": ["title", "pdf_file"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "pdf_file": {"title": "Pdf file", "type": "string", "minLength": 1}, "pages_count": {"title": "Number of Pages", "description": "eg. 34", "type": "string", "maxLength": 255, "minLength": 1, "x-nullable": true}}}, "CreateBook": {"required": ["title", "thumbnail", "files"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "price": {"title": "Price (Coin)", "type": "string", "format": "decimal"}, "summary": {"title": "Summary", "description": "could be null", "type": "string", "maxLength": 512, "x-nullable": true}, "description": {"title": "Description", "description": "could be null", "type": "string", "x-nullable": true}, "thumbnail": {"title": "Thumbnail", "type": "string", "minLength": 1}, "tags": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "categories": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "authors": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "translators": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "narrators": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, "publish_year": {"title": "Publish year", "description": "eg. 1998", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "vol_count": {"title": "Number of Volumes", "description": "eg. 3", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "isbn": {"title": "ISBN", "type": "string", "maxLength": 225, "x-nullable": true}, "files": {"type": "array", "items": {"$ref": "#/definitions/Files"}}}}, "PublisherList": {"required": ["full_name", "book_count"], "type": "object", "properties": {"full_name": {"title": "Full name", "type": "string", "maxLength": 255, "minLength": 1}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "book_count": {"title": "Book count", "type": "integer", "x-nullable": true}, "id": {"title": "ID", "type": "integer", "readOnly": true}}}, "BookFilesV2": {"required": ["title"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "file": {"title": "File", "type": "string", "readOnly": true, "format": "uri"}, "type": {"title": "File Type", "type": "string", "enum": ["pdf", "html", "epub", "docx", "audio"]}, "pages_count": {"title": "Number of Pages", "description": "eg. 34", "type": "string", "maxLength": 255, "minLength": 1, "x-nullable": true}, "volume": {"title": "Volume", "description": "The volume number of the book, e.g., 1 for first volume.", "type": "integer", "maximum": 2147483647, "minimum": -2147483648, "x-nullable": true}}}, "BookDetailV2": {"required": ["title", "author", "file_types", "book_files", "language", "publisher", "categories"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "readOnly": true, "minLength": 1}, "is_bookmark": {"title": "Is bookmark", "type": "boolean", "default": false}, "is_download": {"title": "Is download", "type": "boolean", "default": false}, "price": {"title": "Price (Coin)", "type": "string", "format": "decimal"}, "discount_percentage": {"title": "Discount Percentage", "description": "Discount percentage as an integer between 0 and 100", "type": "integer", "maximum": 2147483647, "minimum": 0}, "final_price": {"title": "Final Price (Coin)", "description": "This field is automatically calculated based on the discount percentage.", "type": "string", "format": "decimal"}, "thumbnail": {"title": "Thumbnail", "type": "string", "readOnly": true}, "author": {"type": "array", "items": {"$ref": "#/definitions/Author"}}, "file_types": {"type": "array", "items": {"type": "string", "minLength": 1}}, "view_count": {"title": "View count", "type": "integer", "maximum": 9223372036854775807, "minimum": 0}, "download_count": {"title": "Download count", "type": "string", "readOnly": true}, "narrator": {"title": "Narrator", "type": "string", "readOnly": true}, "book_files": {"type": "array", "items": {"$ref": "#/definitions/BookFilesV2"}}, "pages_count": {"title": "Number of Pages", "description": "eg. 34", "type": "string", "maxLength": 255, "minLength": 1, "x-nullable": true}, "language": {"type": "array", "items": {"$ref": "#/definitions/Language"}}, "description": {"title": "Description", "description": "could be null", "type": "string", "x-nullable": true}, "summary": {"title": "Summary", "description": "could be null", "type": "string", "maxLength": 512, "x-nullable": true}, "publisher": {"$ref": "#/definitions/BookPublisher"}, "categories": {"type": "array", "items": {"$ref": "#/definitions/Category"}}, "rates": {"title": "Rates", "type": "string", "readOnly": true}, "sample_file": {"title": "Sample file", "type": "string", "readOnly": true}, "related": {"title": "Related", "type": "string", "readOnly": true}}}, "AuthorList": {"required": ["slug", "book_count"], "type": "object", "properties": {"slug": {"title": "Slug", "type": "string", "minLength": 1}, "name": {"title": "Name", "type": "string", "readOnly": true}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}, "book_count": {"title": "Book count", "type": "integer", "x-nullable": true}}}, "MafatihCategories": {"required": ["language"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "thumbnails": {"title": "Thumbnails", "type": "string", "readOnly": true}, "duas_index": {"title": "Duas index", "type": "string", "readOnly": true}, "language": {"$ref": "#/definitions/Language"}, "children": {"title": "Children", "type": "string", "readOnly": true}}}, "DuaCategories": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "thumbnails": {"title": "Thumbnails", "type": "string", "readOnly": true}, "duas_index": {"title": "Duas index", "type": "string", "readOnly": true}, "language": {"title": "Language", "type": "string", "readOnly": true}, "children": {"title": "Children", "type": "string", "readOnly": true}}}, "MafatihDuaPart": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "dua_part_index": {"title": "Dua part index", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string", "x-nullable": true}, "translation": {"title": "Translation", "type": "string", "x-nullable": true}, "local_alpha": {"title": "Local alpha", "type": "string", "x-nullable": true}, "mafatih_dua_id": {"title": "Mafatih dua id", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "x-nullable": true}}}, "DuaPartSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "dua_part_index": {"title": "Dua part index", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string", "x-nullable": true}, "translation": {"title": "Translation", "type": "string", "readOnly": true}, "local_alpha": {"title": "Local alpha", "type": "string", "readOnly": true}, "dua_id": {"title": "Dua id", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "readOnly": true}}}, "MafatihDua": {"required": ["title"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 192, "minLength": 1}, "duas_part_list": {"type": "array", "items": {"type": "integer"}, "readOnly": true, "uniqueItems": true}, "dates": {"title": "Dates", "description": "لیستی از تاریخ های قمری مربوط به قطعه", "type": "object", "x-nullable": true}, "weekdays": {"title": "Weekdays", "type": "string", "readOnly": true}, "audio_sync_data": {"title": "Audio sync data", "type": "string", "readOnly": true}, "audio": {"title": "Audio", "type": "string", "readOnly": true}}}, "DuaAudioDetail": {"required": ["reciter"], "type": "object", "properties": {"reciter": {"title": "Reciter", "type": "string", "maxLength": 119, "minLength": 1}, "audio": {"title": "Audio", "type": "string", "readOnly": true}, "audio_sync_data": {"title": "Audio sync data", "type": "object"}}}, "MafatihDuaSerializerV2": {"required": ["title", "audios"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 192, "minLength": 1}, "duas_part_list": {"type": "array", "items": {"type": "integer"}, "readOnly": true, "uniqueItems": true}, "dates": {"title": "Dates", "description": "لیستی از تاریخ های قمری مربوط به قطعه", "type": "object", "x-nullable": true}, "weekdays": {"title": "Weekdays", "type": "string", "readOnly": true}, "audios": {"type": "array", "items": {"$ref": "#/definitions/DuaAudioDetail"}}}}, "DuaAudioDetailV3": {"type": "object", "properties": {"reciter": {"title": "Reciter", "type": "string", "readOnly": true}, "audio": {"title": "Audio", "type": "string", "readOnly": true}, "audio_sync_data": {"title": "Audio sync data", "type": "object"}}}, "MafatihDuaSerializerV3": {"required": ["audios"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "similar_titles": {"title": "Similar Titles", "type": "object", "x-nullable": true}, "duas_part_list": {"type": "array", "items": {"type": "integer"}, "readOnly": true, "uniqueItems": true}, "dates": {"title": "Dates", "description": "لیستی از تاریخ های قمری مربوط به قطعه", "type": "object", "x-nullable": true}, "weekdays": {"title": "Weekdays", "type": "string", "readOnly": true}, "audios": {"type": "array", "items": {"$ref": "#/definitions/DuaAudioDetailV3"}}}}, "DuaAudioList": {"required": ["reciter"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "reciter": {"title": "Reciter", "type": "string", "maxLength": 119, "minLength": 1}}}, "Masael": {"required": ["title", "content"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "content": {"title": "Content", "type": "string", "minLength": 1}, "category": {"title": "Category", "type": "string", "readOnly": true}, "root_id": {"title": "Root id", "type": "string", "readOnly": true}}}, "MarjaaGuide": {"required": ["language"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "x-nullable": true}, "language": {"$ref": "#/definitions/Language"}, "answer": {"title": "Answer", "type": "string", "x-nullable": true}, "priority": {"title": "Priority", "type": "integer", "maximum": 2147483647, "minimum": -2147483648}}}, "MasaelContent": {"required": ["text"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "header": {"title": "Header", "type": "string", "x-nullable": true}, "text": {"title": "Text", "type": "string", "minLength": 1}, "answer": {"title": "Answer", "type": "string", "x-nullable": true}, "priority": {"title": "Priority", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}}}, "MasaelSerializerV2": {"required": ["title"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "priority": {"title": "Priority", "type": "integer", "maximum": 2147483647, "minimum": 0, "x-nullable": true}, "category": {"title": "Category", "type": "integer", "x-nullable": true}, "title": {"title": "Title", "type": "string", "maxLength": 255, "minLength": 1}, "contents": {"type": "array", "items": {"$ref": "#/definitions/MasaelContent"}, "readOnly": true}}}, "Note": {"required": ["service", "object_id", "note_text"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "service": {"title": "Service", "type": "string", "enum": ["quran", "mafatih", "hadis", "habit"]}, "object_id": {"title": "Object id", "type": "integer", "maximum": 2147483647, "minimum": -2147483648}, "user": {"title": "User", "type": "string", "readOnly": true}, "note_text": {"title": "Note text", "type": "string", "minLength": 1}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}, "feedback_count": {"title": "Feedback count", "type": "string", "readOnly": true}, "language": {"title": "Language", "type": "string", "readOnly": true}, "request_user_feedback": {"title": "Request user feedback", "type": "string", "readOnly": true}}}, "NoteFeedback": {"required": ["note"], "type": "object", "properties": {"note": {"title": "Note", "type": "integer"}, "is_positive": {"title": "Is positive", "type": "boolean"}, "user": {"title": "User", "type": "integer", "readOnly": true, "x-nullable": true}}}, "Plan": {"required": ["price"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "price": {"title": "Price", "type": "string", "format": "decimal"}, "services": {"title": "Services", "type": "object"}, "duration": {"title": "Duration", "description": "Duration in days", "type": "integer", "maximum": 2147483647, "minimum": 0}}}, "Subscribe": {"required": ["plan"], "type": "object", "properties": {"plan": {"title": "Plan", "type": "integer"}, "activated_at": {"title": "Activated at", "type": "string", "format": "date", "readOnly": true}, "expire_at": {"title": "Expire at", "type": "string", "format": "date", "readOnly": true}, "remaining_days": {"title": "Remaining days", "type": "integer", "readOnly": true}, "remaining_credits": {"title": "Remaining credits", "type": "object", "readOnly": true}}}, "QuranPart": {"required": ["index", "start_at", "end_at"], "type": "object", "properties": {"index": {"title": "Index", "type": "integer", "maximum": 2147483647, "minimum": 0}, "start_at": {"title": "Start at", "type": "integer", "maximum": 2147483647, "minimum": 0}, "end_at": {"title": "End at", "type": "integer", "maximum": 2147483647, "minimum": 0}}}, "QuranSuraTranslation": {"required": ["text"], "type": "object", "properties": {"sura_id": {"title": "Sura id", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string", "minLength": 1}}}, "QuranSura": {"required": ["index", "name", "verse_count", "nozul_type", "start_at", "end_at"], "type": "object", "properties": {"index": {"title": "Index", "type": "integer", "maximum": 2147483647, "minimum": 0}, "name": {"title": "Name", "type": "string", "maxLength": 192, "minLength": 1}, "similar_names": {"title": "Similar Names", "type": "object", "x-nullable": true}, "verse_count": {"title": "Verse count", "type": "integer", "maximum": 2147483647, "minimum": 0}, "nozul_type": {"title": "Nozul type", "type": "string", "enum": ["Meccan", "Medinan"]}, "start_at": {"title": "Start at", "type": "integer", "maximum": 2147483647, "minimum": 0}, "end_at": {"title": "End at", "type": "integer", "maximum": 2147483647, "minimum": 0}}}, "QuranTranslators": {"required": ["translator", "language_code"], "type": "object", "properties": {"translator": {"title": "Translator", "type": "string", "maxLength": 192, "minLength": 1}, "translator_en": {"title": "Translator en", "type": "string", "maxLength": 192, "minLength": 1, "x-nullable": true}, "language_code": {"title": "Language code", "type": "string", "maxLength": 2, "minLength": 1}}}, "QuranVerseLocalization": {"required": ["text"], "type": "object", "properties": {"verse_id": {"title": "Verse id", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string", "minLength": 1}}}, "QuranVerseTranslation": {"required": ["text"], "type": "object", "properties": {"verse_id": {"title": "Verse id", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string", "minLength": 1}}}, "QuranVerse": {"required": ["index", "number_in_surah", "juz", "text"], "type": "object", "properties": {"index": {"title": "Index", "type": "integer", "maximum": 2147483647, "minimum": 0}, "sura_id": {"title": "Sura id", "type": "string", "readOnly": true}, "number_in_surah": {"title": "Number in surah", "type": "integer", "maximum": 2147483647, "minimum": 0}, "juz": {"title": "Juz", "type": "integer", "maximum": 2147483647, "minimum": 0}, "text": {"title": "Text", "type": "string", "minLength": 1}, "glyph_text": {"title": "Glyph text", "type": "string", "maxLength": 500, "x-nullable": true}, "raw_text": {"title": "Raw text", "type": "string", "x-nullable": true}, "new_line_at": {"title": "New line at", "type": "string", "maxLength": 255, "x-nullable": true}}}, "QuranWordTranslation": {"required": ["verse", "arabic", "translate", "language_code"], "type": "object", "properties": {"verse": {"title": "Verse", "type": "integer"}, "arabic": {"title": "Arabic word", "type": "string", "maxLength": 255, "minLength": 1}, "translate": {"title": "Translate", "type": "string", "maxLength": 255, "minLength": 1}, "language_code": {"title": "Language code", "type": "string", "minLength": 1}}}, "Adhan": {"required": ["name"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 64, "minLength": 1}, "description": {"title": "Description", "description": "could be null", "type": "string", "maxLength": 255, "x-nullable": true}, "file_path": {"title": "File path", "type": "string", "readOnly": true}}}, "Reminder": {"required": ["service_name", "object_id", "text"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "service_name": {"title": "Service Name", "description": "Name of the service (e.g., \"meet\", \"dua\", etc.)", "type": "string", "maxLength": 100, "minLength": 1}, "object_id": {"title": "Object ID", "description": "ID of the related object (meet ID, dua ID, etc.)", "type": "string", "maxLength": 100, "minLength": 1}, "text": {"title": "Reminder Text", "description": "The reminder message content", "type": "string", "minLength": 1}, "created_at": {"title": "Created At", "description": "When the reminder was created", "type": "string", "format": "date-time", "readOnly": true}, "call_time": {"title": "Call Time", "description": "When the reminder should be triggered/called", "type": "string", "format": "date-time", "x-nullable": true}, "is_sent": {"title": "Is Sent", "description": "Whether the reminder has been sent", "type": "boolean"}, "is_read": {"title": "Is Read", "description": "Whether the user has opened/read the reminder", "type": "boolean"}, "status": {"title": "Status", "description": "General status management for the reminder", "type": "boolean"}}}, "ReminderUpdate": {"type": "object", "properties": {"is_sent": {"title": "Is Sent", "description": "Whether the reminder has been sent", "type": "boolean"}, "is_read": {"title": "Is Read", "description": "Whether the user has opened/read the reminder", "type": "boolean"}, "status": {"title": "Status", "description": "General status management for the reminder", "type": "boolean"}}}, "Report": {"required": ["service_slug", "text"], "type": "object", "properties": {"service_slug": {"title": "Service slug", "type": "string", "enum": ["hussainiyah", "quran", "mafatih", "qiblah", "ahkam", "calendar", "talk", "meet", "library", "hadis", "habit", "checkup", "marriage"]}, "subject": {"title": "Subject", "type": "integer", "x-nullable": true}, "description": {"title": "Description", "type": "string", "x-nullable": true}, "text": {"title": "Report Text", "type": "string", "maxLength": 255, "minLength": 1}, "object_id": {"title": "Object id", "type": "integer", "maximum": 9223372036854775807, "minimum": 0, "x-nullable": true}}}, "Subject": {"required": ["name", "slug"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "maxLength": 255, "minLength": 1}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "maxLength": 50, "minLength": 1}, "service": {"title": "Service", "type": "string", "readOnly": true}}}, "ServiceVersion": {"required": ["version_number", "language"], "type": "object", "properties": {"service": {"title": "Service", "type": "string", "readOnly": true}, "version_number": {"title": "Version Number", "description": "Version number in format 1.3", "type": "string", "maxLength": 20, "minLength": 1}, "language": {"$ref": "#/definitions/Language"}, "is_active": {"title": "Is active", "type": "string", "readOnly": true}, "service_config": {"title": "Service config", "type": "string", "readOnly": true}, "created_at": {"title": "Created At", "type": "string", "format": "date-time", "readOnly": true}, "app_intros": {"title": "App intros", "type": "string", "readOnly": true}, "service_intros": {"title": "Service intros", "type": "string", "readOnly": true}}}, "ShareApp": {"required": ["description"], "type": "object", "properties": {"description": {"title": "Description", "type": "string", "minLength": 1}, "image": {"title": "Image", "type": "string", "readOnly": true}}}, "TafsirVerses": {"required": ["from_verse", "to_verse", "text"], "type": "object", "properties": {"from_verse": {"title": "From verse", "type": "integer", "maximum": 2147483647, "minimum": 0}, "to_verse": {"title": "To verse", "type": "integer", "maximum": 2147483647, "minimum": 0}, "text": {"title": "Text", "type": "string", "minLength": 1}, "surah": {"title": "Surah", "type": "string", "readOnly": true}, "book": {"title": "Book", "type": "string", "readOnly": true}, "ayahs_index": {"title": "Ayahs index", "type": "string", "readOnly": true}}}, "TafsirBook": {"required": ["title"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "maxLength": 112, "minLength": 1}, "surahs": {"title": "Surahs", "type": "string", "readOnly": true}}}, "Transaction": {"required": ["coin_count"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "coin_count": {"title": "Coin count", "type": "integer", "maximum": 2147483647, "minimum": 0}, "description": {"title": "Description", "type": "string", "readOnly": true}, "service": {"title": "Service", "type": "string", "enum": ["hussainiya", "library", "talk", "meet"], "x-nullable": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}}}, "WithdrawalRequest": {"required": ["amount", "status"], "type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "amount": {"title": "Amount", "type": "string", "format": "decimal"}, "status": {"title": "Status", "type": "string", "enum": ["pending", "completed", "failed"]}, "description": {"title": "Description", "type": "string", "maxLength": 255, "x-nullable": true}, "created_at": {"title": "Created at", "type": "string", "format": "date-time", "readOnly": true}, "updated_at": {"title": "Updated at", "type": "string", "format": "date-time", "readOnly": true}}}, "DuaCompleteSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "parts": {"title": "Parts", "type": "string", "readOnly": true}, "total_parts": {"title": "Total parts", "type": "string", "readOnly": true}, "seo_field": {"title": "Seo field", "type": "string", "readOnly": true}, "synced_at": {"title": "Synced at", "type": "string", "readOnly": true}}}, "Web_DuaCategoriesSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "readOnly": true}, "thumbnails": {"title": "Thumbnails", "type": "string", "readOnly": true}, "language": {"title": "Language", "type": "string", "readOnly": true}, "children": {"title": "Children", "type": "string", "readOnly": true}}}, "Web_DuaSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "title": {"title": "Title", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "readOnly": true}, "not_synced": {"title": "Not synced", "type": "boolean", "default": false}, "seo_field": {"title": "Seo field", "type": "string", "readOnly": true}}}, "Web_DuaPartSerializer": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "dua_part_index": {"title": "Dua part index", "type": "string", "readOnly": true}, "text": {"title": "Text", "type": "string", "x-nullable": true}, "translation": {"title": "Translation", "type": "string", "readOnly": true}, "local_alpha": {"title": "Local alpha", "type": "string", "readOnly": true}, "mafatih_dua_id": {"title": "Mafatih dua id", "type": "string", "readOnly": true}, "description": {"title": "Description", "type": "string", "readOnly": true}}}, "WebDuaAudio": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "reciter": {"title": "Reciter", "type": "string", "readOnly": true}, "audio": {"title": "Audio", "type": "string", "readOnly": true}, "audio_sync_data": {"title": "Audio sync data", "type": "object"}}}, "DuaReciter": {"type": "object", "properties": {"id": {"title": "ID", "type": "integer", "readOnly": true}, "name": {"title": "Name", "type": "string", "readOnly": true}, "slug": {"title": "Slug", "type": "string", "format": "slug", "pattern": "^[-a-zA-Z0-9_]+$", "maxLength": 120}, "avatar": {"title": "Avatar", "type": "string", "readOnly": true}}}, "QuranSurahDetailVerse": {"required": ["index", "number_in_surah", "juz", "text"], "type": "object", "properties": {"index": {"title": "Index", "type": "integer", "maximum": 2147483647, "minimum": 0}, "sura_id": {"title": "Sura id", "type": "string", "readOnly": true}, "number_in_surah": {"title": "Number in surah", "type": "integer", "maximum": 2147483647, "minimum": 0}, "juz": {"title": "Juz", "type": "integer", "maximum": 2147483647, "minimum": 0}, "text": {"title": "Text", "type": "string", "minLength": 1}, "glyph_text": {"title": "Glyph text", "type": "string", "maxLength": 500, "x-nullable": true}, "raw_text": {"title": "Raw text", "type": "string", "x-nullable": true}, "new_line_at": {"title": "New line at", "type": "string", "maxLength": 255, "x-nullable": true}, "text_translation": {"title": "Text translation", "type": "string", "readOnly": true}}}}} \ No newline at end of file +{ + "swagger": "2.0", + "info": { + "title": "Snippets API", + "description": "Project API Documentation", + "termsOfService": "https://www.google.com/policies/terms/", + "contact": { "email": "nwhco.com" }, + "license": { "name": "BSD License" }, + "version": "v1" + }, + "host": "habibapp.com", + "schemes": ["https"], + "basePath": "/", + "consumes": ["application/json"], + "produces": ["application/json"], + "securityDefinitions": { "Basic": { "type": "basic" } }, + "security": [{ "Basic": [] }], + "paths": { + "/about-service/": { + "get": { + "operationId": "about-service_list", + "description": "-- params: service", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "service", + "in": "query", + "description": "Service type to filter by", + "type": "string", + "enum": [ + "main", + "hussainiyah", + "quran", + "mafatih", + "qiblah", + "ahkam", + "calendar", + "talk", + "meet", + "library", + "hadis", + "account" + ] + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/AboutService" } + } + } + } + } + }, + "tags": ["about-service"] + }, + "parameters": [] + }, + "/account/activity/create/": { + "post": { + "operationId": "account_activity_create_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Activity" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/Activity" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/apple/": { + "post": { + "operationId": "account_auth_apple_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/AppleAuth" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/AppleAuth" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/google/": { + "post": { + "operationId": "account_auth_google_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GoogleAuth" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/GoogleAuth" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/guest/": { + "post": { + "operationId": "account_auth_guest_create", + "description": "\n### Guest Authentication API\n\nThis API is invoked during the app's intro phase to authenticate guest users. It collects device information\nand performs authentication based on the provided data. \n\n| **Field** | **Type** | **Required** | **Description** |\n|---------------------|------------|--------------|----------------------------------------|\n| `auth_method` | String | No | phone or third_party |\n| `country_code` | int | No | phone country code |\n\n#### Response:\n- **200 OK**: Returns `token`, `auth_method`, and `country_code`.\n- **400 Bad Request**: Input validation failed.\n- **500 Internal Server Error**: Unexpected error.\n\n#### Example Response:\n\n```json\n{\n \"token\": \"1e126d575f3e37d5f8f0fd5a893fae90a7511c25\",\n \"auth_method\": \"phone\",\n \"country_code\": 964\n},\n{\n \"token\": \"1e126d575f3e37d5f8f0fd5a893fae90a7511c25\",\n \"auth_method\": \"third_party\",\n \"country_code\": 964\n}\n```\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GuestUser" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/GuestUser" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/logout/": { + "post": { + "operationId": "account_auth_logout_create", + "description": "\n### User Logout API\n\nThis API endpoint allows authenticated users to securely log out from the application. The logout process\nclears the user's FCM (Firebase Cloud Messaging) token to ensure they no longer receive push notifications\non the logged-out device.\n\n#### Key Features:\n- **Authentication Required**: Only authenticated users can access this endpoint\n- **FCM Token Clearing**: Automatically clears the user's FCM token to stop push notifications\n- **Secure Logout**: Provides a clean logout process following REST API best practices\n- **Error Handling**: Comprehensive error handling with appropriate HTTP status codes\n\n#### Business Logic:\n1. **Authentication Check**: Verifies that the user is properly authenticated via token\n2. **FCM Token Cleanup**: Sets the user's FCM token field to null/empty\n3. **Database Update**: Saves the user record with the cleared FCM token\n4. **Response Generation**: Returns appropriate success or error response\n\n#### Authentication:\n- **Required**: Yes\n- **Method**: Token-based authentication\n- **Header**: `Authorization: Token `\n\n#### HTTP Method:\n- **POST**: Used for logout action (following REST conventions for state-changing operations)\n\n#### Request Headers:\n| **Header** | **Type** | **Required** | **Description** |\n|-------------------|------------|--------------|-----------------------------------|\n| `Authorization` | String | Yes | Token |\n| `Content-Type` | String | Yes | application/json |\n\n#### Response Codes:\n- **200 OK**: Logout successful, FCM token cleared\n- **401 Unauthorized**: Authentication credentials not provided or invalid\n- **500 Internal Server Error**: Unexpected server error during logout\n\n#### Success Response Example:\n```json\n{\n \"status\": \"success\",\n \"message\": \"Logged out successfully\"\n}\n```\n\n#### Error Response Examples:\n\n**401 Unauthorized:**\n```json\n{\n \"detail\": \"Authentication credentials were not provided.\"\n}\n```\n\n**500 Internal Server Error:**\n```json\n{\n \"status\": \"error\",\n \"message\": \"An error occurred during logout\"\n}\n```\n\n#### Usage Example:\n```bash\ncurl -X POST https://api.example.com/auth/logout/ \\\n -H \"Authorization: Token 516e059d2a6b31d74b6a9e4c8f98fe4e8413efbc\" \\\n -H \"Content-Type: application/json\"\n```\n\n#### Security Considerations:\n- The FCM token is immediately cleared to prevent unauthorized push notifications\n- The authentication token remains valid until explicitly deleted or expired\n- Users should clear local storage/cache on the client side after successful logout\n- Consider implementing token blacklisting for enhanced security if needed\n\n#### Integration Notes:\n- After successful logout, clients should redirect users to the login screen\n- Clear any locally stored user data and authentication tokens\n- Stop any background services that depend on user authentication\n- Update UI state to reflect the logged-out status\n", + "parameters": [], + "responses": { + "200": { + "description": "Logout successful", + "examples": { + "application/json": { + "status": "success", + "message": "Logged out successfully" + } + } + }, + "401": { + "description": "Authentication required", + "examples": { + "application/json": { + "detail": "Authentication credentials were not provided." + } + } + }, + "500": { + "description": "Internal server error", + "examples": { + "application/json": { + "status": "error", + "message": "An error occurred during logout" + } + } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/phone/": { + "post": { + "operationId": "account_auth_phone_create", + "description": "\n### Phone Authentication API\n\nThis API allows users to authenticate by providing a phone number. A one-time password (OTP) is sent to the\nuser via the specified method, and the response indicates whether the OTP was successfully sent.\n\n#### Response:\n- **200 OK**: Returns user ID, phone number, verification method, OTP send status, and time limit for resending the OTP.\n- **400 Bad Request**: Input validation failed.\n- **500 Internal Server Error**: Unexpected error occurred.\n\n#### Output Fields:\n\n| **Field** | **Type** | **Description** |\n|---------------------------|------------|----------------------------------------------------------|\n| `user_id` | String | Unique identifier of the authenticated user. |\n| `phone_number` | String | The phone number used for authentication. |\n| `verification_method` | String | Method used to send the OTP (e.g., \"SMS\" or \"WHATSAPP\").|\n| `verification_time_limit` | Integer | Time (in minutes) until the OTP can be resent. |\n| `is_send` | Boolean | Indicates whether the OTP was successfully sent. |\n\n#### Example Response:\n\n```json\n{\n \"user_id\": \"1a2b3c4d\",\n \"phone_number\": \"+1234567890\",\n \"verification_method\": \"WHATSAPP\",\n \"verification_time_limit\": 5,\n \"is_send\": true\n}\n```\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/PhoneAuth" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/PhoneAuth" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/staff/login/": { + "post": { + "operationId": "account_auth_staff_login_create", + "summary": "Email/password login for staff, admin and superuser accounts.", + "description": "Returns a DRF auth token (the same token type used everywhere else in the\nproject, see ``TokenAuthentication2``) so the dashboard can authenticate\nsubsequent requests with ``Authorization: Token ``.\n\nOpen to anonymous callers (``AllowAny``) — the staff check happens inside\nthe serializer; only an account with ``is_staff``/``is_superuser`` and a\ncorrect password gets a token back.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["email", "password"], + "type": "object", + "properties": { + "email": { "type": "string", "format": "email" }, + "password": { "type": "string", "format": "password" } + } + } + } + ], + "responses": { + "200": { + "description": "Authenticated", + "schema": { + "type": "object", + "properties": { + "token": { "type": "string" }, + "user_id": { "type": "integer" }, + "email": { "type": "string" }, + "name": { "type": "string" }, + "is_staff": { "type": "boolean" }, + "is_superuser": { "type": "boolean" } + } + } + }, + "400": { "description": "Invalid credentials or not a staff account" } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/user/me/": { + "get": { + "operationId": "account_auth_user_me_list", + "description": "این متد اطلاعات کاربر را برمی‌گرداند", + "parameters": [], + "responses": { + "200": { + "description": "اطلاعات کاربر", + "examples": { + "application/json": { + "user_id": "ایدی کاربر", + "name": "نام کاربر", + "email": "ایمیل کاربر", + "avatar": "آدرس آواتار", + "country": "کشور", + "city": "شهر", + "phone_number": "شماره تلفن", + "possible_phone_number": "شماره تماس احتمالی کاربر", + "is_phone_number_verified": "شماره تماس تایید شده باشد", + "date_joined": "تاریخ عضویت", + "publisher_in": "اطلاعات ناشر", + "settings": "تنظیمات کاربر", + "provider": "اطلاعات ارائه‌دهنده", + "coin_balance": "موجودی کوین ها", + "balance_in_dollars": "مقدار دلار کاربر (اگر پرووایدر نباشد خالی است)", + "notification_count": "تعداد نوتیفیکیشن‌ها", + "bucket_services": "لیست سرویس باکت های کاربر" + } + } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/user/merge/": { + "post": { + "operationId": "account_auth_user_merge_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MergeAccount" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/MergeAccount" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/user/merge/phone/info/": { + "get": { + "operationId": "account_auth_user_merge_phone_info_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/user/merge/phone/verify/": { + "post": { + "operationId": "account_auth_user_merge_phone_verify_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MergeVerify" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/MergeVerify" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/user/profile/update/": { + "put": { + "operationId": "account_auth_user_profile_update_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserProfile" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserProfile" } + } + }, + "tags": ["account"] + }, + "patch": { + "operationId": "account_auth_user_profile_update_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserProfile" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserProfile" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/user/region/": { + "get": { + "operationId": "account_auth_user_region_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/verify/": { + "post": { + "operationId": "account_auth_verify_create", + "description": "\n### Phone Verification Logic\n\nThe phone verification process ensures user authenticity through a one-time verification code. Below is the streamlined flow:\n\n1. **Input Validation **:\n - Accepts `user_id`, `phone_number`, and a 5-digit `code`.\n - Validates input and raises errors for missing or invalid data.\n\n2. **User Retrieval**:\n - Fetch the user using `user_id`.\n - Raise an error if the user does not exist.\n\n3. **Verification Data Fetch**:\n - Retrieve the verification data from Redis using `phone_number`.\n - Raise an error if data is missing or expired.\n\n4. **Code Comparison**:\n - Compare the provided `code` with the one in Redis.\n - Raise an error for mismatched codes.\n\n5. **User Update**:\n - On success, update the user's `phone_number` and mark them as verified.\n\n6. **Response Generation**:\n - Return an authentication token along with user profile details (e.g., name, email, location, settings).\n\n#### Failure Scenarios:\n- Errors are raised for invalid input, missing verification data, or incorrect codes.\n\nThis process ensures secure and efficient phone verification.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/PhoneVerify" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/PhoneVerify" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/auth/{device_id}/update/": { + "put": { + "operationId": "account_auth_update_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GuestUser" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/GuestUser" } + } + }, + "tags": ["account"] + }, + "patch": { + "operationId": "account_auth_update_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GuestUser" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/GuestUser" } + } + }, + "tags": ["account"] + }, + "parameters": [ + { + "name": "device_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/account/bucket/update/": { + "get": { + "operationId": "account_bucket_update_list", + "description": "Remove a service from user's bucket services", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "service", + "in": "query", + "description": "Service name to remove from bucket services", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Service removed successfully from bucket services", + "examples": { + "application/json": { "message": "Successfully updated" } + } + }, + "400": { "description": "Bad request" }, + "401": { + "description": "Authentication credentials were not provided" + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/delete-account/": { + "post": { + "operationId": "account_delete-account_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/geolocation/": { + "get": { + "operationId": "account_geolocation_list", + "description": "Get geolocation information based on the client's IP address", + "parameters": [], + "responses": { + "200": { + "description": "Geolocation information", + "schema": { "$ref": "#/definitions/IPGeolocation" } + }, + "404": { + "description": "IP address not found in database or database not available" + }, + "500": { "description": "Internal server error" } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/geolocation/coordinates/": { + "get": { + "operationId": "account_geolocation_coordinates_list", + "description": "Get location information (city, country) based on geographic coordinates using reverse geocoding", + "parameters": [ + { + "name": "lat", + "in": "query", + "description": "Latitude coordinate (-90 to 90)", + "required": true, + "type": "number" + }, + { + "name": "lon", + "in": "query", + "description": "Longitude coordinate (-180 to 180)", + "required": true, + "type": "number" + } + ], + "responses": { + "200": { + "description": "Location information", + "schema": { "$ref": "#/definitions/ReverseGeolocationResponse" } + }, + "400": { "description": "Invalid or missing coordinates" }, + "404": { + "description": "No location found for the given coordinates" + }, + "500": { "description": "Internal server error" } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/location-update/": { + "post": { + "operationId": "account_location-update_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/LocationHistory" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/LocationHistory" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/notif-list/": { + "get": { + "operationId": "account_notif-list_list", + "description": "### Example JSON Response:\n```json\n{\n \"count\": 36,\n \"next\": \"https://habibapp.com/account/notif-list/?limit=16&offset=16\",\n \"previous\": null,\n \"results\": [\n {\n \"id\": 126753,\n \"service\": \"mafatih\",\n \"title\": \"اللهم عجل لولیک الفرج\",\n \"message\": \"خواهر یا اخوان،\",\n \"data\": \"4450\",\n \"image\": null,\n \"is_read\": true,\n \"created_at\": \"2024-10-06T14:39:32.893330\"\n }\n ]\n}\n```", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "service", + "in": "query", + "description": "Specify the service to filter messages (optional).", + "required": false, + "type": "string", + "enum": [ + "hussainiya", + "library", + "talk", + "meet", + "mafatih", + "hadis", + "khatm", + "quran", + "tafsir", + "ahkam", + "coin", + "global" + ] + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/UserNotification" } + } + } + } + } + }, + "tags": ["notification"] + }, + "parameters": [] + }, + "/account/provider/requests/": { + "get": { + "operationId": "account_provider_requests_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Provider" } + } + } + } + } + }, + "tags": ["account"] + }, + "post": { + "operationId": "account_provider_requests_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Provider" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/Provider" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/account/read-all-notif/": { + "get": { + "operationId": "account_read-all-notif_list", + "description": "", + "parameters": [ + { + "name": "service", + "in": "query", + "description": "Specify the service to filter messages (optional). If omitted, all messages for the user will be marked as read.", + "required": false, + "type": "string", + "enum": [ + "hussainiya", + "library", + "talk", + "meet", + "mafatih", + "hadis", + "khatm", + "quran", + "tafsir", + "ahkam", + "coin", + "global", + "null" + ] + }, + { + "name": "value_id", + "in": "query", + "description": "value_id optional parameter to mark a specific message as read.(value id notificaiton)", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { "description": "Messages marked as read" }, + "400": { "description": "Service parameter is required" } + }, + "tags": ["notification"] + }, + "parameters": [] + }, + "/account/send-notification/": { + "post": { + "operationId": "account_send-notification_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "description": "Send notification to authenticated user with flexible payload options:\n\n 1. Regular notification: Provide title and message\n 2. Data-only notification: Omit title and message, provide data_notif\n 3. Custom payload: Set use_custom_payload=true to send data_notif keys directly in Firebase payload\n\n When use_custom_payload=true, you can test full FCM payload structure including Android-specific configurations.", + "required": [], + "type": "object", + "properties": { + "title": { + "description": "Notification title (optional - if both title and message are omitted, sends data-only notification)", + "type": "string" + }, + "message": { + "description": "Notification message (optional - if both title and message are omitted, sends data-only notification)", + "type": "string" + }, + "data_notif": { + "description": "Additional data to send with notification (can be object or JSON string)", + "type": "object" + }, + "use_custom_payload": { + "description": "If true, all keys from data_notif will be placed directly in the Firebase payload message object", + "type": "boolean", + "default": false + } + } + } + } + ], + "responses": { + "200": { + "description": "Notification sent successfully", + "schema": { + "type": "object", + "properties": { + "result": { + "description": "FCM response result", + "type": "array", + "items": { "type": "object" } + } + } + } + }, + "400": { "description": "Bad request - invalid data_notif format" }, + "404": { "description": "User not found" } + }, + "tags": ["notification"] + }, + "parameters": [] + }, + "/account/settings/": { + "put": { + "operationId": "account_settings_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserSettings" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserSettings" } + } + }, + "tags": ["account"] + }, + "patch": { + "operationId": "account_settings_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserSettings" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserSettings" } + } + }, + "tags": ["account"] + }, + "parameters": [] + }, + "/api/chat-producer/": { + "post": { + "operationId": "api_chat-producer_create", + "description": "API producer for chat application", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["Talk"] + }, + "parameters": [] + }, + "/api/crm/reviews/": { + "get": { + "operationId": "api_crm_reviews_list", + "description": "", + "parameters": [ + { + "name": "platform", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "needs_human_intervention", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "review_status", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "ordering", + "in": "query", + "description": "Which field to use when ordering the results.", + "required": false, + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ReviewList" } + } + } + } + } + }, + "tags": ["api"] + }, + "post": { + "operationId": "api_crm_reviews_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + }, + "tags": ["api"] + }, + "parameters": [] + }, + "/api/crm/reviews/{id}/": { + "get": { + "operationId": "api_crm_reviews_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + }, + "tags": ["api"] + }, + "put": { + "operationId": "api_crm_reviews_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + }, + "tags": ["api"] + }, + "patch": { + "operationId": "api_crm_reviews_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + }, + "tags": ["api"] + }, + "delete": { + "operationId": "api_crm_reviews_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["api"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/crm/reviews/{id}/edit_reply/": { + "patch": { + "operationId": "api_crm_reviews_edit_reply", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + }, + "tags": ["api"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/crm/reviews/{id}/reply/": { + "post": { + "operationId": "api_crm_reviews_reply", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/ReviewDetail" } + } + }, + "tags": ["api"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/marriage/cases/{case_id}/contact-info/": { + "get": { + "operationId": "api_marriage_cases_contact-info_list", + "description": "\nدریافت اطلاعات تماس خانم پس از پرداخت\n\nپس از تأیید پرداخت (وضعیت payment_done)، آقا می‌تواند اطلاعات تماس\nمجاز خانم را دریافت کند.\n\nشرایط دسترسی:\n - کاربر (آقا یا خانم) باید عضو این کیس باشد\n - وضعیت کیس باید دقیقاً payment_done باشد\n\nاطلاعات تماس قابل‌نمایش توسط ادمین از طریق فیلد female_contact_keys در کیس\nبرای هر کیس به‌صورت اختصاصی تنظیم می‌شود.\nمثال کلیدهای رایج: phone_father, phone_self, address\n\nخروجی: لیستی از فیلدهای فرم با کلید، برچسب، نوع و مقدار واقعی\n", + "parameters": [], + "responses": { + "200": { + "description": "ادمین هنوز هیچ کلید تماسی برای این کیس تنظیم نکرده", + "examples": { "application/json": { "contact_info": [] } } + }, + "403": { + "description": "دسترسی ندارید یا کیس هنوز payment_done نیست", + "examples": { + "application/json": { + "detail": "اطلاعات تماس فقط پس از تأیید پرداخت در دسترس است." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "کیس یافت نشد" } + }, + "tags": ["Marriage"] + }, + "parameters": [ + { "name": "case_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/marriage/cases/{case_id}/contact-status/": { + "post": { + "operationId": "api_marriage_cases_contact-status_create", + "description": "\nگزارش وضعیت تماس پس از دریافت اطلاعات — فقط توسط خانم\n\nخانم پس از دریافت اطلاعات تماس آقا (پس از payment_done) باید در مهلت ۴۸ ساعت\nوضعیت تماس را گزارش دهد. کنترل زمان ۴۸ ساعت در کلاینت انجام می‌شود.\n\nزمان اشتراک‌گذاری اطلاعات تماس از فیلد `contact_shared_at` در `active_case` قابل دسترسی است.\n\nپیش‌شرط:\n - فقط خانم می‌تواند این اندپوینت را فراخوانی کند\n - وضعیت کیس باید payment_done باشد\n\nمنطق:\n contacted →\n وضعیت کیس: payment_done → finalized\n هر دو پروفایل: in_case → matched\n reason_code و custom_note (اگر ارسال شده باشند) در CaseRejection ذخیره می‌شوند\n (کیس با موفقیت به نتیجه رسید)\n\n no_contact →\n جریمه time_suspend برای آقا ثبت می‌شود (۷ روز تعلیق)\n وضعیت کیس: payment_done → dismissed\n reason_code و custom_note در CaseRejection ذخیره می‌شوند\n پروفایل آقا: in_case → suspended (+ penalty_until تنظیم می‌شود)\n پروفایل خانم: in_case → waiting (آزاد برای کیس جدید)\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["action"], + "type": "object", + "properties": { + "action": { + "description": "contacted: آقا تماس گرفت | no_contact: آقا تماس نگرفت", + "type": "string", + "enum": ["contacted", "no_contact"] + }, + "reason_code": { + "description": "کد دلیل (اختیاری) — مثال: no_call_received, wrong_number", + "type": "string" + }, + "custom_note": { + "description": "توضیح اضافه (اختیاری)", + "type": "string" + } + }, + "example": { + "action": "no_contact", + "reason_code": "no_call_received", + "custom_note": "48 ساعت گذشته ولی تماسی نگرفت" + } + } + } + ], + "responses": { + "200": { + "description": "وضعیت تماس ثبت شد — حالت no_contact (جریمه اعمال شد، status در database dismissed است اما در response male_accepted نمایش داده می‌شود)", + "examples": { + "application/json": { + "detail": "عدم تماس ثبت شد. جریمه اعمال گردید.", + "case": { + "id": 15, + "status": "male_accepted", + "introduced_at": "2026-04-20T08:30:00Z", + "male_responded_at": "2026-04-20T10:15:00Z", + "female_responded_at": "2026-04-21T09:00:00Z", + "payment_done_at": "2026-04-21T09:00:00Z", + "contact_shared_at": "2026-04-21T09:00:00Z" + } + } + } + }, + "400": { + "description": "وضعیت کیس برای این عملیات مناسب نیست", + "examples": { + "application/json": { + "detail": "وضعیت کیس برای این عملیات مناسب نیست." + } + } + }, + "403": { + "description": "فقط خانم می‌تواند این عملیات را انجام دهد", + "examples": { + "application/json": { + "detail": "فقط خانم می‌تواند وضعیت تماس را گزارش دهد." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "کیس یافت نشد" } + }, + "tags": ["Marriage"] + }, + "parameters": [ + { "name": "case_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/marriage/cases/{case_id}/respond/": { + "post": { + "operationId": "api_marriage_cases_respond_create", + "description": "\nپاسخ به کیس معرفی (تأیید یا رد)\n\nآقا یا خانم می‌توانند کیس پیشنهادی را تأیید یا رد کنند.\n\nمنطق انتقال وضعیت:\n\nآقا (وقتی کیس در introduced است):\n accept → male_accepted (اطلاعات عمومی خانم برای آقا قابل مشاهده می‌شود)\n reject → male_rejected (هر دو پروفایل به waiting برمی‌گردند)\n\nخانم (وقتی کیس در male_accepted است):\n accept →\n اگر آقا اشتراک معتبر دارد: payment_done (مستقیم — consume_usage فراخوانی می‌شود)\n اگر آقا اشتراک ندارد: payment_pending (نیاز به خرید اشتراک)\n **توجه:** در response، status به `male_accepted` تبدیل می‌شود و جزئیات پرداخت از `needs_subscription` مشخص می‌شود\n reject → female_rejected (هر دو پروفایل به waiting برمی‌گردند)\n\nreason_code: کدهای هاردکد‌شده در فرانت‌اند — مثال: not_matched_financially, changed_mind\ncustom_note: توضیح اضافه اختیاری\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["action"], + "type": "object", + "properties": { + "action": { + "description": "تأیید یا رد کیس", + "type": "string", + "enum": ["accept", "reject"] + }, + "reason_code": { + "description": "کد دلیل رد (اختیاری) — مثال: not_matched_financially", + "type": "string", + "default": "" + }, + "custom_note": { + "description": "توضیح اضافه (اختیاری)", + "type": "string", + "default": "" + } + }, + "example": { + "action": "reject", + "reason_code": "not_matched_financially", + "custom_note": "از نظر مالی تناسب نداشتیم" + } + } + } + ], + "responses": { + "200": { + "description": "آقا تأیید کرد و خانم هم تأیید کرد — در database به payment_done می‌رود اما در response male_accepted نمایش داده می‌شود", + "examples": { + "application/json": { + "detail": "پاسخ شما با موفقیت ثبت شد.", + "case": { + "id": 15, + "status": "male_accepted", + "introduced_at": "2026-04-20T08:30:00Z", + "male_responded_at": "2026-04-20T10:15:00Z", + "female_responded_at": "2026-04-21T09:00:00Z", + "payment_done_at": "2026-04-21T09:00:00Z", + "contact_shared_at": "2026-04-21T09:00:00Z" + } + } + } + }, + "400": { + "description": "وضعیت کیس برای این عملیات مناسب نیست", + "examples": { + "application/json": { + "detail": "وضعیت کیس برای این عملیات مناسب نیست." + } + } + }, + "403": { + "description": "کاربر عضو این کیس نیست", + "examples": { + "application/json": { "detail": "شما به این کیس دسترسی ندارید." } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "کیس یافت نشد" } + }, + "tags": ["Marriage"] + }, + "parameters": [ + { "name": "case_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/marriage/match/start/": { + "post": { + "operationId": "api_marriage_match_start_create", + "description": "\nورود به صف مچینگ\n\nپس از تکمیل تمام محورهای اجباری، کاربر می‌تواند وارد صف انتظار شود\nتا سیستم برایش یک کیس مناسب پیدا کند.\n\nپیش‌شرط‌ها:\n ۱. وضعیت پروفایل باید pending_info باشد\n ۲. کاربر نباید معلق (suspended) باشد\n ۳. تمام محورهای is_required=True باید current_step >= total_steps داشته باشند\n\nپس از موفقیت:\n وضعیت پروفایل از pending_info به waiting تغییر می‌کند.\n ویرایش فرم‌ها قفل می‌شود (can_edit_profile = False).\n", + "parameters": [], + "responses": { + "200": { + "description": "با موفقیت وارد صف مچینگ شدید", + "examples": { + "application/json": { "detail": "با موفقیت وارد صف مچینگ شدید." } + } + }, + "400": { + "description": "خطا — پروفایل ناقص یا وضعیت نامناسب", + "examples": { + "application/json": { + "detail": "لطفاً ابتدا تمام محورهای اجباری را تکمیل کنید." + } + } + }, + "403": { + "description": "کاربر معلق است", + "examples": { + "application/json": { + "detail": "حساب شما معلق است و امکان ورود به صف مچینگ را ندارید." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" } + }, + "tags": ["Marriage"] + }, + "parameters": [] + }, + "/api/marriage/profile/basic/": { + "patch": { + "operationId": "api_marriage_profile_basic_partial_update", + "description": "\nثبت اطلاعات پایه پروفایل (آنبوردینگ)\n\nاولین قدم پس از ورود به سیستم مریج.\nجنسیت و نوع ثبت‌نام کاربر ثبت می‌شود.\n\nمنطق انتقال وضعیت:\n pending_onboarding → pending_info (وقتی هر دو فیلد پر شوند)\n\nis_registering_for_self:\n - True: کاربر برای خودش ثبت‌نام می‌کند\n - False: کاربر برای شخص دیگری (مثلاً خواهر) ثبت‌نام می‌کند\n این مقدار روی کدام محورهای فرم نمایش داده شوند تأثیر مستقیم دارد.\n\nخروجی: پروفایل آپدیت‌شده (همان فرمت GET /profile/main/)\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["gender", "is_registering_for_self"], + "type": "object", + "properties": { + "gender": { + "description": "جنسیت کاربر", + "type": "string", + "enum": ["male", "female"] + }, + "is_registering_for_self": { + "description": "True = برای خودش | False = برای شخص دیگر", + "type": "boolean" + } + }, + "example": { "gender": "male", "is_registering_for_self": true } + } + } + ], + "responses": { + "200": { + "description": "اطلاعات پایه با موفقیت ثبت شد", + "examples": { + "application/json": { + "id": 42, + "status": "pending_info", + "gender": "male", + "is_registering_for_self": true, + "can_edit_profile": true, + "can_message_expert": false, + "active_subscription": null, + "is_ready_for_match": false, + "active_case": null, + "needs_subscription": false, + "match_summary": null + } + } + }, + "400": { + "description": "خطا در اعتبارسنجی ورودی", + "examples": { + "application/json": { + "gender": ["مقدار وارد شده معتبر نیست."], + "is_registering_for_self": ["این فیلد الزامی است."] + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" } + }, + "tags": ["Marriage"] + }, + "parameters": [] + }, + "/api/marriage/profile/main/": { + "get": { + "operationId": "api_marriage_profile_main_list", + "description": "\n## دریافت وضعیت کامل پروفایل مریج\n\nاصلی‌ترین اندپوینت ماژول مریج. تمام اطلاعات لازم برای رندر صفحه اصلی را در یک درخواست برمی‌گرداند.\nاگر پروفایل وجود نداشته باشد، به‌صورت خودکار ساخته می‌شود.\n\n---\n\n### فیلدهای پاسخ\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `id` | integer | شناسه پروفایل |\n| `status` | string | وضعیت فعلی پروفایل (جدول وضعیت‌ها را ببینید) |\n| `gender` | string\\|null | جنسیت: `male` \\| `female` \\| `null` |\n| `is_registering_for_self` | boolean\\|null | `true` = برای خودش \\| `false` = برای شخص دیگر |\n| `can_edit_profile` | boolean | فقط در `pending_onboarding` / `pending_info` مجاز است |\n| `can_message_expert` | boolean | `true` اگر `in_case` باشد یا آقا اشتراک معتبر داشته باشد |\n| `active_subscription` | object\\|null | اشتراک فعال و معتبر — `null` اگر نداشته باشد |\n| `is_ready_for_match` | boolean | تمام فرم‌های `is_required=true` تکمیل شده‌اند |\n| `active_case` | object\\|null | اطلاعات کیس فعال — `null` اگر در کیس نباشد. شامل `my_action` و `other_action` |\n| `needs_subscription` | boolean | `true` فقط برای آقا در `payment_pending` بدون اشتراک معتبر. **توجه:** status های `payment_pending` و `payment_done` در response به `male_accepted` تبدیل می‌شوند و جزئیات پرداخت از این فیلد مشخص می‌شود |\n| `recommended_plan` | object\\|null | پلن پیشنهادی برای خرید اشتراک — همیشه اولین پلن فعال (کمترین order/price) |\n| `match_summary` | object\\|null | خلاصه عمومی پروفایل طرف مقابل — فقط در وضعیت‌های کیس فعال |\n\n---\n\n### جدول وضعیت‌های پروفایل (`status`)\n\n| مقدار | معنا |\n|-------|------|\n| `pending_onboarding` | هنوز جنسیت ثبت نشده |\n| `pending_info` | در حال تکمیل فرم‌ها |\n| `waiting` | در صف انتظار مچینگ |\n| `in_case` | در کیس فعال — ویرایش فرم‌ها قفل است |\n| `suspended` | معلق به دلیل جریمه (عدم تماس) |\n| `matched` | کیس به نتیجه رسیده |\n\n---\n\n### فیلد `active_case`\n\n| فیلد | نوع | توضیح |\n|------|-----|-------|\n| `case_id` | integer | شناسه کیس |\n| `status` | string | وضعیت کیس. **توجه:** `payment_pending` و `payment_done` در response به `male_accepted` تبدیل می‌شوند. جزئیات پرداخت از `needs_subscription` و `payment_done_at` مشخص می‌شود |\n| `introduced_at` | datetime | تاریخ معرفی |\n| `contact_shared_at` | datetime\\|null | تاریخ اشتراک‌گذاری اطلاعات تماس به آقا |\n| `minutes_since_contact_shared` | float\\|null | تعداد دقیقه‌های سپری شده از اشتراک‌گذاری — محاسبه شده توسط سرور |\n| `can_report_no_contact` | boolean | `true` اگر ۴۸ ساعت (۲۸۸۰ دقیقه) گذشته باشد — برای فعال‌سازی دکمه |\n| `my_action` | string | اقدام مورد نیاز از کاربر فعلی |\n| `other_action` | string | اقدام مورد نیاز از طرف مقابل |\n\n#### مقادیر `my_action` / `other_action`\n\n| مقدار | معنا |\n|-------|------|\n| `pending` | نوبت این طرف است که تأیید یا رد کند |\n| `waiting` | منتظر اقدام طرف مقابل |\n| `rejected` | این طرف رد کرده |\n| `other_rejected` | طرف مقابل رد کرده |\n| `payment_required` | آقا باید پرداخت کند |\n| `completed` | پرداخت انجام شده |\n\n---\n\n### فیلد `recommended_plan`\n\nوقتی `needs_subscription = true`، این فیلد اولین پلن فعال را برمی‌گرداند.\nکلاینت باید `id` این پلن را مستقیماً برای پرداخت استفاده کند (اندپوینت جداگانه‌ای برای لیست پلن‌ها وجود ندارد).\n\n```json\n{\n \"id\": 2,\n \"title\": \"اشتراک ۳ معرفی\",\n \"price\": \"150000\"\n}\n```\n\n---\n\n
\n💳 جریان پرداخت اشتراک از طریق habcoin (کلیک کنید)\n\nپس از دریافت `recommended_plan.id`، کلاینت باید درخواست پرداخت را به اندپوینت habcoin بزند:\n\n```\nGET /api/habcoin/pay/\n ?token=\n &service=marriagesubscriptionplan\n &object_id=\n```\n\n**جریان عملیات پس از فراخوانی:**\n\n1. habcoin سکه‌ها را از موجودی کاربر کسر می‌کند (FIFO — نزدیک‌ترین انقضا اول)\n2. رکورد `UserCoinUsage` با `service=marriagesubscriptionplan` ثبت می‌شود\n3. سیگنال `activate_marriage_subscription` به‌صورت خودکار اجرا می‌شود:\n - `ActiveSubscription` برای پروفایل آقا ساخته می‌شود\n - `consume_usage()` فراخوانی می‌شود\n - وضعیت کیس: `payment_pending` → `payment_done`\n - `payment_done_at` و `contact_shared_at` پر می‌شوند\n4. کلاینت می‌تواند اطلاعات تماس را از `GET /cases//contact-info/` دریافت کند\n\n**خطاهای احتمالی از habcoin/pay:**\n\n| کد | پیام | دلیل |\n|----|------|-------|\n| 400 | `Not enough coins` | موجودی سکه کافی نیست |\n| 400 | `Invalid service type` | پارامتر `service` اشتباه است |\n| 403 | `Invalid security token` | توکن امنیتی نامعتبر است |\n| 404 | `Object not found` | `plan_id` یافت نشد یا غیرفعال است |\n\n
\n", + "parameters": [], + "responses": { + "200": { + "description": "پروفایل با موفقیت بازگردانده شد", + "examples": { + "application/json": { + "id": 42, + "status": "in_case", + "gender": "male", + "is_registering_for_self": true, + "can_edit_profile": false, + "can_message_expert": true, + "active_subscription": { + "id": 7, + "plan": { + "id": 2, + "title": "اشتراک ۳ معرفی", + "plan_type": "count_based", + "duration_days": null, + "usage_limit": 3, + "price": "150000" + }, + "start_date": "2026-04-01T10:00:00Z", + "end_date": null, + "total_usages": 1, + "is_active": true, + "is_valid": true + }, + "is_ready_for_match": true, + "active_case": { + "case_id": 15, + "status": "male_accepted", + "introduced_at": "2026-04-20T08:30:00Z", + "contact_shared_at": "2026-04-22T14:15:00Z", + "minutes_since_contact_shared": 2760.5, + "can_report_no_contact": false, + "my_action": "completed", + "other_action": "completed" + }, + "needs_subscription": false, + "recommended_plan": { + "id": 2, + "title": "اشتراک ۳ معرفی", + "price": "150000" + }, + "match_summary": { + "id": 58, + "gender": "female", + "overall_completion_percent": 85.0, + "public_info": [ + { + "key": "birth_year", + "label": "سال تولد", + "type": "number", + "value": 1998 + }, + { + "key": "city", + "label": "شهر", + "type": "text", + "value": "تهران" + }, + { + "key": "education", + "label": "تحصیلات", + "type": "text", + "value": "کارشناسی" + }, + { + "key": "job", + "label": "شغل", + "type": "text", + "value": null + }, + { + "key": "height", + "label": "قد", + "type": "number", + "value": null + } + ] + } + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" } + }, + "tags": ["Marriage"] + }, + "parameters": [] + }, + "/api/marriage/sections/": { + "get": { + "operationId": "api_marriage_sections_list", + "description": "\nلیست محورهای اطلاعاتی فرم به همراه درصد پیشرفت\n\nمحورهایی که برای جنسیت و نوع ثبت‌نام کاربر فعال هستند را به همراه درصد پیشرفت هر کدام برمی‌گرداند.\nاین اندپوینت باید فقط زمانی که کاربر در صفحه «تکمیل پروفایل» است فراخوانی شود (وضعیت pending_info).\nاگر کاربر هنوز جنسیت یا نوع ثبت‌نام را وارد نکرده باشد، آرایه خالی برمی‌گرداند.\n", + "parameters": [], + "responses": { + "200": { + "description": "لیست محورها با موفقیت بازگردانده شد", + "examples": { + "application/json": [ + { + "id": 1, + "slug": "personal_info", + "title": "اطلاعات شخصی", + "is_required": true, + "importance_weight": 1.0, + "estimated_minutes": 10, + "total_steps": 3, + "order": 1, + "current_step": 3, + "completion_percent": 100.0 + }, + { + "id": 2, + "slug": "financial_info", + "title": "اطلاعات مالی", + "is_required": true, + "importance_weight": 1.5, + "estimated_minutes": 8, + "total_steps": 2, + "order": 2, + "current_step": 1, + "completion_percent": 50.0 + } + ] + } + }, + "401": { "description": "کاربر احراز هویت نشده است" } + }, + "tags": ["Marriage"] + }, + "parameters": [] + }, + "/api/marriage/sections/{slug}/data/": { + "get": { + "operationId": "api_marriage_sections_data_list", + "description": "\nدریافت دیتای ذخیره‌شده یک محور فرم\n\nدیتای پر‌شده توسط کاربر برای یک محور اطلاعاتی مشخص (با slug) را برمی‌گرداند.\nاگر کاربر هنوز این محور را شروع نکرده باشد، پاسخ با مقادیر پیش‌فرض برگردانده می‌شود.\n\nساختار فیلد data:\n آرایه‌ای از آبجکت‌ها، هر آبجکت شامل:\n - key: کلید یکتای فیلد (مثل \"birth_year\"، \"job\")\n - label: برچسب نمایشی (مثل \"سال تولد\")\n - type: نوع فیلد (text | number | media | select | ...)\n - value: مقدار وارد شده (برای media: URL فایل دائمی یا null)\n\ncompletion_percent = (current_step / total_steps) * 100\n", + "parameters": [], + "responses": { + "200": { + "description": "محور هنوز شروع نشده — مقادیر پیش‌فرض", + "examples": { + "application/json": { + "slug": "financial_info", + "data": [], + "current_step": 0, + "total_steps": 2, + "completion_percent": 0.0, + "updated_at": null + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { + "description": "محور اطلاعاتی با این slug یافت نشد یا غیرفعال است" + } + }, + "tags": ["Marriage"] + }, + "patch": { + "operationId": "api_marriage_sections_data_partial_update", + "description": "\nآپدیت جزئی دیتای یک محور فرم\n\nدیتای یک یا چند فیلد در محور مشخص‌شده را ذخیره یا آپدیت می‌کند.\nاین عملیات Merge است — فیلدهایی که ارسال نشده‌اند حذف نمی‌شوند.\n\nپیش‌شرط: وضعیت پروفایل باید pending_onboarding یا pending_info باشد.\nدر وضعیت waiting یا in_case، PATCH با خطای ۴۰۳ رد می‌شود.\n\nساختار ورودی:\n - current_step: مرحله فعلی کاربر در این فرم (برای محاسبه درصد پیشرفت)\n - total_steps: (اختیاری) تعداد کل مراحل این فرم. اگر ارسال شود و با مقدار فعلی section متفاوت باشد، بروزرسانی می‌شود\n - fields: آرایه‌ای از فیلدهای تکمیل‌شده\n\nپردازش فیلدهای media:\n ۱. فرانت‌اند فایل را از طریق اندپوینت آپلود موقت می‌فرستد و URL tmp دریافت می‌کند\n ۲. آن URL tmp را به عنوان value فیلد media ارسال می‌کند\n ۳. سرور فایل را از مسیر موقت خوانده، در مسیر دائمی ذخیره می‌کند\n ۴. URL دائمی در JSON فرم جایگزین URL tmp می‌شود\n\nاگر value فیلد media شامل \"tmp\" نباشد (فایل قبلاً دائمی شده)، بدون تغییر ذخیره می‌شود.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["current_step", "fields"], + "type": "object", + "properties": { + "current_step": { + "description": "مرحله فعلی کاربر در این فرم (از صفر)", + "type": "integer", + "minimum": 0 + }, + "total_steps": { + "description": "تعداد کل مراحل این فرم (اختیاری). اگر با مقدار فعلی section متفاوت باشد، بروزرسانی می‌شود", + "type": "integer", + "minimum": 1 + }, + "fields": { + "description": "لیست فیلدهای تکمیل‌شده", + "type": "array", + "items": { + "required": ["key", "label", "type", "value"], + "type": "object", + "properties": { + "key": { + "description": "کلید یکتای فیلد — مثال: birth_year", + "type": "string" + }, + "label": { + "description": "برچسب نمایشی فیلد — مثال: سال تولد", + "type": "string" + }, + "type": { + "description": "نوع فیلد: text | number | media | select | ...", + "type": "string" + }, + "value": { + "description": "مقدار فیلد — برای media: URL موقت یا دائمی (می‌تواند عدد، رشته، یا null باشد)", + "type": "string", + "x-nullable": true + } + } + } + } + }, + "example": { + "current_step": 2, + "total_steps": 3, + "fields": [ + { + "key": "birth_year", + "label": "سال تولد", + "type": "number", + "value": 1995 + }, + { + "key": "city", + "label": "شهر", + "type": "text", + "value": "تهران" + }, + { + "key": "id_scan", + "label": "کارت ملی", + "type": "media", + "value": "/media/tmp/upload_abc123.jpg" + } + ] + } + } + } + ], + "responses": { + "200": { + "description": "دیتای محور با موفقیت آپدیت شد", + "examples": { + "application/json": { + "id": 33, + "slug": "personal_info", + "data": [ + { + "key": "birth_year", + "label": "سال تولد", + "type": "number", + "value": 1995 + }, + { + "key": "city", + "label": "شهر", + "type": "text", + "value": "تهران" + }, + { + "key": "id_scan", + "label": "کارت ملی", + "type": "media", + "value": "/media/marriage/media/2026/04/upload_abc123.jpg" + } + ], + "current_step": 2, + "total_steps": 3, + "completion_percent": 66.7, + "updated_at": "2026-04-23T09:15:00Z" + } + } + }, + "400": { + "description": "خطا در اعتبارسنجی یا فایل media یافت نشد", + "examples": { + "application/json": { + "detail": "فایل رسانه‌ای یافت نشد. لطفاً دوباره آپلود کنید." + } + } + }, + "403": { + "description": "ویرایش در وضعیت فعلی مجاز نیست", + "examples": { + "application/json": { + "detail": "در وضعیت فعلی امکان ویرایش پروفایل وجود ندارد." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { + "description": "محور اطلاعاتی با این slug یافت نشد یا غیرفعال است" + } + }, + "tags": ["Marriage"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/api/talk/guidelines/": { + "get": { + "operationId": "api_talk_guidelines_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["Talk"] + }, + "parameters": [] + }, + "/api/talk/provider/": { + "post": { + "operationId": "api_talk_provider_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/talk_provider_profile" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/talk_provider_profile" } + } + }, + "tags": ["Talk"] + }, + "parameters": [] + }, + "/appversions/": { + "get": { + "operationId": "appversions_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["appversions"] + }, + "parameters": [] + }, + "/appversions/v2/": { + "get": { + "operationId": "appversions_v2_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["appversions"] + }, + "parameters": [] + }, + "/bookmark/add/": { + "post": { + "operationId": "bookmark_add_create", + "summary": "Add a new bookmark for a service.", + "description": "Request should contain:\n- service: The service to be bookmarked.\n- content_id: The content ID of the service to be bookmarked.\n\nReturns the created bookmark.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/BookmarkSerializers" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/BookmarkSerializers" } + } + }, + "tags": ["bookmark"] + }, + "parameters": [] + }, + "/bookmark/bulk/modify/": { + "post": { + "operationId": "bookmark_bulk_modify_create", + "description": "Bulk modify bookmarks by adding and removing them.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["add", "remove"], + "type": "object", + "properties": { + "add": { + "description": "List of items to add to bookmarks", + "type": "array", + "items": { + "type": "object", + "properties": { + "service": { + "description": "The service to be bookmarked (e.g., quran, mafatih, etc.)", + "type": "string" + }, + "content_id": { + "description": "The content ID of the service", + "type": "string" + }, + "text": { + "description": "Optional text for the bookmark", + "type": "string", + "nullable": true + } + } + } + }, + "remove": { + "description": "List of items to remove from bookmarks", + "type": "array", + "items": { + "type": "object", + "properties": { + "content_id": { + "description": "The content ID of the service to be removed", + "type": "string" + }, + "service": { + "description": "The service to be bookmarked (e.g., quran, mafatih, etc.)", + "type": "string" + } + } + } + } + }, + "example": { + "add": [ + { + "service": "quran", + "content_id": "123", + "text": "My favorite verse" + }, + { + "service": "mafatih", + "content_id": "456", + "text": "Daily dua" + } + ], + "remove": [{ "content_id": "789", "service": "quran" }] + } + } + } + ], + "responses": { "200": { "description": "Bulk modify completed." } }, + "tags": ["bookmark"] + }, + "parameters": [] + }, + "/bookmark/list/": { + "get": { + "operationId": "bookmark_list_list", + "summary": "List all bookmarks for the authenticated user.", + "description": "Can be filtered by service using the `service` query parameter.\n\nReturns a list of bookmarks.", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookmarkSerializers" } + } + } + } + } + }, + "tags": ["bookmark"] + }, + "parameters": [] + }, + "/bookmark/remove/{service}/{content_id}/": { + "delete": { + "operationId": "bookmark_remove_delete", + "summary": "Deactivate a bookmark by setting its status to False using content_id and user.", + "description": "The request should specify the content_id of the bookmark to be deactivated.\n\nReturns no content.", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["bookmark"] + }, + "parameters": [ + { "name": "service", "in": "path", "required": true, "type": "string" }, + { + "name": "content_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/calendar/adjustemnts/": { + "get": { + "operationId": "calendar_adjustemnts_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["calendar"] + }, + "parameters": [] + }, + "/calendar/occasions/": { + "get": { + "operationId": "calendar_occasions_list", + "description": "accept parameters:
\n-- **country** : str = Could be empty or ir, de, sp
\n-- **language_code** : str = en, fa
\n-- **last_updated** : datetime = 2021-06-20 08:36:53.153834
", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Calendar" } + } + } + }, + "tags": ["calendar"] + }, + "parameters": [] + }, + "/calendar/occasions/{occasion_id}/": { + "get": { + "operationId": "calendar_occasions_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["calendar"] + }, + "parameters": [ + { + "name": "occasion_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/category-masaels/": { + "get": { + "operationId": "category-masaels_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/MasaelCategories" } + } + } + }, + "tags": ["category-masaels"] + }, + "parameters": [] + }, + "/checkup/list/": { + "get": { + "operationId": "checkup_list_list", + "description": "\nدریافت لیست تمام چک‌آپ‌های فعال\n\nاین API لیست تمام چک‌آپ‌های موجود را با اطلاعات پایه نمایش می‌دهد.\nبرای هر چک‌آپ، اطلاعاتی شامل عنوان، تصویر، خلاصه، قیمت و فیلدهای زیر نمایش داده می‌شود:\n\nفیلدهای پاسخ:\n- questions_count: تعداد سوالات منحصر به فرد در چک‌آپ\n- answered_questions: تعداد سوالاتی که پاسخ داده شده است\n- has_access: آیا کاربر دسترسی دارد (رایگان یا خریده شده)\n- is_user_completed: آیا کاربر چک‌آپ را کامل کرده است\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "لیست چک‌آپ‌ها با موفقیت بازگردانده شد", + "examples": { + "application/json": [ + { + "id": 1, + "title": "چک‌آپ رزق و روزی", + "image": { + "sm": "http://example.com/media/image_sm.jpg", + "md": "http://example.com/media/image_md.jpg", + "lg": "http://example.com/media/image_lg.jpg" + }, + "summary": "بررسی وضعیت رزق و روزی شما", + "price": "10.00", + "is_free": false, + "questions_count": 15, + "has_participated": 0, + "answered_questions": null, + "is_user_completed": false, + "has_access": false + }, + { + "id": 2, + "title": "چک‌آپ سلامت روحی", + "image": { + "sm": "http://example.com/media/image2_sm.jpg", + "md": "http://example.com/media/image2_md.jpg", + "lg": "http://example.com/media/image2_lg.jpg" + }, + "summary": "ارزیابی سلامت روان", + "price": "0.00", + "is_free": true, + "questions_count": 20, + "has_participated": 2, + "answered_questions": 15, + "is_user_completed": false, + "has_access": true + } + ] + } + }, + "401": { "description": "کاربر احراز هویت نشده است" } + }, + "tags": ["checkup"] + }, + "parameters": [] + }, + "/checkup/parameter/{id}/detail/": { + "get": { + "operationId": "checkup_parameter_detail_read", + "description": "\nدریافت جزئیات یک پارامتر چک‌آپ\n\nاین API جزئیات کامل یک پارامتر شامل عنوان و توضیحات (حدیث یا متن تکمیلی) را نمایش می‌دهد.\n\nاستفاده:\n- زمانی که در نتایج چک‌آپ، فیلد has_details = true باشد\n- برای نمایش اطلاعات بیشتر درباره یک توصیه یا نقطه قوت\n\nفیلدهای پاسخ:\n- id: شناسه پارامتر\n- title: عنوان پارامتر\n- description: متن کامل شامل حدیث عربی، ترجمه و منبع\n", + "parameters": [], + "responses": { + "200": { + "description": "جزئیات پارامتر با موفقیت بازگردانده شد", + "examples": { + "application/json": { + "id": 76, + "title": "دوری از دعای بد علیه والدین", + "description": "«لا تَدْعُ عَلى والِدَیْکَ فَاِنَّهُ یُورِثُ الفَقْرَ»\n\nنفرین بر والدین باعث فقر می‌شود. والدین مجرای فیض وجود شما هستند...\n\n📚 منبع: کتاب الکافی، جلد 5، صفحه 554" + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "پارامتر یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Checkup Parameter.", + "required": true, + "type": "integer" + } + ] + }, + "/checkup/parameter/{id}/detail/v2/": { + "get": { + "operationId": "checkup_parameter_detail_v2_read", + "description": "V2 - دریافت جزئیات یک CheckupParameter با ساختار جدید", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/CheckupParameterDetailSerializerV2" + } + } + }, + "tags": ["checkup"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Checkup Parameter.", + "required": true, + "type": "integer" + } + ] + }, + "/checkup/user-checkups/": { + "get": { + "operationId": "checkup_user-checkups_list", + "description": "\nدریافت لیست چک‌آپ‌های کاربر\n\nاین API لیست تمام چک‌آپ‌هایی را که کاربر در آنها شرکت کرده است نمایش می‌دهد.\nبرای هر چک‌آپ، اطلاعاتی شامل عنوان، تصویر، خلاصه، قیمت و فیلدهای زیر نمایش داده می‌شود:\n\nفیلدهای پاسخ:\n- questions_count: تعداد سوالات منحصر به فرد در چک‌آپ\n- answered_questions: تعداد سوالاتی که پاسخ داده شده است\n- has_access: آیا کاربر دسترسی دارد (رایگان یا خریده شده)\n- is_user_completed: آیا کاربر چک‌آپ را کامل کرده است\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "لیست چک‌آپ‌های کاربر با موفقیت بازگردانده شد", + "examples": { + "application/json": [ + { + "id": 1, + "title": "چک‌آپ رزق و روزی", + "image": { + "sm": "http://example.com/media/image_sm.jpg", + "md": "http://example.com/media/image_md.jpg", + "lg": "http://example.com/media/image_lg.jpg" + }, + "summary": "بررسی وضعیت رزق و روزی شما", + "price": "10.00", + "is_free": false, + "questions_count": 15, + "has_participated": 2, + "answered_questions": 20, + "is_user_completed": true + }, + { + "id": 2, + "title": "چک‌آپ سلامت روحی", + "image": { + "sm": "http://example.com/media/image2_sm.jpg", + "md": "http://example.com/media/image2_md.jpg", + "lg": "http://example.com/media/image2_lg.jpg" + }, + "summary": "ارزیابی سلامت روان", + "price": "0.00", + "is_free": true, + "questions_count": 20, + "has_participated": 1, + "answered_questions": 10, + "is_user_completed": false + } + ] + } + }, + "401": { "description": "کاربر احراز هویت نشده است" } + }, + "tags": ["checkup"] + }, + "parameters": [] + }, + "/checkup/{id}/": { + "get": { + "operationId": "checkup_read", + "description": "\nدریافت جزئیات کامل یک چک‌آپ\n\nاین API اطلاعات کامل یک چک‌آپ شامل عنوان، تصویر، خلاصه، توضیحات کامل، قیمت و فیلدهای زیر را نمایش می‌دهد:\n\nفیلدهای پاسخ:\n- questions_count: تعداد سوالات منحصر به فرد در چک‌آپ\n- answered_questions: تعداد سوالاتی که پاسخ داده شده است\n- has_access: آیا کاربر دسترسی دارد (رایگان یا خریده شده)\n- is_user_completed: آیا کاربر چک‌آپ را کامل کرده است\n", + "parameters": [], + "responses": { + "200": { + "description": "جزئیات چک‌آپ با موفقیت بازگردانده شد", + "examples": { + "application/json": { + "id": 1, + "title": "چک‌آپ رزق و روزی", + "image": { + "sm": "http://example.com/media/image_sm.jpg", + "md": "http://example.com/media/image_md.jpg", + "lg": "http://example.com/media/image_lg.jpg" + }, + "summary": "بررسی وضعیت رزق و روزی شما", + "description": "توضیحات کامل در مورد چک‌آپ رزق و روزی...", + "price": "10.00", + "is_free": false, + "questions_count": 15, + "has_participated": 2, + "answered_questions": 5, + "is_user_completed": false, + "has_access": true + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Checkup.", + "required": true, + "type": "integer" + } + ] + }, + "/checkup/{id}/basic-questions/": { + "get": { + "operationId": "checkup_basic-questions_list", + "description": "\nدریافت لیست سوالات پایه یک چک‌آپ\n\nاین API سوالات پایه (مانند جنسیت، سن، وضعیت تأهل) یک چک‌آپ را به همراه \nگزینه‌های پاسخ آن نمایش می‌دهد.\nکاربر باید قبلاً در چک‌آپ شرکت کرده باشد (join).\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "لیست سوالات پایه با موفقیت بازگردانده شد", + "examples": { + "application/json": { + "answered_questions": 2, + "result": [ + { + "id": 1, + "title": "جنسیت شما چیست؟", + "question_help_text": "لطفاً جنسیت خود را انتخاب کنید", + "question_type": "single", + "question_widget_type": "radio", + "answers": [ + { + "id": 1, + "title": "مرد", + "image": { + "sm": "http://example.com/media/male_sm.jpg", + "md": "http://example.com/media/male_md.jpg", + "lg": "http://example.com/media/male_lg.jpg" + } + }, + { + "id": 2, + "title": "زن", + "image": { + "sm": "http://example.com/media/female_sm.jpg", + "md": "http://example.com/media/female_md.jpg", + "lg": "http://example.com/media/female_lg.jpg" + } + } + ] + } + ] + } + } + }, + "400": { "description": "کاربر هنوز در چک‌آپ شرکت نکرده است" }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/basic-questions/submit/": { + "post": { + "operationId": "checkup_basic-questions_submit_create", + "description": "\nثبت پاسخ‌های سوالات پایه\n\nاین API برای ثبت پاسخ‌های کاربر به سوالات پایه چک‌آپ استفاده می‌شود.\nبرای هر سوال، باید شناسه سوال (question_id) و شناسه پاسخ انتخابی (answer_id) ارسال شود.\nاگر UserCheckup وجود نداشته باشد، به صورت خودکار ایجاد می‌شود.\nاین عملیات در یک transaction انجام می‌شود.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["answers"], + "type": "object", + "properties": { + "answers": { + "description": "لیست پاسخ‌های سوالات پایه", + "type": "array", + "items": { + "type": "object", + "properties": { + "question_id": { + "description": "شناسه سوال", + "type": "integer" + }, + "answer_id": { + "description": "شناسه پاسخ", + "type": "integer" + } + } + } + } + }, + "example": { + "answers": [ + { "question_id": 1, "answer_id": 2 }, + { "question_id": 2, "answer_id": 5 } + ] + } + } + } + ], + "responses": { + "201": { + "description": "پاسخ‌ها با موفقیت ثبت شد", + "examples": { + "application/json": { + "detail": "Basic answers submitted successfully." + } + } + }, + "400": { + "description": "خطا در اعتبارسنجی", + "examples": { + "application/json": { + "detail": "Each answer must contain 'question_id' and 'answer_id'." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/history/": { + "get": { + "operationId": "checkup_history_list", + "description": "لیست تمام دفعاتی که کاربر در یک چک‌آپ خاص شرکت کرده و تمام کرده.", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/join/": { + "post": { + "operationId": "checkup_join_create", + "description": "\nشرکت در یک چک‌آپ\n\nاین API برای شرکت کاربر در یک چک‌آپ استفاده می‌شود.\nاگر چک‌آپ رایگان باشد، مستقیماً کاربر ثبت می‌شود.\nاگر چک‌آپ پولی باشد، کوین‌های کاربر کسر شده و سپس ثبت‌نام انجام می‌شود.\nکاربر می‌تواند چند بار در یک چک‌آپ شرکت کند.\n", + "parameters": [], + "responses": { + "201": { + "description": "شرکت در چک‌آپ با موفقیت انجام شد", + "examples": { + "application/json": { + "detail": "Successfully joined the checkup." + } + } + }, + "400": { + "description": "خطا در شرکت", + "examples": { + "application/json": { + "detail": "Insufficient coins. You need 100 coins but have 50." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/parameter-questions/": { + "get": { + "operationId": "checkup_parameter-questions_list", + "description": "\nدریافت لیست سوالات پارامتر یک چک‌آپ\n\nاین API سوالات اصلی چک‌آپ (CheckupParameter Questions) را که از طریق BasicQuestion \nبه پارامترها متصل هستند، به همراه گزینه‌های پاسخ نمایش می‌دهد.\nاین سوالات امتیازدهی دارند و در محاسبه نتیجه نهایی استفاده می‌شوند.\nکاربر باید قبلاً در چک‌آپ شرکت کرده باشد (join).\n\nفیلدهای جدید:\n- is_weight_visible: آیا وزن پارامتر باید برای کاربر نمایش داده شود یا خیر\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "لیست سوالات پارامتر با موفقیت بازگردانده شد", + "examples": { + "application/json": { + "answered_questions": 3, + "result": [ + { + "id": 10, + "title": "آیا در نماز صبح شرکت می‌کنید؟", + "question": "توضیحاتی درباره سوال", + "description": "توضیح کامل پارامتر", + "order": 1, + "parameter_type": "positive", + "is_weight_visible": true, + "parameter_answers": [ + { + "id": 25, + "title": "هیچ وقت", + "answer_type": "text", + "image": null, + "weight": 0 + }, + { + "id": 26, + "title": "گاهی اوقات", + "answer_type": "text", + "image": null, + "weight": 25 + }, + { + "id": 27, + "title": "بیشتر اوقات", + "answer_type": "text", + "image": null, + "weight": 75 + }, + { + "id": 28, + "title": "همیشه", + "answer_type": "text", + "image": null, + "weight": 100 + } + ] + } + ] + } + } + }, + "400": { "description": "کاربر هنوز در چک‌آپ شرکت نکرده است" }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/parameters/submit/": { + "post": { + "operationId": "checkup_parameters_submit_create", + "description": "\nثبت پاسخ‌های سوالات اصلی و محاسبه نتیجه\n\nاین API برای ثبت پاسخ‌های کاربر به سوالات اصلی چک‌آپ (CheckupParameter) استفاده می‌شود.\nبرای هر سوال، باید شناسه سوال (question_id) و شناسه پاسخ (answer_id) ارسال شود.\n\nسیستم به صورت خودکار:\n1. از طریق BasicQuestion، پارامتر مرتبط را پیدا می‌کند\n2. بر اساس parameter_type (positive/negative) و weight، امتیاز محاسبه می‌شود\n3. درصد امکان بهبود (possibility_of_improvement) محاسبه می‌شود\n4. گزارش با سه وضعیت (emergency, improvement, positive) ایجاد می‌شود\n5. لیست توصیه‌ها بر اساس امتیازها تولید می‌شود\n\nاین عملیات در یک transaction انجام می‌شود و UserCheckup به حالت completed تغییر می‌کند.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["answers"], + "type": "object", + "properties": { + "answers": { + "description": "لیست پاسخ‌های سوالات اصلی", + "type": "array", + "items": { + "type": "object", + "properties": { + "question_id": { + "description": "شناسه سوال", + "type": "integer" + }, + "answer_id": { + "description": "شناسه پاسخ", + "type": "integer" + } + } + } + } + }, + "example": { + "answers": [ + { "question_id": 10, "answer_id": 25 }, + { "question_id": 11, "answer_id": 30 }, + { "question_id": 12, "answer_id": 28 } + ] + } + } + } + ], + "responses": { + "201": { + "description": "پاسخ‌ها با موفقیت ثبت و نتیجه محاسبه شد", + "examples": { + "application/json": { + "possibility_of_improvement": 65.5, + "people_medium": 58, + "report": [ + { + "status": "emergency", + "count": 2, + "items": [ + { "order": 1, "text": "نماز صبح" }, + { "order": 3, "text": "روزه" } + ] + }, + { + "status": "improvement", + "count": 3, + "items": [ + { "order": 2, "text": "صدقه" }, + { "order": 5, "text": "دعا" }, + { "order": 7, "text": "استغفار" } + ] + }, + { + "status": "positive", + "count": 4, + "items": [ + { "order": 4, "text": "نماز جماعت" }, + { "order": 6, "text": "قرآن" }, + { "order": 8, "text": "زیارت" }, + { "order": 9, "text": "حج" } + ] + } + ], + "recommendations_count": 9, + "recommendations": [ + { "order": 1, "text": "نماز صبح" }, + { "order": 2, "text": "صدقه" }, + { "order": 3, "text": "روزه" } + ] + } + } + }, + "400": { + "description": "خطا در اعتبارسنجی یا UserCheckup یافت نشد", + "examples": { + "application/json": { + "detail": "UserCheckup not found. Please join the checkup first or complete basic questions." + } + } + }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/previous-answers/": { + "get": { + "operationId": "checkup_previous-answers_read", + "description": "\nGet user's previous answers for a completed checkup\n\nThis API returns the most recent completed UserCheckup for the authenticated user\nalong with all their basic question answers and parameter answers.\n\nUse this when user wants to review their previous checkup results or\nwhen they want to redo a checkup with their previous answers pre-filled.\n\nResponse includes:\n- user_checkup_id: ID of the UserCheckup record\n- checkup_id: ID of the checkup\n- completed_at: When the checkup was completed\n- is_completed: Whether the checkup is completed\n- total_score: Total score achieved\n- basic_question_answers: List of all basic question answers\n- parameter_answers: List of all parameter answers with weighted scores\n", + "parameters": [], + "responses": { + "200": { + "description": "Previous answers retrieved successfully", + "examples": { + "application/json": { + "user_checkup_id": 123, + "checkup_id": 5, + "completed_at": "2025-12-20T10:00:00Z", + "is_completed": true, + "total_score": 85, + "basic_question_answers": [ + { + "question_id": 1, + "question_title": "Gender", + "answer_id": 10, + "answer_title": "Male", + "answered_at": "2025-12-20T09:30:00Z" + } + ], + "parameter_answers": [ + { + "parameter_id": 50, + "parameter_title": "Sleep Quality", + "answer_id": 200, + "answer_title": "Good", + "weighted_score": 8.5, + "answered_at": "2025-12-20T09:35:00Z" + } + ] + } + } + }, + "401": { "description": "User not authenticated" }, + "404": { "description": "No completed checkup found for this user" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/result/": { + "get": { + "operationId": "checkup_result_read", + "description": "\nدریافت نتیجه نهایی چک‌آپ\n\nاین API نتیجه نهایی چک‌آپ را پس از پاسخ به تمام سوالات نمایش می‌دهد.\n\nفیلدهای پاسخ:\n- statistics: آمار متغیرها شامل name، code، value، type، display_mode، achieved_items و total_items\n- report: گزارش دسته‌بندی شده (emergency, improvement, positive)\n- recommendations: لیست توصیه‌های اولویت‌دار\n- total_score: امتیاز کل (میانگین)\n\nتوضیحات statistics:\n- name: نام نمایشی متغیر (ترجمه شده)\n- code: کد یکتای متغیر (برای استفاده در لاجیک)\n- display_mode: نحوه نمایش (gauge: نمودار دایره‌ای، progress_bar: کارت بزرگ، hidden: مخفی)\n- achieved_items: تعداد موارد موفق (برای positive: وزن>=75، برای negative: وزن<=25)\n- total_items: تعداد کل سوالات مرتبط با متغیر\n", + "parameters": [], + "responses": { + "200": { + "description": "نتیجه چک‌آپ با موفقیت محاسبه شد", + "examples": { + "application/json": { + "statistics": [ + { + "name": "عامل برکت روزی", + "code": "blessing_factor", + "value": 97.0, + "type": "positive", + "display_mode": "gauge", + "achieved_items": 73, + "total_items": 75 + }, + { + "name": "عامل موانع روزی", + "code": "obstacle_factor", + "value": 7.7, + "type": "negative", + "display_mode": "progress_bar", + "achieved_items": 1, + "total_items": 68 + } + ], + "report": [ + { + "status": "emergency", + "count": 2, + "items": [ + { "order": 1, "text": "نماز صبح" }, + { "order": 3, "text": "روزه" } + ] + }, + { + "status": "improvement", + "count": 3, + "items": [ + { "order": 2, "text": "صدقه" }, + { "order": 5, "text": "دعا" } + ] + }, + { + "status": "positive", + "count": 4, + "items": [ + { "order": 4, "text": "نماز جماعت" }, + { "order": 6, "text": "قرآن" } + ] + } + ], + "recommendations_count": 9, + "recommendations": [ + { "order": 1, "text": "نماز صبح" }, + { "order": 2, "text": "صدقه" } + ], + "total_score": 85.5 + } + } + }, + "400": { "description": "چک‌آپ تکمیل نشده است" }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{id}/result/v2/": { + "get": { + "operationId": "checkup_result_v2_read", + "description": "\nدریافت نتیجه نهایی چک‌آپ - نسخه 2\n\nاین API نسخه بهبود یافته نتایج است که شامل گزارش با 4 وضعیت جدید می‌شود:\n- strengths: نقاط قوت (امتیاز بالا)\n- emergencies: موارد اضطراری (امتیاز بسیار پایین، نیاز فوری)\n- important: موارد مهم (امتیاز متوسط به پایین)\n- useful: موارد مفید (امتیاز متوسط)\n\nساختار پاسخ مشابه V1 است با این تفاوت که:\n- وضعیت‌های جدید به جای emergency, improvement, positive استفاده می‌شود\n- فیلدهای recommendations_count، recommendations و total_score حذف شده‌اند\n\nفیلدهای پاسخ:\n- statistics: آمار متغیرها شامل name، code، value، type، display_mode، achieved_items و total_items\n- report: آرایه‌ای از 4 وضعیت، هر کدام شامل status، count و items\n- هر آیتم شامل: parameter_id، order، title، text، score و has_details\n\nتوضیحات statistics:\n- name: نام نمایشی متغیر (ترجمه شده)\n- code: کد یکتای متغیر (برای استفاده در لاجیک)\n- display_mode: نحوه نمایش (gauge: نمودار دایره‌ای، progress_bar: کارت بزرگ، hidden: مخفی)\n- achieved_items: تعداد موارد موفق (برای positive: وزن>=75، برای negative: وزن<=25)\n- total_items: تعداد کل سوالات مرتبط با متغیر\n\nنکته مهم:\n- has_details: اگر true باشد، می‌توانید از API جزئیات پارامتر استفاده کنید\n- برای دریافت جزئیات: GET /checkup/parameter/{parameter_id}/detail/\n", + "parameters": [], + "responses": { + "200": { + "description": "نتیجه چک‌آپ نسخه 2 با موفقیت محاسبه شد", + "examples": { + "application/json": { + "statistics": [ + { + "name": "عامل برکت روزی", + "code": "blessing_factor", + "value": 97.0, + "type": "positive", + "display_mode": "gauge", + "achieved_items": 73, + "total_items": 75 + }, + { + "name": "عامل موانع روزی", + "code": "obstacle_factor", + "value": 7.7, + "type": "negative", + "display_mode": "progress_bar", + "achieved_items": 1, + "total_items": 68 + } + ], + "report": [ + { + "status": "strengths", + "count": 2, + "items": [ + { + "parameter_id": 76, + "order": 0, + "title": "دوری از دعای بد علیه والدین", + "text": "والدین، مجرایِ فیضِ وجودِ شما هستند؛ بستنِ این مجرا با نفرین، یعنی بستنِ شیرِ فلکه‌ی حیات...", + "score": 300, + "has_details": true + }, + { + "parameter_id": 40, + "order": 0, + "title": "امانتداری", + "text": "امانتداری، تنها یک فضیلت اخلاقی نیست، بلکه یک استراتژی اقتصادی قدرتمند است...", + "score": 200, + "has_details": true + } + ] + }, + { + "status": "emergencies", + "count": 1, + "items": [ + { + "parameter_id": 15, + "order": 0, + "title": "نماز صبح", + "text": "نماز صبح کلید برکت روز است...", + "score": -300, + "has_details": true + } + ] + }, + { + "status": "important", + "count": 1, + "items": [ + { + "parameter_id": 25, + "order": 0, + "title": "صدقه", + "text": "صدقه دادن درهای روزی را باز می‌کند...", + "score": 150, + "has_details": false + } + ] + }, + { + "status": "useful", + "count": 1, + "items": [ + { + "parameter_id": 30, + "order": 0, + "title": "استغفار", + "text": "استغفار باعث افزایش روزی می‌شود...", + "score": 100, + "has_details": false + } + ] + } + ] + } + } + }, + "400": { "description": "چک‌آپ تکمیل نشده است" }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/checkup/{participation_id}/result/v3/": { + "get": { + "operationId": "checkup_result_v3_read", + "description": "\nدریافت نتیجه نهایی چک‌آپ - نسخه 2\n\nاین API نسخه بهبود یافته نتایج است که شامل گزارش با 4 وضعیت جدید می‌شود:\n- strengths: نقاط قوت (امتیاز بالا)\n- emergencies: موارد اضطراری (امتیاز بسیار پایین، نیاز فوری)\n- important: موارد مهم (امتیاز متوسط به پایین)\n- useful: موارد مفید (امتیاز متوسط)\n\nساختار پاسخ مشابه V1 است با این تفاوت که:\n- وضعیت‌های جدید به جای emergency, improvement, positive استفاده می‌شود\n- فیلدهای recommendations_count، recommendations و total_score حذف شده‌اند\n\nفیلدهای پاسخ:\n- statistics: آمار متغیرها شامل name، code، value، type، display_mode، achieved_items و total_items\n- report: آرایه‌ای از 4 وضعیت، هر کدام شامل status، count و items\n- هر آیتم شامل: parameter_id، order، title، text، score و has_details\n\nتوضیحات statistics:\n- name: نام نمایشی متغیر (ترجمه شده)\n- code: کد یکتای متغیر (برای استفاده در لاجیک)\n- display_mode: نحوه نمایش (gauge: نمودار دایره‌ای، progress_bar: کارت بزرگ، hidden: مخفی)\n- achieved_items: تعداد موارد موفق (برای positive: وزن>=75، برای negative: وزن<=25)\n- total_items: تعداد کل سوالات مرتبط با متغیر\n\nنکته مهم:\n- has_details: اگر true باشد، می‌توانید از API جزئیات پارامتر استفاده کنید\n- برای دریافت جزئیات: GET /checkup/parameter/{parameter_id}/detail/\n", + "parameters": [], + "responses": { + "200": { + "description": "نتیجه چک‌آپ نسخه 2 با موفقیت محاسبه شد", + "examples": { + "application/json": { + "statistics": [ + { + "name": "عامل برکت روزی", + "code": "blessing_factor", + "value": 97.0, + "type": "positive", + "display_mode": "gauge", + "achieved_items": 73, + "total_items": 75 + }, + { + "name": "عامل موانع روزی", + "code": "obstacle_factor", + "value": 7.7, + "type": "negative", + "display_mode": "progress_bar", + "achieved_items": 1, + "total_items": 68 + } + ], + "report": [ + { + "status": "strengths", + "count": 2, + "items": [ + { + "parameter_id": 76, + "order": 0, + "title": "دوری از دعای بد علیه والدین", + "text": "والدین، مجرایِ فیضِ وجودِ شما هستند؛ بستنِ این مجرا با نفرین، یعنی بستنِ شیرِ فلکه‌ی حیات...", + "score": 300, + "has_details": true + }, + { + "parameter_id": 40, + "order": 0, + "title": "امانتداری", + "text": "امانتداری، تنها یک فضیلت اخلاقی نیست، بلکه یک استراتژی اقتصادی قدرتمند است...", + "score": 200, + "has_details": true + } + ] + }, + { + "status": "emergencies", + "count": 1, + "items": [ + { + "parameter_id": 15, + "order": 0, + "title": "نماز صبح", + "text": "نماز صبح کلید برکت روز است...", + "score": -300, + "has_details": true + } + ] + }, + { + "status": "important", + "count": 1, + "items": [ + { + "parameter_id": 25, + "order": 0, + "title": "صدقه", + "text": "صدقه دادن درهای روزی را باز می‌کند...", + "score": 150, + "has_details": false + } + ] + }, + { + "status": "useful", + "count": 1, + "items": [ + { + "parameter_id": 30, + "order": 0, + "title": "استغفار", + "text": "استغفار باعث افزایش روزی می‌شود...", + "score": 100, + "has_details": false + } + ] + } + ] + } + } + }, + "400": { "description": "چک‌آپ تکمیل نشده است" }, + "401": { "description": "کاربر احراز هویت نشده است" }, + "404": { "description": "چک‌آپ یافت نشد" } + }, + "tags": ["checkup"] + }, + "parameters": [ + { + "name": "participation_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/command/": { + "post": { + "operationId": "command_create", + "description": "Handles incoming API requests and routes them to the relevant handler.", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["command"] + }, + "parameters": [] + }, + "/command/help/": { + "get": { + "operationId": "command_help_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/CommandHelp" } + } + } + }, + "tags": ["command"] + }, + "parameters": [] + }, + "/command/suggestion/": { + "get": { + "operationId": "command_suggestion_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/CommandSuggestion" } + } + } + }, + "tags": ["command"] + }, + "parameters": [] + }, + "/command/v2/": { + "post": { + "operationId": "command_v2_create", + "description": "Handles incoming command requests and processes them through RAG system", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["command", "language_code"], + "type": "object", + "properties": { + "command": { + "description": "User command or query", + "type": "string" + }, + "language_code": { + "description": "Language code (e.g., \"en\", \"fa\")", + "type": "string", + "default": "en" + } + } + } + } + ], + "responses": { + "201": { + "description": "", + "schema": { + "required": ["command", "language_code"], + "type": "object", + "properties": { + "command": { + "description": "User command or query", + "type": "string" + }, + "language_code": { + "description": "Language code (e.g., \"en\", \"fa\")", + "type": "string", + "default": "en" + } + } + } + } + }, + "tags": ["command"] + }, + "parameters": [] + }, + "/donate/": { + "post": { + "operationId": "donate_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DonateUser" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DonateUser" } + } + }, + "tags": ["donate"] + }, + "parameters": [] + }, + "/donate/v2/": { + "get": { + "operationId": "donate_v2_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["donate"] + }, + "parameters": [] + }, + "/donate/v2/create/": { + "post": { + "operationId": "donate_v2_create_create", + "description": "\n**Donation Creation API**\n\nCreate a donation record and receive a payment link. This API is designed to never fail and always returns a working donation link without any errors.\n\n**Key Features:**\n- Error-free operation - never returns HTTP errors\n- All fields are completely optional with intelligent defaults\n- Automatic payment method selection based on user location\n- Support for multiple payment gateways\n- Backward compatibility with existing integrations\n\n**Smart Defaults:**\n- **donate_type**: Defaults to 'once' if not provided or invalid\n- **price**: Defaults to '10.00' if not provided or invalid\n- **id**: Auto-selected based on user location (CloudTips for Russian users, Stripe for others)\n- **phone_number**: Optional field, stored if provided, otherwise null\n\n**Payment Methods:**\n- **Stripe**: International payment gateway with predefined donation links\n- **CloudTips**: Russian payment gateway for Russian users\n\n**Localization Logic:**\n- Russian users (language_code=ru OR user.country=RU) default to CloudTips\n- All other users default to Stripe payment gateway\n- Fallback to default donation links for custom amounts\n\n**Business Logic:**\n- Creates donation record in database (optional, doesn't affect response)\n- Optionally stores donor's phone number for contact purposes\n- Maps donation amounts to predefined Stripe payment links\n- Uses fallback links for unmapped amounts\n- Always returns HTTP 200 with working payment link\n\n**Authentication**: Not required - Public API\n**Permissions**: None - Accessible to all users\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": [], + "type": "object", + "properties": { + "donate_type": { + "description": "Type of donation - either 'monthly' for recurring donations or 'once' for one-time donations. This field is completely optional and will default to 'once' if not provided or if an invalid value is sent.", + "type": "string", + "enum": ["monthly", "once"] + }, + "price": { + "description": "Donation amount as a string (e.g., '5.00', '10.00', '20.00'). This field is completely optional and will default to '10.00' if not provided or if an invalid value is sent.", + "type": "string" + }, + "id": { + "description": "Payment gateway identifier. This field is completely optional. If not provided, the system will automatically choose 'stripe' for non-Russian users and 'cloudtips' for Russian users (detected by language_code=ru or user country=RU). If an invalid value is provided, it defaults to 'stripe'.", + "type": "string", + "enum": ["stripe", "cloudtips"] + }, + "phone_number": { + "description": "Optional phone number for the donor. This field is completely optional and can be omitted. If provided, it will be stored with the donation record.", + "type": "string" + } + }, + "example": { + "donate_type": "once", + "price": "15.00", + "id": "stripe", + "phone_number": "+1234567890" + } + } + } + ], + "responses": { + "200": { + "description": "Donation link created successfully. This API is guaranteed to always return HTTP 200 status with a working donation link, regardless of the input provided. Even if no data is sent in the request body, the API will respond with appropriate defaults.", + "examples": { + "application/json": { + "complete_request": { + "summary": "Complete Request with Phone Number", + "description": "Response when all fields including phone_number are provided", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/bIYdSDgiK7Pwh0ccMN" + } + }, + "request_with_phone": { + "summary": "Request Example with Phone", + "description": "Example showing phone_number parameter usage", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/9AQ01N5E68TAbFS002" + } + }, + "empty_request_default": { + "summary": "Empty Request (Default)", + "description": "Response when no fields are provided - uses intelligent defaults", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV" + } + }, + "empty_request_russian_user": { + "summary": "Empty Request (Russian User)", + "description": "Response for Russian users when no fields are provided", + "value": { + "donate_user": 1, + "donate_link": "https://pay.cloudtips.ru/p/d5881ddf" + } + }, + "cloudtips_payment": { + "summary": "CloudTips Payment", + "description": "Response when CloudTips payment method is selected", + "value": { + "donate_user": 1, + "donate_link": "https://pay.cloudtips.ru/p/d5881ddf" + } + }, + "invalid_data_fallback": { + "summary": "Invalid Data Fallback", + "description": "Response when invalid data is provided - normalized to defaults", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV" + } + } + } + } + } + }, + "tags": ["Donate"] + }, + "parameters": [] + }, + "/donate/v3/": { + "get": { + "operationId": "donate_v3_list", + "description": "\n**Donation Details API V3**\n\nRetrieve donation pricing information and available payment methods with intelligent localization support.\n\n**Key Features:**\n- Monthly and one-time donation options\n- Dynamic pricing based on user location\n- Multiple payment gateway support\n- Localized currency and payment methods\n- Russian language and payment gateway support\n\n**Donation Types:**\n- **Monthly**: Recurring donations with subscription pricing\n- **Once**: One-time donations with flexible amounts\n\n**Payment Methods:**\n- **Stripe**: International payment gateway (default)\n- **CloudTips**: Russian payment gateway for Russian users\n\n**Localization Logic:**\n- Detects user language from request headers or query parameters\n- Detects user country from authenticated user profile\n- Russian users see ruble pricing and CloudTips payment option\n- Non-Russian users see USD pricing with Stripe only\n\n**Business Logic:**\n- Monthly donations: Same pricing for all users ($5, $10, $20, $50)\n- Once donations: USD for international users, RUB for Russian users\n- Russian detection: language_code=ru OR user.country=RU\n- Payment buttons include icon, text, and payment method ID\n\n**Authentication**: Not required - Public API\n**Permissions**: None - Accessible to all users\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language preference (e.g., 'ru' for Russian, 'en' for English)", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Donation details retrieved successfully", + "examples": { + "application/json": { + "international_user_response": { + "summary": "International User Response", + "description": "Default response for non-Russian users with USD pricing", + "value": { + "monthly": { + "prices": [ + { "value": "$5", "price": "5.00" }, + { "value": "$10", "price": "10.00" }, + { "value": "$20", "price": "20.00" }, + { "value": "$50", "price": "50.00" } + ], + "buttons": [ + { + "icon": "https://habibapp.com/static/payicon.jpg", + "text": "Donate Now", + "id": "stripe" + } + ] + }, + "once": { + "prices": [ + { "value": "$5", "price": "5.00" }, + { "value": "$15", "price": "15.00" }, + { "value": "$30", "price": "30.00" }, + { "value": "$40", "price": "40.00" } + ], + "buttons": [ + { + "icon": "https://habibapp.com/static/payicon.jpg", + "text": "Donate Now", + "id": "stripe" + } + ] + } + } + }, + "russian_user_response": { + "summary": "Russian User Response", + "description": "Localized response for Russian users with ruble pricing and CloudTips", + "value": { + "monthly": { + "prices": [ + { "value": "$5", "price": "5.00" }, + { "value": "$10", "price": "10.00" }, + { "value": "$20", "price": "20.00" }, + { "value": "$50", "price": "50.00" } + ], + "buttons": [ + { + "icon": "https://habibapp.com/static/payicon.jpg", + "text": "Donate Now", + "id": "stripe" + } + ] + }, + "once": { + "prices": [ + { "value": "₽500", "price": "5.00" }, + { "value": "₽1500", "price": "15.00" }, + { "value": "₽3000", "price": "30.00" }, + { "value": "₽4000", "price": "40.00" } + ], + "buttons": [ + { + "icon": "https://habibapp.com/static/payicon.jpg", + "text": "Donate Now", + "id": "stripe" + }, + { + "icon": "https://habibapp.com/static/cloudtips_icon.png", + "text": "Пожертвовать через CloudTips", + "id": "cloudtips" + } + ] + } + } + } + } + } + } + }, + "tags": ["Donate"] + }, + "parameters": [] + }, + "/dont-kill-help/": { + "get": { + "operationId": "dont-kill-help_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DontKillApp" } + } + }, + "tags": ["dont-kill-help"] + }, + "parameters": [] + }, + "/eightmag-categories/": { + "get": { + "operationId": "eightmag-categories_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/EightmagCategories" } + } + } + }, + "tags": ["eightmag-categories"] + }, + "parameters": [] + }, + "/eightmag-category-items/{slug}/": { + "get": { + "operationId": "eightmag-category-items_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/EightmagList" } + } + } + } + } + }, + "tags": ["eightmag-category-items"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/eightmag-details/{slug}/": { + "get": { + "operationId": "eightmag-details_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/EightmagDetails" } + } + }, + "tags": ["eightmag-details"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/eightmag-details/{slug}/like/": { + "post": { + "operationId": "eightmag-details_like_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["eightmag-details"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/eightmag-list/": { + "get": { + "operationId": "eightmag-list_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/EightmagList" } + } + } + } + } + }, + "tags": ["eightmag-list"] + }, + "parameters": [] + }, + "/elalhabib/": { + "get": { + "operationId": "elalhabib_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ElalHabib" } + } + } + } + } + }, + "tags": ["elalhabib"] + }, + "parameters": [] + }, + "/elalhabib/lectures/": { + "get": { + "operationId": "elalhabib_lectures_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ElalHabibSingerInList" } + } + } + } + } + }, + "tags": ["elalhabib"] + }, + "parameters": [] + }, + "/elalhabib/madah/": { + "get": { + "operationId": "elalhabib_madah_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ElalHabibSingerInList" } + } + } + } + } + }, + "tags": ["elalhabib"] + }, + "parameters": [] + }, + "/habcoin/buy-package/": { + "post": { + "operationId": "habcoin_buy-package_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/contact-info/": { + "get": { + "operationId": "habcoin_contact-info_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/discount-usage-history/": { + "get": { + "operationId": "habcoin_discount-usage-history_list", + "description": "Get user's discount code usage history", + "parameters": [], + "responses": { + "200": { + "description": "List of user discount code usages", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/DiscountCodeUsage" } + } + }, + "401": { "description": "Unauthorized - Authentication required" } + }, + "tags": ["Discount Code"] + }, + "parameters": [] + }, + "/habcoin/inventory/": { + "get": { + "operationId": "habcoin_inventory_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/packages/": { + "get": { + "operationId": "habcoin_packages_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Package" } + } + } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/pay/": { + "get": { + "operationId": "habcoin_pay_list", + "description": "", + "parameters": [ + { + "name": "token", + "in": "query", + "description": "Security token", + "required": true, + "type": "string" + }, + { + "name": "service", + "in": "query", + "description": "Service type", + "required": true, + "type": "string" + }, + { + "name": "object_id", + "in": "query", + "description": "Object ID related to the service", + "required": true, + "type": "integer" + }, + { + "name": "amount", + "in": "query", + "description": "The number of coins to be deducted", + "required": false, + "type": "integer" + }, + { + "name": "app_name", + "in": "query", + "description": "Optional app label for the model", + "required": false, + "type": "string" + }, + { + "name": "discount_code", + "in": "query", + "description": "Optional discount code to apply discount on payment. The code will be validated and discount will be automatically applied if valid.", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Coins deducted successfully", + "examples": { + "application/json": { + "status": "Coins deducted successfully", + "original_price": 10, + "final_price": 8, + "discount_applied": 2 + } + } + }, + "400": { "description": "Not enough coins or invalid discount code" }, + "403": { "description": "Invalid security token" }, + "404": { "description": "User not found" } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/support/": { + "post": { + "operationId": "habcoin_support_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Support" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/Support" } + } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/transactions/": { + "get": { + "operationId": "habcoin_transactions_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Transactions" } + } + } + } + } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/user-coin-usages/": { + "get": { + "operationId": "habcoin_user-coin-usages_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/UserCoinUsage" } + } + } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/user-packages/": { + "get": { + "operationId": "habcoin_user-packages_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/UserPackage" } + } + } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/v2/pay/": { + "get": { + "operationId": "habcoin_v2_pay_list", + "summary": "Escrow Payment API (V2)", + "description": "Extends the original Pay view with support for escrow-style payments:\n- hold: Deduct coins from user but do NOT transfer to provider (escrow hold)\n- release: Transfer held coins to provider's wallet (after successful call)\n- refund: Return held coins to user's balance (on cancellation)\n- direct: Same as original Pay — deduct from user AND transfer to provider", + "parameters": [ + { + "name": "token", + "in": "query", + "description": "Security token", + "required": true, + "type": "string" + }, + { + "name": "action", + "in": "query", + "description": "Payment action: hold, release, refund, direct", + "required": true, + "type": "string", + "enum": ["hold", "release", "refund", "direct"] + }, + { + "name": "username", + "in": "query", + "description": "User email (legacy fallback for hold, refund, direct)", + "required": false, + "type": "string" + }, + { + "name": "habib_user_id", + "in": "query", + "description": "Unambiguous payer id; preferred over username when present", + "required": false, + "type": "integer" + }, + { + "name": "amount", + "in": "query", + "description": "Number of coins", + "required": true, + "type": "integer" + }, + { + "name": "object_id", + "in": "query", + "description": "Consultant ID", + "required": false, + "type": "integer" + }, + { + "name": "call_id", + "in": "query", + "description": "Call ID for tracking", + "required": false, + "type": "integer" + }, + { + "name": "service", + "in": "query", + "description": "Service type (e.g. calls_hold, calls_release)", + "required": false, + "type": "string" + }, + { + "name": "app_name", + "in": "query", + "description": "App label for content type lookup", + "required": false, + "type": "string" + }, + { + "name": "discount_code", + "in": "query", + "description": "Optional discount code (only used in hold/direct)", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Success", + "examples": { + "application/json": { "status": "Coins deducted successfully" } + } + }, + "400": { "description": "Bad request" }, + "403": { "description": "Invalid security token" }, + "404": { "description": "Not found" } + }, + "tags": ["habcoin"] + }, + "parameters": [] + }, + "/habcoin/validate-discount/": { + "post": { + "operationId": "habcoin_validate-discount_create", + "description": "Validate discount code and calculate final price", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["code", "service", "object_id"], + "type": "object", + "properties": { + "code": { + "description": "Discount code", + "type": "string", + "example": "SUMMER20" + }, + "service": { + "description": "Service name (checkup, meet, etc.)", + "type": "string", + "example": "checkup" + }, + "object_id": { + "description": "Object ID (Checkup or Meet ID)", + "type": "integer", + "example": 5 + }, + "app_name": { + "description": "App name (optional)", + "type": "string", + "example": "checkup" + } + } + } + } + ], + "responses": { + "200": { + "description": "Discount code is valid", + "examples": { + "application/json": { + "valid": true, + "original_price": 10.0, + "discounted_price": 8.0, + "discount_amount": 2.0, + "discount_percentage": 20.0, + "message": "Discount code is valid and 20% discount will be applied" + } + } + }, + "400": { + "description": "Invalid discount code", + "examples": { + "application/json": { + "valid": false, + "errors": { "code": ["Discount code has expired"] } + } + } + }, + "401": { "description": "Unauthorized - Authentication required" } + }, + "tags": ["Discount Code"] + }, + "parameters": [] + }, + "/habibmeet/guidelines/": { + "get": { + "operationId": "habibmeet_guidelines_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/": { + "get": { + "operationId": "habibmeet_meets_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "meet_type", + "in": "query", + "description": "Meet Type (e.g., is_free, is_suggested)", + "type": "string" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "Search term", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MeetSerializer" } + } + } + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/archive/{session_id}/": { + "delete": { + "operationId": "habibmeet_meets_archive_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "session_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/habibmeet/meets/create/": { + "post": { + "operationId": "habibmeet_meets_create_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MeetCreate" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/MeetCreate" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/create/v2/": { + "post": { + "operationId": "habibmeet_meets_create_v2_create", + "description": "Create a new meet with access control (public/private) and optional password.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MeetCreateV2" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/MeetCreateV2" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/provider/profile/": { + "post": { + "operationId": "habibmeet_meets_provider_profile_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MeetProviderProfile" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/MeetProviderProfile" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/providers/": { + "get": { + "operationId": "habibmeet_meets_providers_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ProviderMeetSerializer" } + } + } + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/providers/{id}/": { + "get": { + "operationId": "habibmeet_meets_providers_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ProviderDetailMeetSerializer" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Meet Provider Profile.", + "required": true, + "type": "integer" + } + ] + }, + "/habibmeet/meets/reminders/": { + "get": { + "operationId": "habibmeet_meets_reminders_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MeetSerializer" } + } + } + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/room/": { + "get": { + "operationId": "habibmeet_meets_room_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MeetProviderRoom" } + } + } + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/meets/{meet_id}/": { + "get": { + "operationId": "habibmeet_meets_read", + "description": "\nRetrieve detailed information about a specific meet including recordings.\n\nReturns complete meet details with all associated session recordings.\nEach recording includes session information, file details, and metadata.\n\n### Response Structure:\n```json\n{\n \"id\": 174,\n \"name\": \"تست-(Tester)\",\n \"description\": \"Meeting description\",\n \"next_session_subject\": \"Next session topic\",\n \"next_session_schedule\": \"2024-01-01T10:00:00Z\",\n \"is_suggested\": false,\n \"provider\": {\n \"id\": 1,\n \"username\": \"provider_name\",\n \"email\": \"provider@example.com\"\n },\n \"is_free\": true,\n \"price\": \"0.00\",\n \"is_live\": false,\n \"is_closed\": false,\n \"online_users_count\": 0,\n \"language\": \"fa\",\n \"categories\": [],\n \"organizer\": \"Provider Name\",\n \"is_provider\": true,\n \"live_session_id\": null,\n \"has_archive\": true,\n \"recordings\": [\n {\n \"id\": 1,\n \"title\": \"Session Recording\",\n \"file\": \"https://habibapp.com/media/recorded_sessions/recording.mp4\",\n \"file_time\": \"01:30:00\",\n \"recording_type\": \"video\",\n \"created_at\": \"2024-01-01T10:00:00Z\",\n \"session_id\": 548,\n \"session_subject\": \"تلت\"\n }\n ],\n \"access\": \"public\",\n \"password\": null,\n \"has_recording\": true\n}\n```\n\n### Features:\n- Complete meet information\n- All active session recordings included\n- Provider and organizer details\n- Live session status and ID\n- Access control information\n- Recording availability status\n", + "parameters": [ + { + "name": "meet_id", + "in": "path", + "description": "ID of the meet to retrieve details for", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Meet details retrieved successfully", + "schema": { + "type": "object", + "properties": { + "id": { "description": "Meet ID", "type": "integer" }, + "name": { "description": "Meet name", "type": "string" }, + "description": { + "description": "Meet description", + "type": "string" + }, + "next_session_subject": { + "description": "Next session subject", + "type": "string" + }, + "next_session_schedule": { + "description": "Next session schedule", + "type": "string", + "format": "date-time" + }, + "is_suggested": { + "description": "Whether meet is suggested", + "type": "boolean" + }, + "provider": { + "type": "object", + "properties": { + "id": { "description": "Provider ID", "type": "integer" }, + "username": { + "description": "Provider username", + "type": "string" + }, + "email": { + "description": "Provider email", + "type": "string" + } + } + }, + "is_free": { + "description": "Whether meet is free", + "type": "boolean" + }, + "price": { "description": "Meet price", "type": "string" }, + "is_live": { + "description": "Whether meet is currently live", + "type": "boolean" + }, + "is_closed": { + "description": "Whether meet is closed", + "type": "boolean" + }, + "online_users_count": { + "description": "Number of online users", + "type": "integer" + }, + "language": { + "description": "Meet language code", + "type": "string" + }, + "categories": { + "description": "Meet categories", + "type": "array", + "items": { "type": "string" } + }, + "organizer": { + "description": "Organizer name", + "type": "string" + }, + "is_provider": { + "description": "Whether current user is the provider", + "type": "boolean" + }, + "live_session_id": { + "description": "ID of current live session", + "type": "integer", + "nullable": true + }, + "has_archive": { + "description": "Whether meet has archived sessions", + "type": "boolean" + }, + "recordings": { + "description": "List of all active recordings for this meet", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "description": "Recording ID", + "type": "integer" + }, + "title": { + "description": "Recording title", + "type": "string" + }, + "file": { + "description": "Recording file URL", + "type": "string" + }, + "file_time": { + "description": "Recording duration", + "type": "string" + }, + "recording_type": { + "description": "Recording type: voice or video", + "type": "string" + }, + "created_at": { + "description": "Recording creation timestamp", + "type": "string", + "format": "date-time" + }, + "session_id": { + "description": "Associated session ID", + "type": "integer" + }, + "session_subject": { + "description": "Session subject/title", + "type": "string" + } + } + } + }, + "access": { + "description": "Meet access level", + "type": "string" + }, + "password": { + "description": "Meet password if required", + "type": "string", + "nullable": true + }, + "has_recording": { + "description": "Whether meet has any recordings", + "type": "boolean" + } + } + } + }, + "401": { "description": "Authentication required" }, + "403": { "description": "Permission denied" }, + "404": { "description": "Meet not found" } + }, + "tags": ["habibmeet"] + }, + "put": { + "operationId": "habibmeet_meets_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MeetDetailSerializer" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/MeetDetailSerializer" } + } + }, + "tags": ["habibmeet"] + }, + "patch": { + "operationId": "habibmeet_meets_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/MeetDetailSerializer" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/MeetDetailSerializer" } + } + }, + "tags": ["habibmeet"] + }, + "delete": { + "operationId": "habibmeet_meets_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["habibmeet"] + }, + "parameters": [ + { "name": "meet_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibmeet/meets/{meet_id}/archive/": { + "get": { + "operationId": "habibmeet_meets_archive_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SessionArchiveSerializer" } + } + } + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "meet_id", + "in": "path", + "description": "The meet this session belongs to", + "required": true, + "type": "string" + } + ] + }, + "/habibmeet/meets/{meet_id}/close/": { + "post": { + "operationId": "habibmeet_meets_close_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["habibmeet"] + }, + "parameters": [ + { "name": "meet_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibmeet/meets/{meet_id}/reminder/update/": { + "put": { + "operationId": "habibmeet_meets_reminder_update_update", + "description": "Update or create a reminder for a meet with specified active status", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["is_active"], + "type": "object", + "properties": { + "is_active": { + "description": "Whether the reminder is active or not", + "type": "boolean" + } + } + } + } + ], + "responses": { + "200": { + "description": "Reminder status updated successfully", + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + }, + "201": { + "description": "Reminder created with specified status", + "schema": { + "type": "object", + "properties": { "message": { "type": "string" } } + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "type": "object", + "properties": { "detail": { "type": "string" } } + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { "name": "meet_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibmeet/meets/{meet_id}/report/": { + "post": { + "operationId": "habibmeet_meets_report_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReportSerializer" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/ReportSerializer" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "meet_id", + "in": "path", + "description": "Meet being reported on", + "required": true, + "type": "string" + } + ] + }, + "/habibmeet/meets/{meet_id}/schedule/": { + "delete": { + "operationId": "habibmeet_meets_schedule_delete", + "description": "Delete the next session subject and schedule if the meet is not live.\nIf the meet is live, an error is returned. If the next session subject and\nschedule are already empty, an error is returned.", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["habibmeet"] + }, + "parameters": [ + { "name": "meet_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibmeet/meets/{meet_id}/session/": { + "post": { + "operationId": "habibmeet_meets_session_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/SessionCreate" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/SessionCreate" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { "name": "meet_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibmeet/recordings/create/": { + "post": { + "operationId": "habibmeet_recordings_create_create", + "summary": "API endpoint for creating new session recordings.", + "description": "Allows authenticated users to create recordings for sessions.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SessionRecordingCreateUpdateSerializer" + } + } + ], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/SessionRecordingCreateUpdateSerializer" + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [] + }, + "/habibmeet/recordings/{recording_id}/delete/": { + "delete": { + "operationId": "habibmeet_recordings_delete_delete", + "description": "Handle DELETE request with proper error handling and status codes.", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "recording_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/habibmeet/recordings/{recording_id}/update/": { + "put": { + "operationId": "habibmeet_recordings_update_update", + "summary": "API endpoint for updating existing session recordings.", + "description": "Allows authenticated users to update recordings they own.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SessionRecordingCreateUpdateSerializer" + } + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/SessionRecordingCreateUpdateSerializer" + } + } + }, + "tags": ["habibmeet"] + }, + "patch": { + "operationId": "habibmeet_recordings_update_partial_update", + "summary": "API endpoint for updating existing session recordings.", + "description": "Allows authenticated users to update recordings they own.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SessionRecordingCreateUpdateSerializer" + } + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/SessionRecordingCreateUpdateSerializer" + } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "recording_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/habibmeet/sessions/{id}/upload/": { + "put": { + "operationId": "habibmeet_sessions_upload_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/SessionFileUpload" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/SessionFileUpload" } + } + }, + "tags": ["habibmeet"] + }, + "patch": { + "operationId": "habibmeet_sessions_upload_partial_update", + "description": "Upload a file for a specific session.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/SessionFileUpload" } + }, + { + "name": "recorded_file", + "in": "file", + "description": "The file to upload for the session.", + "required": true, + "type": "file" + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/SessionFileUpload" } + } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this session.", + "required": true, + "type": "integer" + } + ] + }, + "/habibmeet/{id}/recordings/": { + "get": { + "operationId": "habibmeet_recordings_list", + "description": "\nRetrieve a list of recorded meeting sessions for a specific meet.\n\nReturns all active session recordings for the specified meet ID with their\nassociated session details, file information, duration, and recording type (voice/video).\n\n### Response Structure:\n```json\n[\n {\n \"id\": 1,\n \"title\": \"Meeting Recording\",\n \"file\": \"https://habibapp.com/media/recorded_sessions/recording.mp4\",\n \"file_time\": \"01:30:00\",\n \"recording_type\": \"video\",\n \"created_at\": \"2024-01-01T10:00:00Z\",\n \"session_id\": 123,\n \"session_subject\": \"Weekly Team Meeting\"\n }\n]\n```\n\n### Features:\n- Only returns active recordings for the specified meet (is_active=True)\n- Includes session information for context\n- Supports filtering and pagination\n- Ordered by creation date (newest first)\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "id", + "in": "path", + "description": "ID of the meet to retrieve recordings for", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "List of session recordings for the specified meet retrieved successfully", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "description": "Recording ID", "type": "integer" }, + "title": { + "description": "Recording title", + "type": "string" + }, + "file": { "description": "File URL", "type": "string" }, + "file_time": { + "description": "Recording duration", + "type": "string" + }, + "recording_type": { + "description": "Type: voice or video", + "type": "string" + }, + "created_at": { + "description": "Creation timestamp", + "type": "string", + "format": "date-time" + }, + "session_id": { + "description": "Associated session ID", + "type": "integer" + }, + "session_subject": { + "description": "Session subject/title", + "type": "string" + } + } + } + } + }, + "401": { "description": "Authentication required" }, + "403": { "description": "Permission denied" }, + "404": { "description": "Meet not found" } + }, + "tags": ["habibmeet"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibnet/centers/": { + "get": { + "operationId": "habibnet_centers_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/CenterList" } + } + } + } + } + }, + "tags": ["habibnet"] + }, + "parameters": [] + }, + "/habibnet/centers/{id}/": { + "get": { + "operationId": "habibnet_centers_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/CenterDetail" } + } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this center.", + "required": true, + "type": "integer" + } + ] + }, + "/habibnet/centers/{id}/events/": { + "get": { + "operationId": "habibnet_centers_events_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/CenterEvent" } + } + } + } + } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibnet/provider/center/": { + "get": { + "operationId": "habibnet_provider_center_read", + "description": "\nRetrieve the center owned by the authenticated provider.\n\n### Requirements:\n- User must be authenticated\n- User must have a verified provider profile\n- Provider must have created a center\n\n### Notes:\n- Each provider can only have one center\n- Returns the provider's center with all details including status\n\n### Response Structure:\nReturns the center details including status, images, and all other information.\n", + "parameters": [], + "responses": { + "200": { + "description": "Center retrieved successfully", + "schema": { + "type": "object", + "properties": { + "id": { "description": "Center ID", "type": "integer" }, + "avatar": { "description": "Avatar URL", "type": "string" }, + "name": { "description": "Center name", "type": "string" }, + "slogan": { "description": "Center slogan", "type": "string" }, + "center_type": { + "description": "Center type", + "type": "string" + }, + "about_center": { + "description": "About center", + "type": "string" + }, + "working_hours": { + "description": "Working hours", + "type": "object" + }, + "social_medias": { + "description": "Social media links", + "type": "array", + "items": { "type": "object" } + }, + "address": { "description": "Address", "type": "string" }, + "lat": { "description": "Latitude", "type": "number" }, + "lon": { "description": "Longitude", "type": "number" }, + "images": { + "description": "Center images", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "image": { "type": "string" }, + "priority": { "type": "integer" } + } + } + }, + "status": { + "description": "Approval status (pending, approved, rejected)", + "type": "string" + }, + "created_at": { "type": "string", "format": "date-time" }, + "updated_at": { "type": "string", "format": "date-time" } + } + }, + "examples": { + "application/json": { + "id": 1, + "avatar": "https://habibapp.com/media/habibnet/avatars/center_avatar.jpg", + "name": "Islamic Center of New York", + "slogan": "Serving the community since 1990", + "center_type": "islamic_center", + "about_center": "A comprehensive Islamic center...", + "working_hours": { + "monday": "9:00 AM - 9:00 PM", + "friday": "9:00 AM - 11:00 PM" + }, + "social_medias": [ + { + "platform": "facebook", + "url": "https://facebook.com/center" + } + ], + "address": "123 Main Street, New York, NY 10001", + "lat": 40.7128, + "lon": -74.006, + "images": [ + { + "id": 1, + "image": "https://habibapp.com/media/habibnet/image1.jpg", + "priority": 1 + } + ], + "status": "pending", + "created_at": "2024-01-15T10:30:00Z", + "updated_at": "2024-01-15T10:30:00Z" + } + } + }, + "401": { "description": "Authentication required" }, + "404": { + "description": "Provider profile or center not found", + "examples": { + "application/json": { + "detail": "No verified provider profile found. Please submit a provider request first." + } + } + } + }, + "tags": ["habibnet"] + }, + "parameters": [] + }, + "/habibnet/provider/center/create/": { + "post": { + "operationId": "habibnet_provider_center_create_create", + "description": "\nCreate a new center for the authenticated provider.\n\n### Requirements:\n- User must be authenticated\n- User must have a verified provider profile\n- Provider profile must be approved\n\n### Request Body:\nThe request should include center details and optionally images.\n\n**IMPORTANT**: Image fields (avatar, images) must be string URLs from the `/habibnet/upload-tmp-media/` endpoint, NOT binary file data.\n\n### Image Upload Workflow:\n1. First upload each image file to `/habibnet/upload-tmp-media/` endpoint\n2. Extract the `file` value from the response (e.g., \"/tmp/xyz-avatar.jpg\")\n3. Use this path string in the center creation request\n\n### Example Request:\n```json\n{\n \"avatar\": \"/tmp/xyz-avatar.jpg\",\n \"name\": \"Islamic Center of New York\",\n \"slogan\": \"Serving the community since 1990\",\n \"center_type\": \"islamic_center\",\n \"about_center\": \"A comprehensive Islamic center offering prayer facilities, educational programs, and community services.\",\n \"working_hours\": {\n \"monday\": \"9:00 AM - 9:00 PM\",\n \"tuesday\": \"9:00 AM - 9:00 PM\",\n \"wednesday\": \"9:00 AM - 9:00 PM\",\n \"thursday\": \"9:00 AM - 9:00 PM\",\n \"friday\": \"9:00 AM - 11:00 PM\",\n \"saturday\": \"9:00 AM - 11:00 PM\",\n \"sunday\": \"9:00 AM - 9:00 PM\"\n },\n \"social_medias\": [\n {\"platform\": \"facebook\", \"url\": \"https://facebook.com/islamiccenter\"},\n {\"platform\": \"instagram\", \"url\": \"https://instagram.com/islamiccenter\"}\n ],\n \"address\": \"123 Main Street, New York, NY 10001\",\n \"lat\": 40.7128,\n \"lon\": -74.0060,\n \"images\": [\n {\"image\": \"/tmp/xyz-image1.jpg\", \"priority\": 1},\n {\"image\": \"/tmp/xyz-image2.jpg\", \"priority\": 2}\n ]\n}\n```\n\n### Response Structure:\nReturns the created center with all details including generated ID and timestamps.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["name", "slogan"], + "type": "object", + "properties": { + "avatar": { + "description": "Avatar image path (string) from temporary upload. First upload to /habibnet/upload-tmp-media/ and use the file value from response.", + "type": "string", + "example": "/tmp/xyz-avatar.jpg" + }, + "name": { + "description": "Center name", + "type": "string", + "example": "Islamic Center of New York" + }, + "slogan": { + "description": "Center slogan or tagline", + "type": "string", + "example": "Serving the community since 1990" + }, + "center_type": { + "description": "Type of center", + "type": "string", + "enum": [ + "islamic_center", + "library", + "mosque", + "shia_center" + ], + "example": "islamic_center" + }, + "about_center": { + "description": "Detailed description about the center", + "type": "string", + "example": "A comprehensive Islamic center offering prayer facilities..." + }, + "working_hours": { + "description": "Working hours for each day of the week", + "type": "object", + "example": { + "monday": "9:00 AM - 9:00 PM", + "friday": "9:00 AM - 11:00 PM" + } + }, + "social_medias": { + "description": "List of social media links", + "type": "array", + "items": { + "type": "object", + "properties": { + "platform": { "type": "string" }, + "url": { "type": "string" } + } + }, + "example": [ + { + "platform": "facebook", + "url": "https://facebook.com/center" + } + ] + }, + "address": { + "description": "Physical address of the center", + "type": "string", + "example": "123 Main Street, New York, NY 10001" + }, + "lat": { + "description": "Latitude coordinate", + "type": "number", + "example": 40.7128 + }, + "lon": { + "description": "Longitude coordinate", + "type": "number", + "example": -74.006 + }, + "images": { + "description": "List of center images. Each image must be a string path from /habibnet/upload-tmp-media/", + "type": "array", + "items": { + "type": "object", + "properties": { + "image": { + "description": "Image path (string) from temporary upload", + "type": "string", + "example": "/tmp/xyz-image.jpg" + }, + "priority": { + "description": "Display priority (higher = shown first)", + "type": "integer", + "default": 10 + } + } + } + } + } + } + } + ], + "responses": { + "201": { + "description": "Center created successfully", + "schema": { + "type": "object", + "properties": { + "id": { "description": "Center ID", "type": "integer" }, + "avatar": { "description": "Avatar URL", "type": "string" }, + "name": { "description": "Center name", "type": "string" }, + "slogan": { "description": "Center slogan", "type": "string" }, + "center_type": { + "description": "Center type", + "type": "string" + }, + "about_center": { + "description": "About center", + "type": "string" + }, + "working_hours": { + "description": "Working hours", + "type": "object" + }, + "social_medias": { + "description": "Social media links", + "type": "array", + "items": { "type": "object" } + }, + "address": { "description": "Address", "type": "string" }, + "lat": { "description": "Latitude", "type": "number" }, + "lon": { "description": "Longitude", "type": "number" }, + "images": { + "description": "Center images", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "image": { "type": "string" }, + "priority": { "type": "integer" } + } + } + }, + "status": { + "description": "Approval status", + "type": "string" + }, + "created_at": { "type": "string", "format": "date-time" }, + "updated_at": { "type": "string", "format": "date-time" } + } + }, + "examples": { + "application/json": { + "id": 1, + "avatar": "https://habibapp.com/media/habibnet/avatars/center_avatar.jpg", + "name": "Islamic Center of New York", + "slogan": "Serving the community since 1990", + "center_type": "islamic_center", + "about_center": "A comprehensive Islamic center...", + "working_hours": { + "monday": "9:00 AM - 9:00 PM", + "friday": "9:00 AM - 11:00 PM" + }, + "social_medias": [ + { + "platform": "facebook", + "url": "https://facebook.com/center" + } + ], + "address": "123 Main Street, New York, NY 10001", + "lat": 40.7128, + "lon": -74.006, + "images": [ + { + "id": 1, + "image": "https://habibapp.com/media/habibnet/image1.jpg", + "priority": 1 + } + ], + "status": "pending", + "created_at": "2024-01-15T10:30:00Z", + "updated_at": "2024-01-15T10:30:00Z" + } + } + }, + "400": { + "description": "Validation error", + "examples": { + "application/json": { + "name": ["This field is required."], + "center_type": [ + "Invalid center type. Must be one of: islamic_center, library, mosque, shia_center" + ] + } + } + }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Provider not verified", + "examples": { + "application/json": { + "detail": "You must have a verified provider profile to create centers." + } + } + } + }, + "tags": ["habibnet"] + }, + "parameters": [] + }, + "/habibnet/provider/center/{center_id}/events/": { + "get": { + "operationId": "habibnet_provider_center_events_list", + "description": "\nList all events for a specific center owned by the provider.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n\n### Response Structure:\nReturns a list of all events for the specified center.\n\n### Example Response:\n```json\n[\n {\n \"id\": 1,\n \"title\": \"Friday Prayer\",\n \"description\": \"Weekly Friday congregational prayer\",\n \"time\": \"1:00 PM\",\n \"start_time\": \"2024-01-19T13:00:00Z\",\n \"end_time\": \"2024-01-19T14:00:00Z\",\n \"date\": \"2024-01-19T13:00:00Z\",\n \"image\": \"https://habibapp.com/media/habibnet/event1.jpg\",\n \"center\": 1\n }\n]\n```\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "center_id", + "in": "path", + "description": "ID of the center to list events for", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "List of center events", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "description": "Event ID", "type": "integer" }, + "title": { "description": "Event title", "type": "string" }, + "description": { + "description": "Event description", + "type": "string" + }, + "time": { + "description": "Event time (text format)", + "type": "string" + }, + "start_time": { + "description": "Start time", + "type": "string", + "format": "date-time" + }, + "end_time": { + "description": "End time", + "type": "string", + "format": "date-time" + }, + "date": { + "description": "Event date", + "type": "string", + "format": "date-time" + }, + "image": { + "description": "Event image URL", + "type": "string" + }, + "center": { "description": "Center ID", "type": "integer" } + } + } + } + }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Not the owner", + "examples": { + "application/json": { + "detail": "You do not have permission to view events for this center." + } + } + }, + "404": { "description": "Center not found" } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "center_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/habibnet/provider/center/{center_id}/events/create/": { + "post": { + "operationId": "habibnet_provider_center_events_create_create", + "description": "\nCreate a new event for a center owned by the provider.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Image must be uploaded via `/habibnet/upload-tmp-media/` endpoint first\n\n**IMPORTANT**: The image field must be a string URL (apath) from the upload endpoint, NOT binary file data.\n\n### Example Request:\n```json\n{\n \"title\": \"Friday Prayer\",\n \"description\": \"Weekly Friday congregational prayer. All community members are welcome.\",\n \"time\": \"1:00 PM\",\n \"start_time\": \"2024-01-19T13:00:00Z\",\n \"end_time\": \"2024-01-19T14:00:00Z\",\n \"date\": \"2024-01-19T13:00:00Z\",\n \"image\": \"/tmp/xyz-event-image.jpg\"\n}\n```\n\n### Response Structure:\nReturns the created event with all details including the full image URL.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["title", "description", "time", "date", "image"], + "type": "object", + "properties": { + "title": { + "description": "Event title", + "type": "string", + "example": "Friday Prayer", + "maxLength": 119 + }, + "description": { + "description": "Detailed event description", + "type": "string", + "example": "Weekly Friday congregational prayer. All community members are welcome." + }, + "time": { + "description": "Event time in text format", + "type": "string", + "example": "1:00 PM", + "maxLength": 255 + }, + "start_time": { + "description": "Event start time (optional)", + "type": "string", + "format": "date-time", + "example": "2024-01-19T13:00:00Z" + }, + "end_time": { + "description": "Event end time (optional)", + "type": "string", + "format": "date-time", + "example": "2024-01-19T14:00:00Z" + }, + "date": { + "description": "Event date", + "type": "string", + "format": "date-time", + "example": "2024-01-19T13:00:00Z" + }, + "image": { + "description": "Event image path from temporary upload", + "type": "string", + "example": "/static/tmp/xyz-event-image.jpg" + } + } + } + }, + { + "name": "center_id", + "in": "path", + "description": "ID of the center to create event for", + "required": true, + "type": "integer" + } + ], + "responses": { + "201": { + "description": "Event created successfully", + "schema": { + "type": "object", + "properties": { + "id": { "description": "Event ID", "type": "integer" }, + "title": { "description": "Event title", "type": "string" }, + "description": { + "description": "Event description", + "type": "string" + }, + "time": { "description": "Event time", "type": "string" }, + "start_time": { + "description": "Start time", + "type": "string", + "format": "date-time" + }, + "end_time": { + "description": "End time", + "type": "string", + "format": "date-time" + }, + "date": { + "description": "Event date", + "type": "string", + "format": "date-time" + }, + "image": { "description": "Event image URL", "type": "string" }, + "center": { "description": "Center ID", "type": "integer" } + } + }, + "examples": { + "application/json": { + "id": 1, + "title": "Friday Prayer", + "description": "Weekly Friday congregational prayer. All community members are welcome.", + "time": "1:00 PM", + "start_time": "2024-01-19T13:00:00Z", + "end_time": "2024-01-19T14:00:00Z", + "date": "2024-01-19T13:00:00Z", + "image": "https://habibapp.com/media/habibnet/event_image.jpg", + "center": 1 + } + } + }, + "400": { + "description": "Validation error", + "examples": { + "application/json": { + "title": ["This field is required."], + "image": ["This field is required."] + } + } + }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Not the owner", + "examples": { + "application/json": { + "detail": "You do not have permission to create events for this center." + } + } + }, + "404": { "description": "Center not found" } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "center_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/habibnet/provider/center/{center_id}/events/{event_id}/": { + "patch": { + "operationId": "habibnet_provider_center_events_partial_update", + "description": "\nUpdate an existing event for a center owned by the provider (PATCH only - partial update).\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Event must belong to the specified center\n\n### Notes:\n- This endpoint supports partial updates (PATCH)\n- Only provided fields will be updated\n- Image can be updated by uploading via `/upload-tmp-media` endpoint first\n\n### Example Request:\n```json\n{\n \"title\": \"Updated Friday Prayer\",\n \"description\": \"Updated description for the weekly Friday prayer\",\n \"start_time\": \"2024-01-19T13:30:00Z\"\n}\n```\n\n### Response Structure:\nReturns the updated event with all current details.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "title": { + "description": "Event title", + "type": "string", + "example": "Updated Friday Prayer", + "maxLength": 119 + }, + "description": { + "description": "Event description", + "type": "string", + "example": "Updated description for the weekly Friday prayer" + }, + "time": { + "description": "Event time in text format", + "type": "string", + "example": "1:30 PM", + "maxLength": 255 + }, + "start_time": { + "description": "Event start time", + "type": "string", + "format": "date-time", + "example": "2024-01-19T13:30:00Z" + }, + "end_time": { + "description": "Event end time", + "type": "string", + "format": "date-time", + "example": "2024-01-19T14:30:00Z" + }, + "date": { + "description": "Event date", + "type": "string", + "format": "date-time", + "example": "2024-01-19T13:30:00Z" + }, + "image": { + "description": "New event image path from temporary upload", + "type": "string", + "example": "/static/tmp/xyz-new-event-image.jpg" + } + } + } + }, + { + "name": "center_id", + "in": "path", + "description": "ID of the center", + "required": true, + "type": "integer" + }, + { + "name": "event_id", + "in": "path", + "description": "ID of the event to update", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "Event updated successfully", + "schema": { + "type": "object", + "properties": { + "id": { "description": "Event ID", "type": "integer" }, + "title": { "description": "Event title", "type": "string" }, + "description": { + "description": "Event description", + "type": "string" + }, + "time": { "description": "Event time", "type": "string" }, + "start_time": { + "description": "Start time", + "type": "string", + "format": "date-time" + }, + "end_time": { + "description": "End time", + "type": "string", + "format": "date-time" + }, + "date": { + "description": "Event date", + "type": "string", + "format": "date-time" + }, + "image": { "description": "Event image URL", "type": "string" }, + "center": { "description": "Center ID", "type": "integer" } + } + }, + "examples": { + "application/json": { + "id": 1, + "title": "Updated Friday Prayer", + "description": "Updated description for the weekly Friday prayer", + "time": "1:30 PM", + "start_time": "2024-01-19T13:30:00Z", + "end_time": "2024-01-19T14:30:00Z", + "date": "2024-01-19T13:30:00Z", + "image": "https://habibapp.com/media/habibnet/event_image.jpg", + "center": 1 + } + } + }, + "400": { + "description": "Validation error", + "examples": { + "application/json": { + "title": ["Ensure this field has no more than 119 characters."] + } + } + }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Not the owner", + "examples": { + "application/json": { + "detail": "You do not have permission to update events for this center." + } + } + }, + "404": { + "description": "Event or center not found", + "examples": { "application/json": { "detail": "Not found." } } + } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "center_id", + "in": "path", + "required": true, + "type": "string" + }, + { "name": "event_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibnet/provider/center/{center_id}/events/{event_id}/delete/": { + "delete": { + "operationId": "habibnet_provider_center_events_delete_delete", + "description": "\nDelete an event for a center owned by the provider.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Event must belong to the specified center\n\n### Notes:\n- This action is permanent and cannot be undone\n- The event will be completely removed from the system\n\n### Response:\nReturns 204 No Content on successful deletion.\n", + "parameters": [ + { + "name": "center_id", + "in": "path", + "description": "ID of the center", + "required": true, + "type": "integer" + }, + { + "name": "event_id", + "in": "path", + "description": "ID of the event to delete", + "required": true, + "type": "integer" + } + ], + "responses": { + "204": { "description": "Event deleted successfully (No Content)" }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Not the owner", + "examples": { + "application/json": { + "detail": "You do not have permission to delete events for this center." + } + } + }, + "404": { + "description": "Event or center not found", + "examples": { "application/json": { "detail": "Not found." } } + } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "center_id", + "in": "path", + "required": true, + "type": "string" + }, + { "name": "event_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibnet/provider/center/{center_id}/images/{image_id}/": { + "delete": { + "operationId": "habibnet_provider_center_images_delete", + "description": "\nDelete a specific image from a center's gallery.\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Image must belong to the specified center\n\n### URL Parameters:\n- `center_id`: ID of the center\n- `image_id`: ID of the image to delete\n\n### Example Response:\n```json\n{\n \"detail\": \"Image deleted successfully\"\n}\n```\n\n### Notes:\n- This permanently deletes the image from storage\n- Cannot be undone\n- The image file is removed from the server\n", + "parameters": [ + { + "name": "center_id", + "in": "path", + "description": "ID of the center", + "required": true, + "type": "integer" + }, + { + "name": "image_id", + "in": "path", + "description": "ID of the image to delete", + "required": true, + "type": "integer" + } + ], + "responses": { + "204": { "description": "Image deleted successfully" }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Not the owner", + "examples": { + "application/json": { + "detail": "You do not have permission to delete this image." + } + } + }, + "404": { + "description": "Image or center not found", + "examples": { + "application/json": { + "detail": "Image not found or does not belong to this center." + } + } + } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "center_id", + "in": "path", + "required": true, + "type": "string" + }, + { "name": "image_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habibnet/provider/center/{id}/": { + "patch": { + "operationId": "habibnet_provider_center_partial_update", + "description": "\nUpdate an existing center (PATCH only - partial update).\n\n### Requirements:\n- User must be authenticated\n- User must be the owner of the center (via provider profile)\n- Only the provider who created the center can update it\n\n### Notes:\n- This endpoint supports partial updates (PATCH)\n- Only provided fields will be updated\n- Images can be added but not removed via this endpoint (use DELETE endpoint for image removal)\n\n### Example Request:\n```json\n{\n \"slogan\": \"Updated slogan for the center\",\n \"about_center\": \"Updated description with more details\",\n \"working_hours\": {\n \"monday\": \"8:00 AM - 10:00 PM\",\n \"friday\": \"8:00 AM - 11:00 PM\"\n }\n}\n```\n\n### Response Structure:\nReturns the updated center with all current details.\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "avatar": { + "description": "New avatar image path from temporary upload", + "type": "string" + }, + "name": { "description": "Center name", "type": "string" }, + "slogan": { "description": "Center slogan", "type": "string" }, + "center_type": { + "description": "Type of center", + "type": "string", + "enum": ["islamic_center", "library", "mosque", "shia_center"] + }, + "about_center": { + "description": "About the center", + "type": "string" + }, + "working_hours": { + "description": "Working hours", + "type": "object" + }, + "social_medias": { + "description": "Social media links", + "type": "array", + "items": { + "type": "object", + "properties": { + "platform": { "type": "string" }, + "url": { "type": "string" } + } + } + }, + "address": { + "description": "Physical address", + "type": "string" + }, + "lat": { "description": "Latitude", "type": "number" }, + "lon": { "description": "Longitude", "type": "number" }, + "images": { + "description": "New images to add", + "type": "array", + "items": { + "type": "object", + "properties": { + "image": { "type": "string" }, + "priority": { "type": "integer", "default": 10 } + } + } + } + } + } + } + ], + "responses": { + "200": { + "description": "Center updated successfully", + "schema": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "avatar": { "type": "string" }, + "name": { "type": "string" }, + "slogan": { "type": "string" }, + "center_type": { "type": "string" }, + "about_center": { "type": "string" }, + "working_hours": { "type": "object" }, + "social_medias": { + "type": "array", + "items": { "type": "object" } + }, + "address": { "type": "string" }, + "lat": { "type": "number" }, + "lon": { "type": "number" }, + "images": { "type": "array", "items": { "type": "object" } }, + "status": { "type": "string" }, + "created_at": { "type": "string", "format": "date-time" }, + "updated_at": { "type": "string", "format": "date-time" } + } + }, + "examples": { + "application/json": { + "id": 1, + "avatar": "https://habibapp.com/media/habibnet/avatars/center_avatar.jpg", + "name": "Islamic Center of New York", + "slogan": "Updated slogan for the center", + "center_type": "islamic_center", + "about_center": "Updated description with more details", + "working_hours": { + "monday": "8:00 AM - 10:00 PM", + "friday": "8:00 AM - 11:00 PM" + }, + "social_medias": [ + { + "platform": "facebook", + "url": "https://facebook.com/center" + } + ], + "address": "123 Main Street, New York, NY 10001", + "lat": 40.7128, + "lon": -74.006, + "images": [], + "status": "pending", + "created_at": "2024-01-15T10:30:00Z", + "updated_at": "2024-01-15T14:20:00Z" + } + } + }, + "400": { "description": "Validation error" }, + "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - Not the owner", + "examples": { + "application/json": { + "detail": "You do not have permission to update this center." + } + } + }, + "404": { "description": "Center not found" } + }, + "tags": ["habibnet"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this center.", + "required": true, + "type": "integer" + } + ] + }, + "/habibnet/provider/profile/": { + "post": { + "operationId": "habibnet_provider_profile_create", + "summary": "API endpoint for creating center provider profiles.", + "description": "This view handles provider requests for centers in Habibnet.\nUsers can request to become providers with two types:\n- management: Part of the center's management team\n- connected: Connected with the center's team", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/CenterProviderProfile" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/CenterProviderProfile" } + } + }, + "tags": ["habibnet"] + }, + "parameters": [] + }, + "/habit/challenge/list/": { + "get": { + "operationId": "habit_challenge_list_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ChallengeList" } + } + } + } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/challenge/{id}/": { + "get": { + "operationId": "habit_challenge_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ChallengeDetail" } + } + }, + "tags": ["habit"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Challenge.", + "required": true, + "type": "integer" + } + ] + }, + "/habit/challenge/{id}/join/": { + "post": { + "operationId": "habit_challenge_join_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["habit"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habit/checklist/create/": { + "post": { + "operationId": "habit_checklist_create_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserChecklistItem" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/UserChecklistItem" } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/checklist/list/": { + "get": { + "operationId": "habit_checklist_list_list", + "description": "category (prayer, quran, duas, worship, challenge, general, custom, all)", + "parameters": [ + { + "name": "category", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/UserChecklistItem" } + } + } + } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/checklist/mark-completed/": { + "get": { + "operationId": "habit_checklist_mark-completed_list", + "description": "\n### ثبت وضعیت تکمیل چک لیست\nاین API وضعیت تکمیل یک چک لیست را برای تاریخ مشخص ثبت میکند. در صورت تکرار درخواست، وضعیت قبلی با تأیید جدید بهروغرسان میشود.\n\n| **فیلد** | **نوع** | **ضروری** | **توضیحات** |\n|----------|---------|-----------|-------------|\n| `checklist_id` | `integer` | بله | شناسه یکتای چک لیست |\n| `date` | `string` | نه | تاریخ در فرمت `YYYY-MM-DD` (پیشفرض: امروز) |\n| `day_of_week` | `string` | بله | روز هفته (مقدارهای مجاز: `monday`, `tuesday`, ..., `sunday`) |\n\n#### پاسخ:\n- **200 OK**: وضعیت تکمیل چک لیست\n- **400 Bad Request**: پارامترهای ورودی نامعتبر\n- **404 Not Found**: چک لیست موردنظر وجود ندارد\n- **500 Internal Server Error**: خطا در پردازش درخواست\n\n#### مثال پاسخ:\n```json\n{\n \"title\": \"تمرین ورزشی\",\n \"completed\": true\n}\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "date", + "in": "query", + "description": "Date in YYYY-MM-DD format", + "required": true, + "type": "string", + "default": "2026-07-01" + }, + { + "name": "checklist_id", + "in": "query", + "description": "Checklist ID", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ChecklistEntryList" } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/checklist/report/": { + "get": { + "operationId": "habit_checklist_report_list", + "description": "\n### آمار تکمیل چک لیست\nاین API آمار تکمیل چک لیست برای دوره های 7، 30 روز و یک سال گذشته را میگرداند. نتایج بر اساس روزهای فعال چک لیست محاسبه میشوند.\n\n| **فیلد** | **نوع** | **ضروری** | **توضیحات** |\n|----------|---------|-----------|-------------|\n| `checklist_id` | `integer` | بله | شناسه یکتای چک لیست |\n| `date` | `string` | نه | تاریخ در فرمت `YYYY-MM-DD` (پیشفرض: امروز) |\n| `day_of_week` | `string` | بله | روز هفته (مقدارهای مجاز: `monday`, `tuesday`, ..., `sunday`) |\n\n#### پاسخ:\n- **200 OK**: آمار تکمیل در فرمت زیر\n- **400 Bad Request**: پارامترهای ورودی نامعتبر\n- **404 Not Found**: چک لیست موردنظر وجود ندارد\n- **500 Internal Server Error**: خطا در پردازش درخواست\n\n#### مثال پاسخ:\n```json\n{\n \"7_days\": {\n \"total_days\": 5,\n \"completed_days\": 3,\n \"percentage\": 60.0\n },\n \"30_days\": {\n \"total_days\": 20,\n \"completed_days\": 15,\n \"percentage\": 75.0\n },\n \"year\": {\n \"total_days\": 365,\n \"completed_days\": 300,\n \"percentage\": 82.2\n }\n}\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "checklist_id", + "in": "query", + "description": "Checklist ID", + "required": true, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ChecklistStats" } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/checklist/{id}/delete/": { + "delete": { + "operationId": "habit_checklist_delete_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["habit"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this User Checklist Item.", + "required": true, + "type": "integer" + } + ] + }, + "/habit/checklist/{id}/detail/": { + "get": { + "operationId": "habit_checklist_detail_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ChecklistDetail" } + } + }, + "tags": ["habit"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/habit/checklist/{id}/update/": { + "put": { + "operationId": "habit_checklist_update_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserChecklistItem" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserChecklistItem" } + } + }, + "tags": ["habit"] + }, + "patch": { + "operationId": "habit_checklist_update_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserChecklistItem" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserChecklistItem" } + } + }, + "tags": ["habit"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this User Checklist Item.", + "required": true, + "type": "integer" + } + ] + }, + "/habit/info/": { + "get": { + "operationId": "habit_info_list", + "summary": "Main Page", + "description": "\n### لیست چک لیست های فعال\nاین API لیست چک لیست های فعال کاربر را برای یک روز هفته و تاریخ خاص میگرداند. تنها چک لیست هایی که در بازه زمانی فعالیت و روزهای مجاز هستند نمایش داده میشوند.\n\n| **فیلد** | **نوع** | **ضروری** | **توضیحات** |\n|----------|---------|-----------|-------------|\n| `date` | `string` | نه | تاریخ در فرمت `YYYY-MM-DD` (پیشفرض: امروز) |\n| `day_of_week` | `string` | بله | روز هفته (مقدارهای مجاز: `monday`, `tuesday`, ..., `sunday`) |\n\n#### پاسخ:\n- **200 OK**: لیست چک لیست ها با وضعیت تکمیل\n- **400 Bad Request**: پارامترهای ورودی نامعتبر\n- **500 Internal Server Error**: خطا در پردازش درخواست\n\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "date", + "in": "query", + "description": "Date in YYYY-MM-DD format", + "required": true, + "type": "string", + "default": "2026-07-01" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/reminder/info/": { + "get": { + "operationId": "habit_reminder_info_list", + "description": "\n### اطلاعات یادآوری چک لیست\nاین API وضعیت یادآوری چک لیست کاربر را بررسی میکند و در صورت وجود یادآوری فعال، اطلاعات کامل آن را برمیگرداند.\n\n#### منطق کسب و کار:\n- بررسی وجود یادآوری چک لیست برای کاربر جاری\n- اگر یادآوری وجود داشته باشد و وضعیت آن فعال باشد: `has_active_reminder: true` و اطلاعات کامل یادآوری\n- اگر یادآوری وجود نداشته باشد یا وضعیت آن غیرفعال باشد: `has_active_reminder: false` و `reminder: null`\n\n#### پاسخ:\n- **200 OK**: اطلاعات یادآوری با موفقیت دریافت شد\n\n#### مثال پاسخ (یادآوری فعال):\n```json\n{\n \"has_active_reminder\": true,\n \"reminder\": {\n \"id\": 123,\n \"service_name\": \"habit\",\n \"object_id\": \"\",\n \"text\": \"Daily Checklist Reminder\",\n \"created_at\": \"2024-01-15T10:30:00Z\",\n \"call_time\": \"2024-01-16T09:00:00Z\",\n \"is_sent\": false,\n \"is_read\": false,\n \"status\": true,\n \"notif_data\": null\n }\n}\n```\n\n#### مثال پاسخ (بدون یادآوری فعال):\n```json\n{\n \"has_active_reminder\": false,\n \"reminder\": null\n}\n```\n", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "اطلاعات یادآوری با موفقیت دریافت شد", + "schema": { + "type": "object", + "properties": { + "has_active_reminder": { + "description": "آیا یادآوری فعال وجود دارد", + "type": "boolean" + }, + "reminder": { + "description": "اطلاعات کامل یادآوری در صورت فعال بودن، در غیر این صورت null", + "type": "object", + "nullable": true + } + } + } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/habit/reminder/update/": { + "put": { + "operationId": "habit_reminder_update_update", + "description": "API endpoint for updating habit reminder status.\nCreates reminder if it doesn't exist, updates if it exists.", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["habit"] + }, + "patch": { + "operationId": "habit_reminder_update_partial_update", + "description": "\nPartially update or create a habit reminder with specified status and optional call time.\n\n### Request Structure (PATCH):\n```json\n{\n \"status\": true, // Required: boolean - Whether reminder is active\n \"call_time\": \"09:30\" // Optional: string - Time in HH:MM format (24-hour)\n}\n```\n\n### Behavior:\n- If reminder doesn't exist: Creates new reminder with provided fields\n- If reminder exists: Updates only the provided fields (partial update)\n- call_time only updates when valid time format is provided (HH:MM)\n- Invalid, empty, or null call_time values are ignored (field remains unchanged)\n\n### Examples:\n- `{\"status\": true}` - Only update status, keep existing call_time\n- `{\"status\": false, \"call_time\": \"14:30\"}` - Update status and set call_time to 14:30\n- `{\"status\": false, \"call_time\": \"\"}` - Only update status, ignore empty call_time\n- `{\"status\": false, \"call_time\": null}` - Only update status, ignore null call_time\n- `{\"status\": true, \"call_time\": \"invalid\"}` - Only update status, ignore invalid time\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["status"], + "type": "object", + "properties": { + "status": { + "description": "Whether the habit reminder is active or not", + "type": "boolean" + }, + "call_time": { + "description": "Time when reminder should be triggered. Format: \"HH:MM\" (24-hour format). Optional - leave empty to clear.", + "type": "string", + "example": "09:30" + } + } + } + } + ], + "responses": { + "200": { + "description": "Reminder status updated successfully", + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "status": { "type": "boolean" } + } + } + }, + "201": { + "description": "Reminder created with specified status", + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "status": { "type": "boolean" } + } + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "type": "object", + "properties": { "detail": { "type": "string" } } + } + } + }, + "tags": ["habit"] + }, + "parameters": [] + }, + "/hadis/categories/": { + "get": { + "operationId": "hadis_categories_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/HadisCategory" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/categories/{category}/": { + "get": { + "operationId": "hadis_categories_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Hadis" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [ + { "name": "category", "in": "path", "required": true, "type": "string" } + ] + }, + "/hadis/events/": { + "get": { + "operationId": "hadis_events_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/interests-items/": { + "get": { + "operationId": "hadis_interests-items_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Interest" } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/narrators/": { + "get": { + "operationId": "hadis_narrators_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Narrator" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/narrators/{id}/": { + "get": { + "operationId": "hadis_narrators_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Hadis" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hadis/resources/": { + "get": { + "operationId": "hadis_resources_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Resources" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/search/{query}/": { + "get": { + "operationId": "hadis_search_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Hadis" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [ + { "name": "query", "in": "path", "required": true, "type": "string" } + ] + }, + "/hadis/stats/": { + "get": { + "operationId": "hadis_stats_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/trends/": { + "get": { + "operationId": "hadis_trends_list", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Trend" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/trends/{trend}/": { + "get": { + "operationId": "hadis_trends_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Hadis" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [ + { "name": "trend", "in": "path", "required": true, "type": "string" } + ] + }, + "/hadis/user-hadises/": { + "get": { + "operationId": "hadis_user-hadises_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Hadis" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/user-interests/": { + "get": { + "operationId": "hadis_user-interests_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserInterest" } + } + }, + "tags": ["hadis"] + }, + "put": { + "operationId": "hadis_user-interests_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserInterest" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserInterest" } + } + }, + "tags": ["hadis"] + }, + "patch": { + "operationId": "hadis_user-interests_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UserInterest" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UserInterest" } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/v2/categories/": { + "get": { + "operationId": "hadis_v2_categories_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/v2/hadis/": { + "get": { + "operationId": "hadis_v2_hadis_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/HadisSerializerV2" } + } + } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/v2/narrators/": { + "get": { + "operationId": "hadis_v2_narrators_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/NarratorSerializerV2" } + } + } + }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/v2/user-daily/": { + "get": { + "operationId": "hadis_v2_user-daily_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/v2/user-hadises/": { + "get": { + "operationId": "hadis_v2_user-hadises_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["hadis"] + }, + "parameters": [] + }, + "/hadis/{id}/": { + "get": { + "operationId": "hadis_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/Hadis" } + } + }, + "tags": ["hadis"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this hadis.", + "required": true, + "type": "integer" + } + ] + }, + "/hussainya/albums-search/": { + "get": { + "operationId": "hussainya_albums-search_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code", + "type": "string" + }, + { + "name": "s", + "in": "query", + "description": "Search term", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/AlbumList" } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/albums/": { + "get": { + "operationId": "hussainya_albums_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "topic_id", + "in": "query", + "description": "Filter by Topic ID", + "type": "integer" + }, + { + "name": "singer_slug", + "in": "query", + "description": "Filter by singer slug", + "type": "string" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "Search term", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/AlbumList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/albums//": { + "get": { + "operationId": "hussainya_albums_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "topic_id", + "in": "query", + "description": "Filter by Topic ID", + "type": "integer" + }, + { + "name": "singer_slug", + "in": "query", + "description": "Filter by singer slug", + "type": "string" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "Search term", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/AlbumList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/albums//{id}/": { + "get": { + "operationId": "hussainya_albums__read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/albums/{id}/": { + "get": { + "operationId": "hussainya_albums_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/albums/{id}/details/": { + "get": { + "operationId": "hussainya_albums_details_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/AlbumList" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/collections/": { + "get": { + "operationId": "hussainya_collections_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/CollectionList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/collections//": { + "get": { + "operationId": "hussainya_collections_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/CollectionList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/collections//{id}/": { + "get": { + "operationId": "hussainya_collections__read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/CollectionDetail" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/collections/{id}/": { + "get": { + "operationId": "hussainya_collections_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/CollectionDetail" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/albums/": { + "get": { + "operationId": "hussainya_dashboard_albums_list", + "summary": "GET — لیست البوم‌ها با فیلترها\nPOST — ایجاد البوم جدید", + "description": "Query params (GET):\n search جستجو در translations (icontains)\n status active | draft\n language_code کدهای زبان جداشده با کاما (fa,ar)\n order hijri → مرتب‌سازی بر اساس نزدیکیِ تاریخ قمری (get_albums_by_hijri_date)؛\n در غیر این صورت ترتیب پیش‌فرض (پین‌شده‌ها، سپس جدیدترین ساخت)\n page / page_size", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardAlbumRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_albums_create", + "summary": "GET — لیست البوم‌ها با فیلترها\nPOST — ایجاد البوم جدید", + "description": "Query params (GET):\n search جستجو در translations (icontains)\n status active | draft\n language_code کدهای زبان جداشده با کاما (fa,ar)\n order hijri → مرتب‌سازی بر اساس نزدیکیِ تاریخ قمری (get_albums_by_hijri_date)؛\n در غیر این صورت ترتیب پیش‌فرض (پین‌شده‌ها، سپس جدیدترین ساخت)\n page / page_size", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardAlbumInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardAlbumInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/albums/{id}/": { + "get": { + "operationId": "hussainya_dashboard_albums_read", + "description": "GET /hussainya/dashboard/albums//\nPATCH /hussainya/dashboard/albums//\nDELETE /hussainya/dashboard/albums//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardAlbumRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_albums_partial_update", + "description": "GET /hussainya/dashboard/albums//\nPATCH /hussainya/dashboard/albums//\nDELETE /hussainya/dashboard/albums//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardAlbumInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardAlbumInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_albums_delete", + "description": "GET /hussainya/dashboard/albums//\nPATCH /hussainya/dashboard/albums//\nDELETE /hussainya/dashboard/albums//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/autocomplete/albums/": { + "get": { + "operationId": "hussainya_dashboard_autocomplete_albums_list", + "description": "GET /hussainya/dashboard/autocomplete/albums/", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/_AlbumAutocomplete" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/autocomplete/genres/": { + "get": { + "operationId": "hussainya_dashboard_autocomplete_genres_list", + "description": "GET /hussainya/dashboard/autocomplete/genres/", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/_GenreAutocomplete" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/autocomplete/publishers/": { + "get": { + "operationId": "hussainya_dashboard_autocomplete_publishers_list", + "description": "GET /hussainya/dashboard/autocomplete/publishers/", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/_PublisherAutocomplete" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/autocomplete/singers/": { + "get": { + "operationId": "hussainya_dashboard_autocomplete_singers_list", + "summary": "GET /hussainya/dashboard/autocomplete/singers/", + "description": "Query params اضافه:\n singer_type madah | lecturer (پیش‌فرض: همه)", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/_SingerAutocomplete" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/autocomplete/songs/": { + "get": { + "operationId": "hussainya_dashboard_autocomplete_songs_list", + "summary": "GET /hussainya/dashboard/autocomplete/songs/", + "description": "پیکرِ آهنگِ فرم «بفرمایید روضه» — جستجوی صفحه‌بندی‌شده در عنوان/اسلاگ.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/_SongAutocomplete" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/autocomplete/tags/": { + "get": { + "operationId": "hussainya_dashboard_autocomplete_tags_list", + "description": "GET /hussainya/dashboard/autocomplete/tags/", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/_TagAutocomplete" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/collections/": { + "get": { + "operationId": "hussainya_dashboard_collections_list", + "summary": "GET — لیست مجموعه‌ها با فیلترها\nPOST — ایجاد مجموعهٔ جدید", + "description": "Query params (GET):\n search جستجو در title (JSONField icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size\n\nترتیب: pin_to_top اول، سپس بقیه بر اساس نزدیکیِ تاریخ قمری به امروز.\nget_collections_by_hijri_date یک list برمی‌گرداند؛ DashboardPageNumberPagination\nبا list هم کار می‌کند (عیناً مثل البوم‌ها).", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardCollectionRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_collections_create", + "summary": "GET — لیست مجموعه‌ها با فیلترها\nPOST — ایجاد مجموعهٔ جدید", + "description": "Query params (GET):\n search جستجو در title (JSONField icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size\n\nترتیب: pin_to_top اول، سپس بقیه بر اساس نزدیکیِ تاریخ قمری به امروز.\nget_collections_by_hijri_date یک list برمی‌گرداند؛ DashboardPageNumberPagination\nبا list هم کار می‌کند (عیناً مثل البوم‌ها).", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardCollectionInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardCollectionInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/collections/{id}/": { + "get": { + "operationId": "hussainya_dashboard_collections_read", + "description": "GET /hussainya/dashboard/collections//\nPATCH /hussainya/dashboard/collections//\nDELETE /hussainya/dashboard/collections//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardCollectionRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_collections_partial_update", + "description": "GET /hussainya/dashboard/collections//\nPATCH /hussainya/dashboard/collections//\nDELETE /hussainya/dashboard/collections//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardCollectionInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardCollectionInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_collections_delete", + "description": "GET /hussainya/dashboard/collections//\nPATCH /hussainya/dashboard/collections//\nDELETE /hussainya/dashboard/collections//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/collections/{id}/songs/": { + "get": { + "operationId": "hussainya_dashboard_collections_songs_list", + "summary": "GET /hussainya/dashboard/collections//songs/?page=&page_size=", + "description": "آهنگ‌های متصل به یک مجموعه — به ترتیب ordering آهنگ و id نزولی.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/discover/": { + "post": { + "operationId": "hussainya_dashboard_discover_create", + "description": "On-demand discovery of a YouTube channel/page into ImportItems.", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/genres/": { + "get": { + "operationId": "hussainya_dashboard_genres_list", + "summary": "GET — لیست ژانرها با فیلترها\nPOST — ایجاد ژانر جدید", + "description": "Query params (GET):\n search جستجو در title/slug (icontains)\n limit / offset", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardGenreRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_genres_create", + "summary": "GET — لیست ژانرها با فیلترها\nPOST — ایجاد ژانر جدید", + "description": "Query params (GET):\n search جستجو در title/slug (icontains)\n limit / offset", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardGenreInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardGenreInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/genres/{id}/": { + "get": { + "operationId": "hussainya_dashboard_genres_read", + "description": "GET /hussainya/dashboard/genres//\nPATCH /hussainya/dashboard/genres//\nDELETE /hussainya/dashboard/genres//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardGenreRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_genres_partial_update", + "description": "GET /hussainya/dashboard/genres//\nPATCH /hussainya/dashboard/genres//\nDELETE /hussainya/dashboard/genres//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardGenreInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardGenreInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_genres_delete", + "description": "GET /hussainya/dashboard/genres//\nPATCH /hussainya/dashboard/genres//\nDELETE /hussainya/dashboard/genres//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/home/albums/": { + "get": { + "operationId": "hussainya_dashboard_home_albums_list", + "description": "GET /hussainya/dashboard/home/albums/?language_code=fa,ar", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/home/lives/": { + "get": { + "operationId": "hussainya_dashboard_home_lives_list", + "description": "GET /hussainya/dashboard/home/lives/?language_code=fa,ar", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/home/maddahs/": { + "get": { + "operationId": "hussainya_dashboard_home_maddahs_list", + "description": "GET /hussainya/dashboard/home/maddahs/?language_code=fa,ar&page=N&page_size=M", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SingersList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/home/popular/": { + "get": { + "operationId": "hussainya_dashboard_home_popular_list", + "summary": "GET /hussainya/dashboard/home/popular/?language_code=fa,ar&page=N&page_size=M", + "description": "محبوب‌ترین آهنگ‌ها برای گریدِ داشبورد، صفحه‌بندی‌شده (infinite scroll).\nAdmin-only؛ از ``language_code`` (تک‌زبانه یا کاما-سپریت) پشتیبانی می‌کند.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/home/speakers/": { + "get": { + "operationId": "hussainya_dashboard_home_speakers_list", + "description": "GET /hussainya/dashboard/home/speakers/?language_code=fa,ar&page=N&page_size=M", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SingersList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/import-items/": { + "get": { + "operationId": "hussainya_dashboard_import-items_list", + "description": "GET صف importها با فیلتر؛ POST ثبت لینک مستقیم و dispatch دریافت متادیتا.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ImportItemRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_import-items_create", + "description": "GET صف importها با فیلتر؛ POST ثبت لینک مستقیم و dispatch دریافت متادیتا.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ImportItemCreate" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/ImportItemCreate" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/import-items/{id}/": { + "get": { + "operationId": "hussainya_dashboard_import-items_read", + "description": "GET جزئیات؛ PATCH اصلاح متادیتای AI؛ DELETE حذف.", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ImportItemDetail" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_import-items_partial_update", + "description": "GET جزئیات؛ PATCH اصلاح متادیتای AI؛ DELETE حذف.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ImportItemMetadata" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ImportItemMetadata" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_import-items_delete", + "description": "GET جزئیات؛ PATCH اصلاح متادیتای AI؛ DELETE حذف.", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this import item.", + "required": true, + "type": "integer" + } + ] + }, + "/hussainya/dashboard/import-items/{id}/cancel/": { + "post": { + "operationId": "hussainya_dashboard_import-items_cancel_create", + "description": "Cancel an item so it is excluded from the active queue.", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/import-items/{id}/publish/": { + "post": { + "operationId": "hussainya_dashboard_import-items_publish_create", + "description": "Manual publish — used for channel/scheduled items after admin approval.", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/import-items/{id}/retry/": { + "post": { + "operationId": "hussainya_dashboard_import-items_retry_create", + "description": "Re-dispatch metadata fetch for a failed/stuck item.", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/import-jobs/": { + "post": { + "operationId": "hussainya_dashboard_import-jobs_create", + "summary": "Batch link submission from the dashboard ``Add links`` panel.", + "description": "Direct links create one ImportItem each (carrying the admin's manual\nmetadata + locked fields) and dispatch metadata fetch; channel/page links\nkick off discovery. Detection falls back to the server when source/kind is\nnot supplied by the client.", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/please/": { + "get": { + "operationId": "hussainya_dashboard_please_list", + "summary": "GET — لیست روضه‌ها با فیلترها\nPOST — ایجاد روضهٔ جدید", + "description": "Query params (GET):\n search جستجو در translations/live_title (icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardPleaseRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_please_create", + "summary": "GET — لیست روضه‌ها با فیلترها\nPOST — ایجاد روضهٔ جدید", + "description": "Query params (GET):\n search جستجو در translations/live_title (icontains)\n status active | draft\n pin_to_top pinned | unpinned\n page / page_size", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardPleaseInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardPleaseInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/please/{id}/": { + "get": { + "operationId": "hussainya_dashboard_please_read", + "description": "GET /hussainya/dashboard/please//\nPATCH /hussainya/dashboard/please//\nDELETE /hussainya/dashboard/please//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardPleaseRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_please_partial_update", + "description": "GET /hussainya/dashboard/please//\nPATCH /hussainya/dashboard/please//\nDELETE /hussainya/dashboard/please//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardPleaseInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardPleaseInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_please_delete", + "description": "GET /hussainya/dashboard/please//\nPATCH /hussainya/dashboard/please//\nDELETE /hussainya/dashboard/please//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/please/{id}/songs/": { + "get": { + "operationId": "hussainya_dashboard_please_songs_list", + "summary": "GET /hussainya/dashboard/please//songs/?page=&page_size=", + "description": "آهنگ‌های متصل به یک روضه — به ترتیب priority و در شکل پخش‌پذیر\n(`SongsListSerializer`، همان شکل آهنگ‌های پنل آلبوم) برای پنل جزئیات.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/publishers/": { + "get": { + "operationId": "hussainya_dashboard_publishers_list", + "summary": "GET — لیست ناشران با فیلترها\nPOST — ایجاد ناشر جدید", + "description": "Query params (GET):\n search جستجو در name (icontains)\n type YT | IT | WS | TG | AP\n language_code کدهای زبان جداشده با کاما (fa,ar)\n page / page_size", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardPublisherRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_publishers_create", + "summary": "GET — لیست ناشران با فیلترها\nPOST — ایجاد ناشر جدید", + "description": "Query params (GET):\n search جستجو در name (icontains)\n type YT | IT | WS | TG | AP\n language_code کدهای زبان جداشده با کاما (fa,ar)\n page / page_size", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardPublisherInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardPublisherInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/publishers/{id}/": { + "get": { + "operationId": "hussainya_dashboard_publishers_read", + "description": "GET /hussainya/dashboard/publishers//\nPATCH /hussainya/dashboard/publishers//\nDELETE /hussainya/dashboard/publishers//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardPublisherRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_publishers_partial_update", + "description": "GET /hussainya/dashboard/publishers//\nPATCH /hussainya/dashboard/publishers//\nDELETE /hussainya/dashboard/publishers//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardPublisherInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardPublisherInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_publishers_delete", + "description": "GET /hussainya/dashboard/publishers//\nPATCH /hussainya/dashboard/publishers//\nDELETE /hussainya/dashboard/publishers//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/runs/": { + "get": { + "operationId": "hussainya_dashboard_runs_list", + "description": "History of discovery runs.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ImportRunRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/search/": { + "get": { + "operationId": "hussainya_dashboard_search_list", + "description": "GET /hussainya/dashboard/search/?q=&types=&limit=", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/singers/": { + "get": { + "operationId": "hussainya_dashboard_singers_list", + "summary": "Management list + create for dashboard maddahs/speakers.", + "description": "GET /hussainya/dashboard/singers/ → لیست با فیلترها\nPOST /hussainya/dashboard/singers/ → ایجاد مداح/سخنران جدید\n\nQuery params (GET):\n - singer_type: all | madah | lecturer\n - status: all | active | draft\n - language_code: comma-separated language codes, e.g. fa,ar\n - search: text matched against translations JSON\n - page / page_size", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardSinger" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_singers_create", + "summary": "Management list + create for dashboard maddahs/speakers.", + "description": "GET /hussainya/dashboard/singers/ → لیست با فیلترها\nPOST /hussainya/dashboard/singers/ → ایجاد مداح/سخنران جدید\n\nQuery params (GET):\n - singer_type: all | madah | lecturer\n - status: all | active | draft\n - language_code: comma-separated language codes, e.g. fa,ar\n - search: text matched against translations JSON\n - page / page_size", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardSingerInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardSingerInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/singers/{identifier}/": { + "get": { + "operationId": "hussainya_dashboard_singers_read", + "summary": "Detail / update / delete for one dashboard singer/provider.", + "description": "GET /hussainya/dashboard/singers//\nPATCH /hussainya/dashboard/singers//\nDELETE /hussainya/dashboard/singers//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardSinger" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_singers_partial_update", + "summary": "Detail / update / delete for one dashboard singer/provider.", + "description": "GET /hussainya/dashboard/singers//\nPATCH /hussainya/dashboard/singers//\nDELETE /hussainya/dashboard/singers//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardSingerInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardSingerInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_singers_delete", + "summary": "Detail / update / delete for one dashboard singer/provider.", + "description": "GET /hussainya/dashboard/singers//\nPATCH /hussainya/dashboard/singers//\nDELETE /hussainya/dashboard/singers//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/hussainya/dashboard/songs/": { + "get": { + "operationId": "hussainya_dashboard_songs_list", + "summary": "GET — لیست آهنگ‌ها با فیلترها\nPOST — ایجاد آهنگ جدید", + "description": "Query params (GET):\n search جستجو در عنوان (JSONField)\n genre id ژانر\n song_type audio | video | youtube\n singers idهای خواننده، جداشده با کاما (فیلتر دقیق)\n status active | draft\n singer_type madah | lecturer (فیلتر از طریق سینگرها)\n language_code کد زبان با کاما (fa,ar)\n page / page_size", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardSongRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_songs_create", + "summary": "GET — لیست آهنگ‌ها با فیلترها\nPOST — ایجاد آهنگ جدید", + "description": "Query params (GET):\n search جستجو در عنوان (JSONField)\n genre id ژانر\n song_type audio | video | youtube\n singers idهای خواننده، جداشده با کاما (فیلتر دقیق)\n status active | draft\n singer_type madah | lecturer (فیلتر از طریق سینگرها)\n language_code کد زبان با کاما (fa,ar)\n page / page_size", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardSongInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardSongInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/songs/{identifier}/": { + "get": { + "operationId": "hussainya_dashboard_songs_read", + "description": "GET /hussainya/dashboard/songs//\nPATCH /hussainya/dashboard/songs//\nDELETE /hussainya/dashboard/songs//\n\nشناسه می‌تواند id عددی (از جدول مدیریت) یا slug (از کارت‌های صفحهٔ خانه/جستجو)\nباشد؛ هم‌رفتار با DashboardSingerDetailView. این‌طور پنل آهنگ همیشه با یک API\nواحد دیتای کامل (تصویر + فایل) را می‌گیرد، چه از جدول باز شود چه از خانه.", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardSongRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_songs_partial_update", + "description": "GET /hussainya/dashboard/songs//\nPATCH /hussainya/dashboard/songs//\nDELETE /hussainya/dashboard/songs//\n\nشناسه می‌تواند id عددی (از جدول مدیریت) یا slug (از کارت‌های صفحهٔ خانه/جستجو)\nباشد؛ هم‌رفتار با DashboardSingerDetailView. این‌طور پنل آهنگ همیشه با یک API\nواحد دیتای کامل (تصویر + فایل) را می‌گیرد، چه از جدول باز شود چه از خانه.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardSongInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardSongInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_songs_delete", + "description": "GET /hussainya/dashboard/songs//\nPATCH /hussainya/dashboard/songs//\nDELETE /hussainya/dashboard/songs//\n\nشناسه می‌تواند id عددی (از جدول مدیریت) یا slug (از کارت‌های صفحهٔ خانه/جستجو)\nباشد؛ هم‌رفتار با DashboardSingerDetailView. این‌طور پنل آهنگ همیشه با یک API\nواحد دیتای کامل (تصویر + فایل) را می‌گیرد، چه از جدول باز شود چه از خانه.", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "identifier", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/hussainya/dashboard/source-tasks/": { + "get": { + "operationId": "hussainya_dashboard_source-tasks_list", + "description": "CRUD list/create for periodic channel watchers.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ImportSourceTaskRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_source-tasks_create", + "description": "CRUD list/create for periodic channel watchers.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ImportSourceTaskInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/ImportSourceTaskInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/source-tasks/{id}/": { + "get": { + "operationId": "hussainya_dashboard_source-tasks_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ImportSourceTaskRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_source-tasks_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ImportSourceTaskInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ImportSourceTaskInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_source-tasks_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this import source task.", + "required": true, + "type": "integer" + } + ] + }, + "/hussainya/dashboard/source-tasks/{id}/run-now/": { + "post": { + "operationId": "hussainya_dashboard_source-tasks_run-now_create", + "description": "Trigger a periodic task's discovery immediately (admin 'run now').", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/tags/": { + "get": { + "operationId": "hussainya_dashboard_tags_list", + "summary": "GET — لیست تگ‌ها با فیلترها\nPOST — ایجاد تگ جدید", + "description": "Query params (GET):\n search جستجو در title/translations\n page / page_size", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DashboardTagRow" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "post": { + "operationId": "hussainya_dashboard_tags_create", + "summary": "GET — لیست تگ‌ها با فیلترها\nPOST — ایجاد تگ جدید", + "description": "Query params (GET):\n search جستجو در title/translations\n page / page_size", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardTagInput" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardTagInput" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/dashboard/tags/{id}/": { + "get": { + "operationId": "hussainya_dashboard_tags_read", + "description": "GET /hussainya/dashboard/tags//\nPATCH /hussainya/dashboard/tags//\nDELETE /hussainya/dashboard/tags//", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardTagRow" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_dashboard_tags_partial_update", + "description": "GET /hussainya/dashboard/tags//\nPATCH /hussainya/dashboard/tags//\nDELETE /hussainya/dashboard/tags//", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/DashboardTagInput" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DashboardTagInput" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_dashboard_tags_delete", + "description": "GET /hussainya/dashboard/tags//\nPATCH /hussainya/dashboard/tags//\nDELETE /hussainya/dashboard/tags//", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/dashboard/upload-media/": { + "post": { + "operationId": "hussainya_dashboard_upload-media_create", + "description": "آپلود فایل موقت برای فرم‌های داشبورد — admin-only.", + "parameters": [ + { "name": "file", "in": "formData", "required": true, "type": "file" } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/_Upload" } + } + }, + "consumes": [ + "multipart/form-data", + "application/x-www-form-urlencoded" + ], + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/genre-list/": { + "get": { + "operationId": "hussainya_genre-list_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/get-youtube-info/": { + "post": { + "operationId": "hussainya_get-youtube-info_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { "youtube_link": { "type": "string" } } + } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/YoutubeInfo" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/lives/": { + "get": { + "operationId": "hussainya_lives_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ShrineLive" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/playlist/": { + "get": { + "operationId": "hussainya_playlist_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/playlist//": { + "get": { + "operationId": "hussainya_playlist_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/provider/profile/": { + "post": { + "operationId": "hussainya_provider_profile_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/HussainiyaProviderProfileSerializer" + } + } + ], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/HussainiyaProviderProfileSerializer" + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/provider/songs/": { + "get": { + "operationId": "hussainya_provider_songs_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/provider/songs/create/": { + "post": { + "operationId": "hussainya_provider_songs_create_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/CreateSong" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/CreateSong" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/provider/songs/{slug}/": { + "put": { + "operationId": "hussainya_provider_songs_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UpdateSong" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UpdateSong" } + } + }, + "tags": ["hussainya"] + }, + "patch": { + "operationId": "hussainya_provider_songs_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/UpdateSong" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/UpdateSong" } + } + }, + "tags": ["hussainya"] + }, + "delete": { + "operationId": "hussainya_provider_songs_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/publishers/": { + "get": { + "operationId": "hussainya_publishers_list", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Publisher" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/publishers//": { + "get": { + "operationId": "hussainya_publishers_list", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Publisher" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/publishers//{id}/": { + "get": { + "operationId": "hussainya_publishers__read", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "ordering", + "in": "query", + "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", + "type": "string", + "enum": [ + "like_counts", + "-like_counts", + "view_count", + "-view_count", + "created_at", + "-created_at", + "published_date", + "-published_date" + ] + }, + { + "name": "song_type", + "in": "query", + "description": "Filter by song type (audio, video, youtube)", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + { + "name": "genre_id", + "in": "query", + "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", + "type": "string" + }, + { + "name": "random", + "in": "query", + "description": "Filter Random Palyer", + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/publishers/{id}/": { + "get": { + "operationId": "hussainya_publishers_read", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "ordering", + "in": "query", + "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", + "type": "string", + "enum": [ + "like_counts", + "-like_counts", + "view_count", + "-view_count", + "created_at", + "-created_at", + "published_date", + "-published_date" + ] + }, + { + "name": "song_type", + "in": "query", + "description": "Filter by song type (audio, video, youtube)", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + { + "name": "genre_id", + "in": "query", + "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", + "type": "string" + }, + { + "name": "random", + "in": "query", + "description": "Filter Random Palyer", + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/pwa/collections/": { + "get": { + "operationId": "hussainya_pwa_collections_list", + "summary": "Unified collection list for the PWA home (``pwa/collections``).", + "description": "Returns one flat list where the **user's own** collections\n(``PlaylistCollection``) come first, followed by the **public**\ncollections (``Collection``). The response shape is identical for both\nsources — ``{id, title, songs}`` — with no ``type`` field.", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/pwa/home/": { + "get": { + "operationId": "hussainya_pwa_home_list", + "summary": "PWA home — the same payload as ``HomePageV3`` but only the\nmadah / lecturer / event sections.", + "description": "These three sections carry no per-user data (the singer/album serializers\nhave no ``is_liked``/``is_playlist`` fields), so the payload is fully\nshareable. It is cached per language under its own key and served without\nthe per-user ``personalize`` step.\n\nEach section also exposes a stable ``key`` alongside the (translated)\n``title`` so the client can identify sections without depending on the\nlocalized title string.", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/pwa/playlist/collections/": { + "get": { + "operationId": "hussainya_pwa_playlist_collections_list", + "summary": "Collection list for the PWA **playlist tab** (``pwa/playlist/collections``).", + "description": "Differs from ``PWACollectionsView`` (home) in three ways:\n * **lightweight** — metadata only, no embedded songs, so it is cheap and\n paginated;\n * **keeps empty collections** — a freshly created user collection with no\n songs must still appear;\n * **paginated** — ``DashboardPageNumberPagination`` (``page``/``page_size``).", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/PlaylistTabCollection" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/pwa/playlist/collections/{cid}/songs/": { + "get": { + "operationId": "hussainya_pwa_playlist_collections_songs_list", + "summary": "Songs of a single playlist-tab collection — unified across both sources.", + "description": "The ``cid`` path arg is the **prefixed** id used everywhere in the PWA:\n * ``u`` → user collection (``PlaylistCollection`` via ``Playlist``);\n * ``p`` → public collection (``Collection.get_songs``).\n\nBoth branches are language-ordered (same priority as the home popular row),\nannotated with per-user ``is_liked``, prefetched against N+1, paginated, and\nserialized with ``SongsListSerializer``. An empty collection returns an empty\npage (200), never 404.", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "page_size", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "cid", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/singers-search/": { + "get": { + "operationId": "hussainya_singers-search_list", + "description": "", + "parameters": [ + { + "name": "s", + "in": "query", + "description": "Search", + "type": "string" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code", + "type": "string" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/singers/": { + "get": { + "operationId": "hussainya_singers_list", + "description": "Advanced Singer List API with PostgreSQL-optimized search functionality", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "singer_type", + "in": "query", + "description": "Singer Type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + { + "name": "search", + "in": "query", + "description": "Search term", + "type": "string" + }, + { + "name": "album_id", + "in": "query", + "description": "Album ID", + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SingersList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/singers//": { + "get": { + "operationId": "hussainya_singers_list", + "description": "Advanced Singer List API with PostgreSQL-optimized search functionality", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "singer_type", + "in": "query", + "description": "Singer Type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + { + "name": "search", + "in": "query", + "description": "Search term", + "type": "string" + }, + { + "name": "album_id", + "in": "query", + "description": "Album ID", + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SingersList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/singers//{slug}/": { + "get": { + "operationId": "hussainya_singers__read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/SingerSong" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/singers/{slug}/": { + "get": { + "operationId": "hussainya_singers_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/SingerSong" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/": { + "get": { + "operationId": "hussainya_songs_list", + "description": "ordering : ('like_count', 'view_count','created_at', 'published_date')", + "parameters": [ + { + "name": "song_type", + "in": "query", + "description": "Filter by song type (audio, video, youtube)", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "ordering", + "in": "query", + "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", + "type": "string", + "enum": [ + "like_counts", + "-like_counts", + "view_count", + "-view_count", + "created_at", + "-created_at", + "published_date", + "-published_date" + ] + }, + { + "name": "genre_id", + "in": "query", + "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", + "type": "string" + }, + { + "name": "random", + "in": "query", + "description": "Filter Random Palyer", + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/songs//": { + "get": { + "operationId": "hussainya_songs_list", + "description": "ordering : ('like_count', 'view_count','created_at', 'published_date')", + "parameters": [ + { + "name": "song_type", + "in": "query", + "description": "Filter by song type (audio, video, youtube)", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "ordering", + "in": "query", + "description": "Order fields by (created_at, -created_at (desc) | view_count, like_count, published_date", + "type": "string", + "enum": [ + "like_counts", + "-like_counts", + "view_count", + "-view_count", + "created_at", + "-created_at", + "published_date", + "-published_date" + ] + }, + { + "name": "genre_id", + "in": "query", + "description": "Filter genre_id ['1-(مداحی)', '2-(سخنرانی)', '3-(سخنرانی کوتاه)', '4-(مولودی)', '5-(ادعیه)', '6-(مناجات)', '7-(مقتل)', '8-(روضه)']]", + "type": "string" + }, + { + "name": "random", + "in": "query", + "description": "Filter Random Palyer", + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/songs//download/{slug}/": { + "get": { + "operationId": "hussainya_songs__download_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs//increase-view/{slug}/": { + "get": { + "operationId": "hussainya_songs__increase-view_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs//like/{slug}/": { + "get": { + "operationId": "hussainya_songs__like_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs//unlike/{slug}/": { + "get": { + "operationId": "hussainya_songs__unlike_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs//{slug}/": { + "get": { + "operationId": "hussainya_songs__read", + "description": "song details api\n-- params: song slug", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/SongDetail" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/add-to-playlist/{slug}/": { + "get": { + "operationId": "hussainya_songs_add-to-playlist_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/download/{slug}/": { + "get": { + "operationId": "hussainya_songs_download_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/increase-view/{slug}/": { + "get": { + "operationId": "hussainya_songs_increase-view_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/like/{slug}/": { + "get": { + "operationId": "hussainya_songs_like_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/recent/": { + "get": { + "operationId": "hussainya_songs_recent_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "days", + "in": "query", + "description": "Number of days to filter recent songs", + "type": "integer", + "default": 60 + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/songs/remove-from-playlist/{slug}/": { + "get": { + "operationId": "hussainya_songs_remove-from-playlist_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/unlike/{slug}/": { + "get": { + "operationId": "hussainya_songs_unlike_read", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/songs/{slug}/": { + "get": { + "operationId": "hussainya_songs_read", + "description": "song details api\n-- params: song slug", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/SongDetail" } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/statistics/": { + "get": { + "operationId": "hussainya_statistics_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/statistics//": { + "get": { + "operationId": "hussainya_statistics_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/topics/{topic_id}/albums/": { + "get": { + "operationId": "hussainya_topics_albums_list", + "description": "Return albums belonging to a specific topic using topic_id in path.", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, ar)", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/AlbumList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "topic_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v2/albums//{id}/": { + "get": { + "operationId": "hussainya_v2_albums__read", + "description": "", + "parameters": [ + { + "name": "singer_type", + "in": "query", + "description": "Type of singers to filter (lecture, madah, singer)", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "type", + "in": "query", + "description": "Type of songs to filter (audio, video, youtube)", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "singer_slug", + "in": "query", + "description": "Comma-separated SingerSlug (e.g, mahmoud-karimi-2, huseyn-taheri) Slugs", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v2/albums/{id}/": { + "get": { + "operationId": "hussainya_v2_albums_read", + "description": "", + "parameters": [ + { + "name": "singer_type", + "in": "query", + "description": "Type of singers to filter (lecture, madah, singer)", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "type", + "in": "query", + "description": "Type of songs to filter (audio, video, youtube)", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + }, + { + "name": "singer_slug", + "in": "query", + "description": "Comma-separated SingerSlug (e.g, mahmoud-karimi-2, huseyn-taheri) Slugs", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v2/collections//{id}/": { + "get": { + "operationId": "hussainya_v2_collections__read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v2/collections/{id}/": { + "get": { + "operationId": "hussainya_v2_collections_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v2/home/": { + "get": { + "operationId": "hussainya_v2_home_list", + "description": "home page API", + "parameters": [ + { + "name": "hijri-date", + "in": "query", + "description": "eg. 01/09 (MONTH/DAY) ", + "type": "string" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/v2/playlist/add/": { + "post": { + "operationId": "hussainya_v2_playlist_add_create", + "description": "افزودن آهنگ به پلی لیست در کالکشن", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/v2/playlist/collections/create/": { + "post": { + "operationId": "hussainya_v2_playlist_collections_create_create", + "description": "ایجاد کالکشن جدید", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/v2/playlist/collections/list/": { + "get": { + "operationId": "hussainya_v2_playlist_collections_list_list", + "description": "لیست کالکشن‌های کاربر با قابلیت سرچ", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/hussainya/v2/playlist/collections/{collection_id}/delete/": { + "delete": { + "operationId": "hussainya_v2_playlist_collections_delete_delete", + "description": "حذف کالکشن", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "collection_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/hussainya/v2/playlist/collections/{collection_id}/songs/": { + "get": { + "operationId": "hussainya_v2_playlist_collections_songs_list", + "description": "لیست آهنگ‌های یک کالکشن با قابلیت سرچ", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "collection_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/hussainya/v2/playlist/collections/{collection_id}/update/": { + "patch": { + "operationId": "hussainya_v2_playlist_collections_update_partial_update", + "description": "آپدیت نام کالکشن", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [ + { + "name": "collection_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/hussainya/v2/singers//{slug}/": { + "get": { + "operationId": "hussainya_v2_singers__read", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "album_id", + "in": "query", + "description": "Comma-separated Album IDs(e.g, 733, 530)", + "type": "string" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v2/singers/{slug}/": { + "get": { + "operationId": "hussainya_v2_singers_read", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "album_id", + "in": "query", + "description": "Comma-separated Album IDs(e.g, 733, 530)", + "type": "string" + }, + { + "name": "language_code", + "in": "query", + "description": "Language Code (e.g., en, fa, es)", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/SongsList" } + } + } + } + } + }, + "tags": ["hussainya"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/hussainya/v3/home/": { + "get": { + "operationId": "hussainya_v3_home_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["hussainya"] + }, + "parameters": [] + }, + "/important-notices/": { + "get": { + "operationId": "important-notices_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/ImportantNotice" } + } + } + } + } + }, + "tags": ["important-notices"] + }, + "parameters": [] + }, + "/khatm/groups/": { + "get": { + "operationId": "khatm_groups_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Filter to show only the groups page", + "type": "string", + "enum": ["created", "joined"] + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/GroupKhatm" } + } + } + } + } + }, + "tags": ["khatm"] + }, + "post": { + "operationId": "khatm_groups_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + }, + "tags": ["khatm"] + }, + "parameters": [] + }, + "/khatm/groups/{slug}/": { + "get": { + "operationId": "khatm_groups_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + }, + "tags": ["khatm"] + }, + "put": { + "operationId": "khatm_groups_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + }, + "tags": ["khatm"] + }, + "patch": { + "operationId": "khatm_groups_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/GroupKhatm" } + } + }, + "tags": ["khatm"] + }, + "delete": { + "operationId": "khatm_groups_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["khatm"] + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "type": "string", + "format": "slug", + "pattern": "^[-\\w]+$" + } + ] + }, + "/khatm/groups/{slug}/join/": { + "post": { + "operationId": "khatm_groups_join_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["pages_count"], + "type": "object", + "properties": { + "pages_count": { + "description": "Number of pages to read", + "type": "integer" + } + } + } + } + ], + "responses": { + "201": { + "description": "", + "schema": { + "required": ["pages_count"], + "type": "object", + "properties": { + "pages_count": { + "description": "Number of pages to read", + "type": "integer" + } + } + } + } + }, + "tags": ["khatm"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/khatm/groups/{slug}/read-page/": { + "put": { + "operationId": "khatm_groups_read-page_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReadPage" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ReadPage" } + } + }, + "tags": ["khatm"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/khatm/individuals/": { + "get": { + "operationId": "khatm_individuals_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/IndividualKhatm" } + } + } + }, + "tags": ["khatm"] + }, + "post": { + "operationId": "khatm_individuals_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/IndividualKhatm" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/IndividualKhatm" } + } + }, + "tags": ["khatm"] + }, + "parameters": [] + }, + "/khatm/individuals/{slug}/": { + "put": { + "operationId": "khatm_individuals_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/IndividualKhatmUpdate" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/IndividualKhatmUpdate" } + } + }, + "tags": ["khatm"] + }, + "patch": { + "operationId": "khatm_individuals_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/IndividualKhatmUpdate" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/IndividualKhatmUpdate" } + } + }, + "tags": ["khatm"] + }, + "delete": { + "operationId": "khatm_individuals_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["khatm"] + }, + "parameters": [ + { + "name": "slug", + "in": "path", + "required": true, + "type": "string", + "format": "slug", + "pattern": "^[-\\w]+$" + } + ] + }, + "/khatm/individuals/{slug}/read-page/": { + "put": { + "operationId": "khatm_individuals_read-page_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/IndividualReadPage" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/IndividualReadPage" } + } + }, + "tags": ["khatm"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/khatm/joined-groups/": { + "get": { + "operationId": "khatm_joined-groups_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/UserGroupKhatm" } + } + } + }, + "tags": ["khatm"] + }, + "parameters": [] + }, + "/library/banner-bottom/": { + "get": { + "operationId": "library_banner-bottom_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/BannerList" } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/banner/": { + "get": { + "operationId": "library_banner_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/BannerList" } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/banner/{id}/": { + "get": { + "operationId": "library_banner_read", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookList" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/bookmark/": { + "get": { + "operationId": "library_bookmark_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookmarkSerializers" } + } + } + } + } + }, + "tags": ["library"] + }, + "post": { + "operationId": "library_bookmark_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/BookmarkSerializers" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/BookmarkSerializers" } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/bookmark/remove/{slug}/": { + "post": { + "operationId": "library_bookmark_remove_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/": { + "get": { + "operationId": "library_books_list", + "description": "", + "parameters": [ + { + "name": "audio", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "nonfree", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "publisher", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "authors", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "category", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "order", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookList" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/books/editorsuggestions/": { + "get": { + "operationId": "library_books_editorsuggestions_list", + "description": "", + "parameters": [ + { + "name": "audio", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "nonfree", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "publisher", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "authors", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "category", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "order", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/BookListSerializerEditorSuggestion" + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/books/rate/{slug}/": { + "post": { + "operationId": "library_books_rate_create", + "summary": "Rate a book", + "description": "Allows users to rate a book and optionally provide a note about the book.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["rate"], + "type": "object", + "properties": { + "rate": { + "description": "Rating for the book (0 to 10)", + "type": "integer", + "example": 8 + }, + "note": { + "description": "Optional note about the book (max 512 characters)", + "type": "string", + "example": "This book was amazing!" + } + } + } + }, + { + "name": "slug", + "in": "path", + "description": "Slug of the book to be rated", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Rate submitted successfully", + "examples": { + "application/json": { + "status": true, + "message": "rate submitted" + } + } + }, + "400": { + "description": "Invalid input or book not found", + "examples": { + "application/json": { + "status": false, + "message": "rate must be between 0 and 10" + } + } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/user-downloads/": { + "get": { + "operationId": "library_books_user-downloads_list", + "summary": "Redesign v2", + "description": "", + "parameters": [ + { + "name": "audio", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "nonfree", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "publisher", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "authors", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "category", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "order", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookListV2" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/books/{slug}/": { + "get": { + "operationId": "library_books_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/BookDetail" } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/{slug}/download/": { + "post": { + "operationId": "library_books_download_create", + "summary": "Redesign v2", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/{slug}/purchase/": { + "post": { + "operationId": "library_books_purchase_create", + "description": "", + "parameters": [], + "responses": { "201": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/{slug}/rates/": { + "get": { + "operationId": "library_books_rates_list", + "summary": "Redesign v2", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/UserRate" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/{slug}/related/": { + "get": { + "operationId": "library_books_related_list", + "description": "", + "parameters": [ + { + "name": "audio", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "nonfree", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "publisher", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "authors", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "category", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "order", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookList" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/books/{slug}/v2/": { + "get": { + "operationId": "library_books_v2_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/BookDetail" } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/category/": { + "get": { + "operationId": "library_category_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Category" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/getFilters/": { + "get": { + "operationId": "library_getFilters_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publish/authors-list/": { + "get": { + "operationId": "library_publish_authors-list_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publish/categories-list/": { + "get": { + "operationId": "library_publish_categories-list_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publish/create/": { + "post": { + "operationId": "library_publish_create_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/CreateBook" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/CreateBook" } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publish/narrators-list/": { + "get": { + "operationId": "library_publish_narrators-list_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publish/tags-search/": { + "get": { + "operationId": "library_publish_tags-search_list", + "description": "", + "parameters": [ + { + "name": "s", + "in": "query", + "description": "Search by name", + "type": "string" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publish/translators-list/": { + "get": { + "operationId": "library_publish_translators-list_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/publishers/": { + "get": { + "operationId": "library_publishers_list", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/PublisherList" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/statistics/": { + "get": { + "operationId": "library_statistics_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/v2/banner/{id}/": { + "get": { + "operationId": "library_v2_banner_read", + "summary": "Redesign v2", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookListV2" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/v2/books/": { + "get": { + "operationId": "library_v2_books_list", + "description": "", + "parameters": [ + { + "name": "audio", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "nonfree", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "size", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "publisher", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "authors", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "category", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "order", + "in": "query", + "description": "", + "required": false, + "type": "string" + }, + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/BookListV2" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/library/v2/books/{slug}/": { + "get": { + "operationId": "library_v2_books_read", + "summary": "Redesign v2", + "description": "\n# 📘 Scenario 1\n اگر مقدار قیمت \n price کتاب\n برابر با صفر بود آن کتاب رایگان است در غیر این صورت اگر بیشتر از صفر بود\n دو مقدار discount_percentage و final_price\n هم بایستی در نظر گرفته شود که نشان دهنده مقدار درصد تخفیف و قیمت نهایی با تخفیف محاسبه شده است\n\n# 📘 Scenario 2\n اگر کاربر قصد خرید یا دانلود کتاب را داشت بایستی قبل از آن api \n دانلود کتاب فراخوانی شود \n library/books/ slug book /download/\n\n سپس اگر کتاب غیر رایگان بود به api مربوطه در سرویس حبیب کوین\n برای پرداخت هزینه کوین کتاب بایستی فراخوانی شود که مقدار نام سرویس برابر با \n book است\n و مقدار ابجکت ایدی برابر با ایدی این کتاب است \n\n## (دقت داشته باشید که اگر کتاب غیر رایگان بود ابتدا بایستی خریداری شود سپس دانلود شود)\n\n\n\n\n# مقادیر\n\n برمیگردان جزعیات یک کتاب را به وسیله اسلاگ آن کتاب,\n مقدار is_bookmark مشخص میکند کاربر این کتاب را بوک مارک کرده است bool,\n مقدار is_download مشخص میکند کاربر این کتاب را دانلود کرده است bool,\n\n مقدار user_rate که یک ابجکت از rate که مشخص کننده rate همین کتاب است به همراه مقدار user_rate که مشخص کننده مقدار rate است که کاربر داده است و ممکن است null هم باشد که ساختار آن مانند:\n\n ```json\n \"rates\": {\n \"rate\": 4,\n \"user_rate\": {\n \"note\": \"This book was amazing!\",\n \"rate\": 3\n }\n ```\n\n\n", + "parameters": [], + "responses": { + "200": { + "description": "Successful retrieval of book details.", + "schema": { "$ref": "#/definitions/BookDetailV2" } + }, + "401": { + "description": "Unauthorized. Authentication credentials were not provided or are invalid." + }, + "404": { + "description": "Not Found. The book with the given slug does not exist." + } + }, + "tags": ["library"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/library/writers/": { + "get": { + "operationId": "library_writers_list", + "description": "", + "parameters": [ + { + "name": "search", + "in": "query", + "description": "A search term.", + "required": false, + "type": "string" + }, + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/AuthorList" } + } + } + } + } + }, + "tags": ["library"] + }, + "parameters": [] + }, + "/mafatih-categories/": { + "get": { + "operationId": "mafatih-categories_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/MafatihCategories" } + } + } + }, + "tags": ["mafatih-categories"] + }, + "parameters": [] + }, + "/mafatih-categories/v2/": { + "get": { + "operationId": "mafatih-categories_v2_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/DuaCategories" } + } + } + }, + "tags": ["mafatih-categories"] + }, + "parameters": [] + }, + "/mafatih-dua-parts/": { + "get": { + "operationId": "mafatih-dua-parts_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MafatihDuaPart" } + } + } + } + } + }, + "tags": ["mafatih-dua-parts"] + }, + "parameters": [] + }, + "/mafatih-dua-parts/v2/": { + "get": { + "operationId": "mafatih-dua-parts_v2_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DuaPartSerializer" } + } + } + } + } + }, + "tags": ["mafatih-dua-parts"] + }, + "parameters": [] + }, + "/mafatih-duas/": { + "get": { + "operationId": "mafatih-duas_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MafatihDua" } + } + } + } + } + }, + "tags": ["mafatih-duas"] + }, + "parameters": [] + }, + "/mafatih-duas/audios/{id}/": { + "get": { + "operationId": "mafatih-duas_audios_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DuaAudioDetail" } + } + }, + "tags": ["mafatih-duas"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/mafatih-duas/dhikrs/": { + "get": { + "operationId": "mafatih-duas_dhikrs_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["mafatih-duas"] + }, + "parameters": [] + }, + "/mafatih-duas/famous/": { + "get": { + "operationId": "mafatih-duas_famous_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["mafatih-duas"] + }, + "parameters": [] + }, + "/mafatih-duas/location/": { + "get": { + "operationId": "mafatih-duas_location_list", + "description": "Retrieve nearby duas based on the user's location.\nThis view takes the user's latitude and longitude as input and returns a list of duas within 20 kilometers,\nsorted by distance. Additionally, duas within 2 kilometers are prioritized based on the priority field.", + "parameters": [ + { + "name": "lat", + "in": "query", + "description": "Latitude of the location lat = {Mashhad : 36.2605, Karbala : 32.6160326} ", + "type": "number" + }, + { + "name": "lon", + "in": "query", + "description": "Longitude of the location lon = {Mashhad : 59.6168, Karbala : 44.0244229} ", + "type": "number" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["mafatih-duas"] + }, + "parameters": [] + }, + "/mafatih-duas/v2/": { + "get": { + "operationId": "mafatih-duas_v2_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MafatihDuaSerializerV2" } + } + } + } + } + }, + "tags": ["mafatih-duas"] + }, + "parameters": [] + }, + "/mafatih-duas/v3/": { + "get": { + "operationId": "mafatih-duas_v3_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/MafatihDuaSerializerV3" } + } + } + } + } + }, + "tags": ["mafatih-duas"] + }, + "parameters": [] + }, + "/mafatih-duas/{id}/audios/": { + "get": { + "operationId": "mafatih-duas_audios_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DuaAudioList" } + } + } + } + } + }, + "tags": ["mafatih-duas"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/mafatih/{mafatih_dua_id}/reciters/": { + "get": { + "operationId": "mafatih_reciters_list", + "description": "Retrieve a list of unique reciters for a given MafatihDua.", + "parameters": [ + { + "name": "show_all", + "in": "query", + "description": "If true, returns all reciters, otherwise returns only reciters related to the specified MafatihDua.", + "type": "boolean", + "default": false + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Name of the reciter", + "type": "string" + }, + "avatar": { + "description": "URL of the reciter's avatar", + "type": "string" + } + } + } + } + } + }, + "tags": ["mafatih"] + }, + "parameters": [ + { + "name": "mafatih_dua_id", + "in": "path", + "required": true, + "type": "string" + } + ] + }, + "/masaels/": { + "get": { + "operationId": "masaels_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Masael" } + } + } + }, + "tags": ["masaels"] + }, + "parameters": [] + }, + "/masaels/marjaa-guide/": { + "get": { + "operationId": "masaels_marjaa-guide_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/MarjaaGuide" } + } + } + }, + "tags": ["masaels"] + }, + "parameters": [] + }, + "/masaels/v2/": { + "get": { + "operationId": "masaels_v2_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/MasaelSerializerV2" } + } + } + }, + "tags": ["masaels"] + }, + "parameters": [] + }, + "/notespace/create/": { + "post": { + "operationId": "notespace_create_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Note" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/Note" } + } + }, + "tags": ["notespace"] + }, + "parameters": [] + }, + "/notespace/create/feedback/": { + "post": { + "operationId": "notespace_create_feedback_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/NoteFeedback" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/NoteFeedback" } + } + }, + "tags": ["notespace"] + }, + "parameters": [] + }, + "/notespace/feedbak/{note_id}/delete/": { + "delete": { + "operationId": "notespace_feedbak_delete_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["notespace"] + }, + "parameters": [ + { "name": "note_id", "in": "path", "required": true, "type": "string" } + ] + }, + "/notespace/list/{service}/": { + "get": { + "operationId": "notespace_list_read", + "description": "Retrieve a list of Notes for a specific service and optionally a specific object.", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "service", + "in": "path", + "description": "Service type", + "type": "string", + "enum": ["quran", "mafatih", "hadis", "habit"], + "required": true + }, + { + "name": "object_id", + "in": "query", + "description": "Comma-separated list of Object IDs(e.g 1,2,5,...)", + "required": false, + "type": "string", + "default": "1,2,4" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Note" } + } + } + } + } + }, + "tags": ["notespace"] + }, + "parameters": [ + { "name": "service", "in": "path", "required": true, "type": "string" } + ] + }, + "/notespace/list/{service}/{object_id}/": { + "get": { + "operationId": "notespace_list_read", + "description": "Retrieve a list Note", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "service", + "in": "path", + "description": "Service type", + "type": "string", + "enum": ["quran", "mafatih", "hadis", "habit"], + "required": true + }, + { + "name": "object_id", + "in": "path", + "description": "Object ID for the note", + "type": "integer", + "required": true + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Note" } + } + } + } + } + }, + "tags": ["notespace"] + }, + "parameters": [ + { "name": "service", "in": "path", "required": true, "type": "string" }, + { + "name": "object_id", + "in": "path", + "required": true, + "type": "integer" + } + ] + }, + "/notespace/{id}/delete/": { + "delete": { + "operationId": "notespace_delete_delete", + "description": "", + "parameters": [], + "responses": { "204": { "description": "" } }, + "tags": ["notespace"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Note.", + "required": true, + "type": "integer" + } + ] + }, + "/notespace/{id}/update/": { + "put": { + "operationId": "notespace_update_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Note" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/Note" } + } + }, + "tags": ["notespace"] + }, + "patch": { + "operationId": "notespace_update_partial_update", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Note" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/Note" } + } + }, + "tags": ["notespace"] + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "A unique integer value identifying this Note.", + "required": true, + "type": "integer" + } + ] + }, + "/payment/methods/": { + "get": { + "operationId": "payment_methods_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["payment"] + }, + "parameters": [] + }, + "/plans/": { + "get": { + "operationId": "plans_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Plan" } + } + } + } + } + }, + "tags": ["plans"] + }, + "parameters": [] + }, + "/plans/subscribe/": { + "post": { + "operationId": "plans_subscribe_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Subscribe" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/Subscribe" } + } + }, + "tags": ["plans"] + }, + "parameters": [] + }, + "/plans/subscription-history/": { + "get": { + "operationId": "plans_subscription-history_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Subscribe" } + } + } + } + } + }, + "tags": ["plans"] + }, + "parameters": [] + }, + "/quran-juz/": { + "get": { + "operationId": "quran-juz_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranPart" } + } + } + } + } + }, + "tags": ["quran-juz"] + }, + "parameters": [] + }, + "/quran-page/": { + "get": { + "operationId": "quran-page_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranPart" } + } + } + } + } + }, + "tags": ["quran-page"] + }, + "parameters": [] + }, + "/quran-qaris/": { + "get": { + "operationId": "quran-qaris_list", + "description": "", + "parameters": [ + { + "name": "type", + "in": "query", + "type": "string", + "enum": ["reciter", "translation"] + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["quran-qaris"] + }, + "parameters": [] + }, + "/quran-qaris/v2/": { + "get": { + "operationId": "quran-qaris_v2_list", + "description": "", + "parameters": [ + { + "name": "type", + "in": "query", + "type": "string", + "enum": ["reciter", "translation"] + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["quran-qaris"] + }, + "parameters": [] + }, + "/quran-surahs-translation/": { + "get": { + "operationId": "quran-surahs-translation_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranSuraTranslation" } + } + } + } + } + }, + "tags": ["quran-surahs-translation"] + }, + "parameters": [] + }, + "/quran-surahs/": { + "get": { + "operationId": "quran-surahs_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranSura" } + } + } + } + } + }, + "tags": ["quran-surahs"] + }, + "parameters": [] + }, + "/quran-translators/": { + "get": { + "operationId": "quran-translators_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/QuranTranslators" } + } + } + }, + "tags": ["quran-translators"] + }, + "parameters": [] + }, + "/quran-verses-localization/": { + "get": { + "operationId": "quran-verses-localization_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { "name": "translator_en", "in": "query", "type": "string" } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranVerseLocalization" } + } + } + } + } + }, + "tags": ["quran-verses-localization"] + }, + "parameters": [] + }, + "/quran-verses-translation/": { + "get": { + "operationId": "quran-verses-translation_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { "name": "translator_en", "in": "query", "type": "string" } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranVerseTranslation" } + } + } + } + } + }, + "tags": ["quran-verses-translation"] + }, + "parameters": [] + }, + "/quran-verses/": { + "get": { + "operationId": "quran-verses_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranVerse" } + } + } + } + } + }, + "tags": ["quran-verses"] + }, + "parameters": [] + }, + "/quran-word-translation/": { + "get": { + "operationId": "quran-word-translation_list", + "description": "", + "parameters": [ + { "name": "surah_index", "in": "query", "type": "number" }, + { "name": "verse_index", "in": "query", "type": "number" }, + { + "name": "language_code", + "in": "query", + "type": "string", + "default": "en" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/QuranWordTranslation" } + } + } + }, + "tags": ["quran-word-translation"] + }, + "parameters": [] + }, + "/religious_times/adhans/": { + "get": { + "operationId": "religious_times_adhans_list", + "description": "adhan list api", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Adhan" } + } + } + } + } + }, + "tags": ["religious_times"] + }, + "parameters": [] + }, + "/religious_times/pre-adhans/": { + "get": { + "operationId": "religious_times_pre-adhans_list", + "description": "adhan list api", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Adhan" } + } + } + } + } + }, + "tags": ["religious_times"] + }, + "parameters": [] + }, + "/reminders/": { + "get": { + "operationId": "reminders_list", + "summary": "Get list of reminders for the authenticated user.", + "description": "### Example JSON Response:\n```json\n{\n \"count\": 10,\n \"next\": \"http://example.com/api/reminders/?page=2\",\n \"previous\": null,\n \"results\": [\n {\n \"id\": 1,\n \"service_name\": \"meet\",\n \"object_id\": \"123\",\n \"text\": \"Don't forget about the meeting tomorrow\",\n \"created_at\": \"2024-01-15T10:30:00Z\",\n \"call_time\": \"2024-01-16T09:00:00Z\",\n \"is_sent\": false,\n \"is_read\": false,\n \"status\": true,\n }\n ]\n}\n```", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "service_name", + "in": "query", + "description": "Filter reminders by service name (e.g., 'meet', 'dua', etc.)", + "required": false, + "type": "string" + }, + { + "name": "is_sent", + "in": "query", + "description": "Filter reminders by sent status", + "required": false, + "type": "boolean" + }, + { + "name": "is_read", + "in": "query", + "description": "Filter reminders by read status", + "required": false, + "type": "boolean" + }, + { + "name": "status", + "in": "query", + "description": "Filter reminders by active status", + "required": false, + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "List of user reminders", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Reminder" } + } + } + }, + "tags": ["reminders"] + }, + "parameters": [] + }, + "/reminders/{id}/": { + "put": { + "operationId": "reminders_update", + "description": "Update reminder status fields (same as PATCH).", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/ReminderUpdate" } + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ReminderUpdate" } + } + }, + "tags": ["reminders"] + }, + "patch": { + "operationId": "reminders_partial_update", + "summary": "Update reminder status fields.", + "description": "### Example Request:\n```json\n{\n \"status\": false\n}\n```\n\n### Example Response:\n```json\n{\n\n \"status\": false\n}\n```", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "description": "At least one field must be provided", + "required": [], + "type": "object", + "properties": { + "status": { + "description": "General status of the reminder", + "type": "boolean" + } + } + } + } + ], + "responses": { + "200": { + "description": "Reminder updated successfully", + "schema": { "$ref": "#/definitions/ReminderUpdate" } + }, + "400": { "description": "Bad request - validation errors" }, + "404": { "description": "Reminder not found" }, + "403": { + "description": "Permission denied - reminder belongs to another user" + } + }, + "tags": ["reminders"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/report/": { + "post": { + "operationId": "report_create", + "description": "", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { "$ref": "#/definitions/Report" } + } + ], + "responses": { + "201": { + "description": "", + "schema": { "$ref": "#/definitions/Report" } + } + }, + "tags": ["report"] + }, + "parameters": [] + }, + "/report/subjects/": { + "get": { + "operationId": "report_subjects_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Subject" } + } + } + } + } + }, + "tags": ["report"] + }, + "parameters": [] + }, + "/service-versions/": { + "get": { + "operationId": "service-versions_list", + "description": "\n# 📘 Scenario\nدر حبیب دیتا های بعضی از سرویس ها به صورت یک جا گرفته و ذخیره میشوند سمت کلاینت \nممکن است در مرور زمان این دیتا ها بر اساس محتوا تغییراتی داشته باشند بنابر این\nدر اینجا ما میتوانی به هر سرویس شماره ورژنی اختصاص دهیم بر اساس زبان\n(به طور مثال در احکام زبان فارسی ترجمه ای آپدیت میشود و بایستی داده جدیدی به کاربر نمایش دهیم)\nبنابر این میتوانیم به طور تخمینی یک زمانی را تعیین کنیم که این ای پی ای فراخوانی شود \nو اگر شماره ورژن سرویسی افزایش پیدا کرده بود آن دیتا را مجددا درخواست کنیم \nو بایستی برای هر کلاینت این شماره ورژن های سرویس را ذخیره و در هر بار مقایسه کنیم\n\n---\n\n## 🚀 درخواست API\n\nکاربر باید احراز هویت شده باشد و زبان درخواست از طریق `LANGUAGE_CODE` در تنظیمات کاربر مشخص می‌شود. این API تنها نسخه‌های مرتبط با زبان کاربر را باز می‌گرداند.\n\n\n## 📊 پاسخ‌ها\n\n| کد وضعیت | توضیحات |\n|----------|------------------------------------------------------------|\n| `200` | موفقیت‌آمیز - لیستی از آخرین نسخه‌های سرویس‌ها برمی‌گرداند |\n\n---\n\n## 📄 نمونه پاسخ موفقیت‌آمیز\n\n```json\n[\n {\n \"service\": \"ahkam\",\n \"version_number\": \"1.3\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-11-01T12:34:56Z\",\n \"app_intros\": [\n {\n \"title\": \"خوش آمدید به سرویس احکام\",\n \"summary\": \"این سرویس شامل احکام شرعی است\",\n \"image\": \"https://example.com/images/intro1.jpg\",\n \"priority\": 1\n },\n {\n \"title\": \"نحوه استفاده\",\n \"summary\": \"برای استفاده از سرویس احکام...\",\n \"image\": \"https://example.com/images/intro2.jpg\",\n \"priority\": 2\n }\n ],\n \"service_intros\": [\n {\n \"title\": \"به‌روزرسانی جدید\",\n \"summary\": \"در این نسخه ویژگی‌های جدیدی اضافه شده است\",\n \"image\": \"https://example.com/images/update1.jpg\",\n \"priority\": 1\n }\n ]\n },\n {\n \"service\": \"quran\",\n \"version_number\": \"2.1\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-10-20T10:24:36Z\",\n \"app_intros\": [],\n \"service_intros\": []\n }\n]\n```\n\n### 📋 توضیحات فیلدها\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `service` | string | شناسه (slug) سرویس |\n| `version_number` | string | شماره نسخه سرویس (مثال: \"1.3\") |\n| `language` | object | اطلاعات زبان شامل `code` و `name` |\n| `created_at` | datetime | تاریخ ایجاد نسخه |\n| `app_intros` | array | لیست اسلایدهای معرفی استاتیک (Onboarding) که برای تمام نسخه‌های سرویس یکسان است |\n| `service_intros` | array | لیست اسلایدهای معرفی مخصوص این نسخه (Update Note) |\n\n### 📝 ساختار هر آیتم در `app_intros` و `service_intros`:\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `title` | string | عنوان ترجمه شده بر اساس زبان درخواست |\n| `summary` | string | خلاصه ترجمه شده بر اساس زبان درخواست |\n| `image` | string\\|null | URL تصویر یا null در صورت عدم وجود |\n| `priority` | integer | اولویت نمایش (کمتر = اولویت بیشتر) |\n\n**نکته:** فیلدهای `title` و `summary` به صورت خودکار بر اساس زبان درخواست (`LANGUAGE_CODE`) ترجمه می‌شوند و فقط مقدار ترجمه شده (string) برگردانده می‌شود، نه دیکشنری کامل ترجمه‌ها.\n", + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "Bearer token for authentication", + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/ServiceVersion" } + } + } + }, + "tags": ["service-versions"] + }, + "parameters": [] + }, + "/service-versions/v2/": { + "get": { + "operationId": "service-versions_v2_list", + "description": "\n# 📘 Scenario\nدر حبیب دیتا های بعضی از سرویس ها به صورت یک جا گرفته و ذخیره میشوند سمت کلاینت \nممکن است در مرور زمان این دیتا ها بر اساس محتوا تغییراتی داشته باشند بنابر این\nدر اینجا ما میتوانی به هر سرویس شماره ورژنی اختصاص دهیم بر اساس زبان\n(به طور مثال در احکام زبان فارسی ترجمه ای آپدیت میشود و بایستی داده جدیدی به کاربر نمایش دهیم)\nبنابر این میتوانیم به طور تخمینی یک زمانی را تعیین کنیم که این ای پی ای فراخوانی شود \nو اگر شماره ورژن سرویسی افزایش پیدا کرده بود آن دیتا را مجددا درخواست کنیم \nو بایستی برای هر کلاینت این شماره ورژن های سرویس را ذخیره و در هر بار مقایسه کنیم\n\n---\n\n## 🚀 درخواست API\n\nکاربر باید احراز هویت شده باشد و زبان درخواست از طریق `LANGUAGE_CODE` در تنظیمات کاربر مشخص می‌شود. این API تنها نسخه‌های مرتبط با زبان کاربر را باز می‌گرداند.\n\n\n## 📊 پاسخ‌ها\n\n| کد وضعیت | توضیحات |\n|----------|------------------------------------------------------------|\n| `200` | موفقیت‌آمیز - لیستی از آخرین نسخه‌های سرویس‌ها برمی‌گرداند |\n\n---\n\n## 📄 نمونه پاسخ موفقیت‌آمیز\n\n```json\n[\n {\n \"service\": \"ahkam\",\n \"version_number\": \"1.3\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-11-01T12:34:56Z\",\n \"app_intros\": [\n {\n \"title\": \"خوش آمدید به سرویس احکام\",\n \"summary\": \"این سرویس شامل احکام شرعی است\",\n \"image\": \"https://example.com/images/intro1.jpg\",\n \"priority\": 1\n },\n {\n \"title\": \"نحوه استفاده\",\n \"summary\": \"برای استفاده از سرویس احکام...\",\n \"image\": \"https://example.com/images/intro2.jpg\",\n \"priority\": 2\n }\n ],\n \"service_intros\": [\n {\n \"title\": \"به‌روزرسانی جدید\",\n \"summary\": \"در این نسخه ویژگی‌های جدیدی اضافه شده است\",\n \"image\": \"https://example.com/images/update1.jpg\",\n \"priority\": 1\n }\n ]\n },\n {\n \"service\": \"quran\",\n \"version_number\": \"2.1\",\n \"language\": {\n \"code\": \"fa\",\n \"name\": \"فارسی\"\n },\n \"created_at\": \"2023-10-20T10:24:36Z\",\n \"app_intros\": [],\n \"service_intros\": []\n }\n]\n```\n\n### 📋 توضیحات فیلدها\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `service` | string | شناسه (slug) سرویس |\n| `version_number` | string | شماره نسخه سرویس (مثال: \"1.3\") |\n| `language` | object | اطلاعات زبان شامل `code` و `name` |\n| `created_at` | datetime | تاریخ ایجاد نسخه |\n| `app_intros` | array | لیست اسلایدهای معرفی استاتیک (Onboarding) که برای تمام نسخه‌های سرویس یکسان است |\n| `service_intros` | array | لیست اسلایدهای معرفی مخصوص این نسخه (Update Note) |\n\n### 📝 ساختار هر آیتم در `app_intros` و `service_intros`:\n\n| فیلد | نوع | توضیحات |\n|------|-----|---------|\n| `title` | string | عنوان ترجمه شده بر اساس زبان درخواست |\n| `summary` | string | خلاصه ترجمه شده بر اساس زبان درخواست |\n| `image` | string\\|null | URL تصویر یا null در صورت عدم وجود |\n| `priority` | integer | اولویت نمایش (کمتر = اولویت بیشتر) |\n\n**نکته:** فیلدهای `title` و `summary` به صورت خودکار بر اساس زبان درخواست (`LANGUAGE_CODE`) ترجمه می‌شوند و فقط مقدار ترجمه شده (string) برگردانده می‌شود، نه دیکشنری کامل ترجمه‌ها.\n", + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "Bearer token for authentication", + "type": "string" + } + ], + "responses": { + "200": { + "description": "Service versions with startup modal", + "schema": { + "type": "object", + "properties": { + "versions": { "type": "array", "items": { "type": "object" } }, + "startup_modal": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "html_content": { + "description": "Rendered HTML form content", + "type": "string" + }, + "width_percentage": { + "description": "Modal width in percentage", + "type": "integer" + }, + "height_percentage": { + "description": "Modal height in percentage", + "type": "integer" + }, + "is_forced": { "type": "boolean" } + }, + "nullable": true + } + } + } + } + }, + "tags": ["service-versions"] + }, + "parameters": [] + }, + "/share-app/": { + "get": { + "operationId": "share-app_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/ShareApp" } + } + }, + "tags": ["share-app"] + }, + "parameters": [] + }, + "/tafsir/book/{book}/{surah}/{verse}/": { + "get": { + "operationId": "tafsir_book_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/TafsirVerses" } + } + }, + "tags": ["tafsir"] + }, + "parameters": [ + { "name": "book", "in": "path", "required": true, "type": "string" }, + { "name": "surah", "in": "path", "required": true, "type": "string" }, + { "name": "verse", "in": "path", "required": true, "type": "string" } + ] + }, + "/tafsir/books/": { + "get": { + "operationId": "tafsir_books_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/TafsirBook" } + } + } + }, + "tags": ["tafsir"] + }, + "parameters": [] + }, + "/upload-tmp-media/": { + "post": { + "operationId": "upload-tmp-media_create", + "description": "upload file...", + "parameters": [ + { "name": "file", "in": "formData", "required": true, "type": "file" } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "default": true }, + "path": { "description": "url path of file", "type": "string" }, + "apath": { + "description": "absolute path of file", + "type": "string" + }, + "name": { "type": "string" }, + "size": { "type": "string" } + } + } + }, + "400": { + "description": "", + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "default": false }, + "reason": { "type": "string" } + } + } + } + }, + "consumes": ["multipart/form-data"], + "tags": ["upload-tmp-media"] + }, + "parameters": [] + }, + "/v1/languages/": { + "get": { + "operationId": "v1_languages_list", + "description": "language list api", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Language" } + } + } + }, + "tags": ["v1"] + }, + "parameters": [] + }, + "/wallet/info/": { + "get": { + "operationId": "wallet_info_list", + "description": "Retrieve wallet details for the authenticated user, including balance in coins and USD", + "parameters": [], + "responses": { + "200": { + "description": "Wallet details", + "examples": { + "application/json": { + "id": 1, + "currency": "USD", + "balance_coin_count": 100, + "balance_amount": 10.0, + "coin_amount": { "coin": 10, "amount": 1.0 } + } + } + }, + "400": { "description": "User does not have any active publishers." }, + "404": { "description": "Wallet not found." } + }, + "tags": ["wallet"] + }, + "parameters": [] + }, + "/wallet/transactions/": { + "get": { + "operationId": "wallet_transactions_list", + "description": "List all income transactions", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Transaction" } + } + } + }, + "tags": ["wallet"] + }, + "parameters": [] + }, + "/wallet/wallet/withdrawal-requests/create/": { + "post": { + "operationId": "wallet_wallet_withdrawal-requests_create_create", + "description": "Creates a withdrawal request for the authenticated user.", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": ["coin_count"], + "type": "object", + "properties": { + "coin_count": { + "description": "Number of coins to withdraw", + "type": "integer" + } + } + } + } + ], + "responses": { + "201": { + "description": "Withdrawal request created successfully", + "examples": { + "application/json": { + "detail": "Withdrawal request created successfully.", + "request_id": 1, + "status": "pending", + "amount": 5.0, + "coin_count": 50, + "currency": "USD" + } + } + }, + "400": { + "description": "Bad request due to validation error or insufficient balance", + "examples": { + "application/json": { + "detail": "Insufficient balance to create debit request." + } + } + }, + "404": { + "description": "Wallet not found", + "examples": { + "application/json": { "detail": "User does not have a wallet." } + } + } + }, + "tags": ["wallet"] + }, + "parameters": [] + }, + "/wallet/withdrawal-requests/": { + "get": { + "operationId": "wallet_withdrawal-requests_list", + "description": "List all withdrawal requests for the authenticated user", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/WithdrawalRequest" } + } + } + }, + "tags": ["wallet"] + }, + "parameters": [] + }, + "/web/donate/v2/": { + "get": { + "operationId": "web_donate_v2_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["web"] + }, + "parameters": [] + }, + "/web/donate/v2/create/": { + "post": { + "operationId": "web_donate_v2_create_create", + "description": "\n**Donation Creation API**\n\nCreate a donation record and receive a payment link. This API is designed to never fail and always returns a working donation link without any errors.\n\n**Key Features:**\n- Error-free operation - never returns HTTP errors\n- All fields are completely optional with intelligent defaults\n- Automatic payment method selection based on user location\n- Support for multiple payment gateways\n- Backward compatibility with existing integrations\n\n**Smart Defaults:**\n- **donate_type**: Defaults to 'once' if not provided or invalid\n- **price**: Defaults to '10.00' if not provided or invalid\n- **id**: Auto-selected based on user location (CloudTips for Russian users, Stripe for others)\n- **phone_number**: Optional field, stored if provided, otherwise null\n\n**Payment Methods:**\n- **Stripe**: International payment gateway with predefined donation links\n- **CloudTips**: Russian payment gateway for Russian users\n\n**Localization Logic:**\n- Russian users (language_code=ru OR user.country=RU) default to CloudTips\n- All other users default to Stripe payment gateway\n- Fallback to default donation links for custom amounts\n\n**Business Logic:**\n- Creates donation record in database (optional, doesn't affect response)\n- Optionally stores donor's phone number for contact purposes\n- Maps donation amounts to predefined Stripe payment links\n- Uses fallback links for unmapped amounts\n- Always returns HTTP 200 with working payment link\n\n**Authentication**: Not required - Public API\n**Permissions**: None - Accessible to all users\n", + "parameters": [ + { + "name": "data", + "in": "body", + "required": true, + "schema": { + "required": [], + "type": "object", + "properties": { + "donate_type": { + "description": "Type of donation - either 'monthly' for recurring donations or 'once' for one-time donations. This field is completely optional and will default to 'once' if not provided or if an invalid value is sent.", + "type": "string", + "enum": ["monthly", "once"] + }, + "price": { + "description": "Donation amount as a string (e.g., '5.00', '10.00', '20.00'). This field is completely optional and will default to '10.00' if not provided or if an invalid value is sent.", + "type": "string" + }, + "id": { + "description": "Payment gateway identifier. This field is completely optional. If not provided, the system will automatically choose 'stripe' for non-Russian users and 'cloudtips' for Russian users (detected by language_code=ru or user country=RU). If an invalid value is provided, it defaults to 'stripe'.", + "type": "string", + "enum": ["stripe", "cloudtips"] + }, + "phone_number": { + "description": "Optional phone number for the donor. This field is completely optional and can be omitted. If provided, it will be stored with the donation record.", + "type": "string" + } + }, + "example": { + "donate_type": "once", + "price": "15.00", + "id": "stripe", + "phone_number": "+1234567890" + } + } + } + ], + "responses": { + "200": { + "description": "Donation link created successfully. This API is guaranteed to always return HTTP 200 status with a working donation link, regardless of the input provided. Even if no data is sent in the request body, the API will respond with appropriate defaults.", + "examples": { + "application/json": { + "complete_request": { + "summary": "Complete Request with Phone Number", + "description": "Response when all fields including phone_number are provided", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/bIYdSDgiK7Pwh0ccMN" + } + }, + "request_with_phone": { + "summary": "Request Example with Phone", + "description": "Example showing phone_number parameter usage", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/9AQ01N5E68TAbFS002" + } + }, + "empty_request_default": { + "summary": "Empty Request (Default)", + "description": "Response when no fields are provided - uses intelligent defaults", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV" + } + }, + "empty_request_russian_user": { + "summary": "Empty Request (Russian User)", + "description": "Response for Russian users when no fields are provided", + "value": { + "donate_user": 1, + "donate_link": "https://pay.cloudtips.ru/p/d5881ddf" + } + }, + "cloudtips_payment": { + "summary": "CloudTips Payment", + "description": "Response when CloudTips payment method is selected", + "value": { + "donate_user": 1, + "donate_link": "https://pay.cloudtips.ru/p/d5881ddf" + } + }, + "invalid_data_fallback": { + "summary": "Invalid Data Fallback", + "description": "Response when invalid data is provided - normalized to defaults", + "value": { + "donate_user": 1, + "donate_link": "https://donate.stripe.com/7sI3dZaYq7Pw9xKcMV" + } + } + } + } + } + }, + "tags": ["Donate"] + }, + "parameters": [] + }, + "/web/duas/robots.txt": { + "get": { + "operationId": "web_duas_robots.txt_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["web"] + }, + "parameters": [] + }, + "/web/duas/{slug}/complete/": { + "get": { + "operationId": "web_duas_complete_read", + "description": "دریافت کامل یک دعا با تمام بخش‌ها (بدون pagination) برای استفاده آفلاین", + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Slug دعا", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "", + "schema": { "$ref": "#/definitions/DuaCompleteSerializer" } + }, + "404": { "description": "دعا یافت نشد" } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/mafatih-categories/": { + "get": { + "operationId": "web_mafatih-categories_list", + "description": "", + "parameters": [ + { "name": "language_code", "in": "query", "type": "string" } + ], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { "$ref": "#/definitions/Web_DuaCategoriesSerializer" } + } + } + }, + "tags": ["web"] + }, + "parameters": [] + }, + "/web/mafatih-duas/": { + "get": { + "operationId": "web_mafatih-duas_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + }, + { + "name": "category", + "in": "query", + "description": "ID دسته‌بندی برای فیلتر دعاها", + "type": "integer" + }, + { + "name": "search", + "in": "query", + "description": "جستجو بر اساس عنوان دعاها", + "type": "string" + }, + { + "name": "today", + "in": "query", + "description": "", + "type": "string" + }, + { + "name": "famous", + "in": "query", + "description": "", + "type": "string" + }, + { + "name": "lat", + "in": "query", + "description": "Latitude of the location lat = {Mashhad : 36.2605, Karbala : 32.6160326} ", + "type": "number" + }, + { + "name": "lon", + "in": "query", + "description": "Longitude of the location lon = {Mashhad : 59.6168, Karbala : 44.0244229} ", + "type": "number" + }, + { + "name": "not_synced", + "in": "query", + "description": "", + "type": "boolean" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Web_DuaSerializer" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [] + }, + "/web/mafatih-duas/dhikrs/": { + "get": { + "operationId": "web_mafatih-duas_dhikrs_list", + "description": "", + "parameters": [], + "responses": { "200": { "description": "" } }, + "tags": ["web"] + }, + "parameters": [] + }, + "/web/mafatih-duas/{id}/parts/": { + "get": { + "operationId": "web_mafatih-duas_parts_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Web_DuaPartSerializer" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/mafatih-duas/{slug}/parts/": { + "get": { + "operationId": "web_mafatih-duas_parts_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/Web_DuaPartSerializer" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/mafatih/{id}/audios/": { + "get": { + "operationId": "web_mafatih_audios_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/WebDuaAudio" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/mafatih/{id}/reciters/": { + "get": { + "operationId": "web_mafatih_reciters_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DuaReciter" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "id", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/mafatih/{slug}/audios/": { + "get": { + "operationId": "web_mafatih_audios_list", + "description": "", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "A page number within the paginated result set.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/WebDuaAudio" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/mafatih/{slug}/reciters/": { + "get": { + "operationId": "web_mafatih_reciters_list", + "description": "", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/DuaReciter" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "slug", "in": "path", "required": true, "type": "string" } + ] + }, + "/web/quran-qaris/": { + "get": { + "operationId": "web_quran-qaris_list", + "description": "", + "parameters": [ + { + "name": "type", + "in": "query", + "type": "string", + "enum": ["reciter", "translation"] + } + ], + "responses": { "200": { "description": "" } }, + "tags": ["web"] + }, + "parameters": [] + }, + "/web/quran-surah/{surah_id}/": { + "get": { + "operationId": "web_quran-surah_read", + "description": "API view that returns all verses from a specific Surah with translations\nbased on the language_code query parameter", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Number of results to return per page.", + "required": false, + "type": "integer" + }, + { + "name": "offset", + "in": "query", + "description": "The initial index from which to return the results.", + "required": false, + "type": "integer" + }, + { + "name": "language_code", + "in": "query", + "type": "string", + "default": "en" + } + ], + "responses": { + "200": { + "description": "", + "schema": { + "required": ["count", "results"], + "type": "object", + "properties": { + "count": { "type": "integer" }, + "next": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "previous": { + "type": "string", + "format": "uri", + "x-nullable": true + }, + "results": { + "type": "array", + "items": { "$ref": "#/definitions/QuranSurahDetailVerse" } + } + } + } + } + }, + "tags": ["web"] + }, + "parameters": [ + { "name": "surah_id", "in": "path", "required": true, "type": "string" } + ] + } + }, + "definitions": { + "Supporter": { + "required": ["title"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "url": { + "title": "Url", + "description": "https://example.com", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "logo": { "title": "Logo", "type": "string", "readOnly": true } + } + }, + "AboutService": { + "required": ["description", "language", "service", "supporters"], + "type": "object", + "properties": { + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + }, + "language": { "title": "Language", "type": "string", "minLength": 1 }, + "service": { + "title": "Service", + "type": "string", + "enum": [ + "main", + "hussainiyah", + "quran", + "mafatih", + "qiblah", + "ahkam", + "calendar", + "talk", + "meet", + "library", + "hadis", + "account" + ] + }, + "supporters": { + "type": "array", + "items": { "$ref": "#/definitions/Supporter" } + } + } + }, + "Activity": { + "required": ["usage_duration"], + "type": "object", + "properties": { + "service": { + "title": "Service", + "type": "string", + "maxLength": 100, + "x-nullable": true + }, + "usage_duration": { "title": "Usage duration", "type": "string" }, + "entered_at": { + "title": "Entered at", + "type": "string", + "format": "date-time" + }, + "additional_info": { "title": "Additional info", "type": "object" } + } + }, + "AppleAuth": { + "required": ["id_token", "server_auth_token", "mobile_device_id"], + "type": "object", + "properties": { + "id_token": { + "title": "Id token", + "type": "string", + "maxLength": 9000, + "minLength": 1 + }, + "server_auth_token": { + "title": "Server auth token", + "type": "string", + "maxLength": 9000, + "minLength": 1 + }, + "mobile_device_id": { + "title": "Mobile device id", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "avatar": { "title": "~ Avatar", "type": "string", "x-nullable": true }, + "fcm": { "title": "Fcm", "type": "string", "x-nullable": true }, + "publisher_in": { + "title": "Publisher in", + "type": "string", + "readOnly": true + }, + "token": { + "title": "Token", + "type": "string", + "readOnly": true, + "minLength": 1 + } + } + }, + "GoogleAuth": { + "required": [ + "email", + "name", + "mobile_device_id", + "server_auth_token", + "id_token" + ], + "type": "object", + "properties": { + "email": { "title": "Email", "type": "string", "x-nullable": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "mobile_device_id": { + "title": "Mobile device id", + "type": "string", + "maxLength": 500, + "x-nullable": true + }, + "avatar": { "title": "~ Avatar", "type": "string", "x-nullable": true }, + "server_auth_token": { + "title": "Server auth token", + "type": "string", + "maxLength": 9000, + "minLength": 1 + }, + "id_token": { + "title": "Id token", + "type": "string", + "maxLength": 9000, + "minLength": 1 + }, + "fcm": { "title": "Fcm", "type": "string", "x-nullable": true }, + "publisher_in": { + "title": "Publisher in", + "type": "string", + "readOnly": true + } + } + }, + "GuestUser": { + "required": ["mobile_device_id"], + "type": "object", + "properties": { + "lat": { + "title": "Lat", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "lon": { + "title": "Lon", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "mobile_device_id": { + "title": "Mobile device id", + "type": "string", + "x-nullable": true + }, + "language": { + "title": "Language", + "type": "string", + "x-nullable": true + }, + "cpu_type": { + "title": "Cpu type", + "type": "string", + "maxLength": 64, + "x-nullable": true + }, + "model_name": { + "title": "Model name", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "os_platform": { + "title": "Os platform", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "screen_size": { + "title": "Screen size", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "device_brand": { + "title": "Device brand", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "timezone": { + "title": "Timezone", + "type": "string", + "x-nullable": true + }, + "api_version": { + "title": "Api version", + "type": "string", + "x-nullable": true + }, + "fcm": { + "title": "Firebase token", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "location_method": { + "title": "Location method", + "type": "string", + "x-nullable": true + } + } + }, + "PhoneAuth": { + "required": ["phone_number", "mobile_device_id"], + "type": "object", + "properties": { + "phone_number": { + "title": "Phone number", + "type": "string", + "maxLength": 254, + "x-nullable": true + }, + "lat": { + "title": "Lat", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "lon": { + "title": "Lon", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "mobile_device_id": { + "title": "Mobile device id", + "type": "string", + "maxLength": 500, + "x-nullable": true + }, + "cpu_type": { + "title": "Cpu type", + "type": "string", + "maxLength": 64, + "x-nullable": true + }, + "model_name": { + "title": "Model name", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "os_platform": { + "title": "Os platform", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "screen_size": { + "title": "Screen size", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "device_brand": { + "title": "Device brand", + "type": "string", + "maxLength": 120, + "x-nullable": true + }, + "timezone": { + "title": "Timezone", + "type": "string", + "x-nullable": true + }, + "api_version": { + "title": "Api version", + "type": "string", + "x-nullable": true + }, + "fcm": { "title": "Fcm", "type": "string", "x-nullable": true }, + "location_method": { + "title": "Location method", + "type": "string", + "x-nullable": true + } + } + }, + "MergeAccount": { + "required": ["method", "value"], + "type": "object", + "properties": { + "method": { + "title": "Method", + "type": "string", + "enum": ["phone", "email"] + }, + "value": { "title": "Value", "type": "string", "minLength": 1 } + } + }, + "MergeVerify": { + "required": ["phone_number", "code"], + "type": "object", + "properties": { + "phone_number": { + "title": "Phone number", + "type": "string", + "minLength": 1 + }, + "code": { "title": "Code", "type": "string", "minLength": 1 } + } + }, + "UserProfile": { + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "minLength": 1 }, + "avatar": { "title": "Avatar", "type": "string", "x-nullable": true }, + "email": { + "title": "Email", + "type": "string", + "format": "email", + "readOnly": true, + "minLength": 1 + }, + "phone_number": { + "title": "Phone number", + "type": "string", + "readOnly": true, + "minLength": 1 + } + } + }, + "PhoneVerify": { + "required": ["phone_number", "user_id", "code"], + "type": "object", + "properties": { + "phone_number": { + "title": "Phone number", + "type": "string", + "maxLength": 254, + "x-nullable": true + }, + "user_id": { + "title": "User id", + "type": "string", + "maxLength": 10, + "minLength": 1 + }, + "code": { + "title": "Code", + "type": "string", + "maxLength": 5, + "minLength": 1 + } + } + }, + "IPGeolocation": { + "type": "object", + "properties": { + "ip": { + "title": "Ip", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "country": { + "title": "Country", + "type": "string", + "readOnly": true, + "maxLength": 100, + "x-nullable": true + }, + "country_code": { + "title": "Country code", + "type": "string", + "readOnly": true, + "maxLength": 10, + "x-nullable": true + }, + "city": { + "title": "City", + "type": "string", + "readOnly": true, + "maxLength": 100, + "x-nullable": true + }, + "latitude": { + "title": "Latitude", + "type": "number", + "readOnly": true, + "x-nullable": true + }, + "longitude": { + "title": "Longitude", + "type": "number", + "readOnly": true, + "x-nullable": true + }, + "accuracy_radius": { + "title": "Accuracy radius", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "time_zone": { + "title": "Time zone", + "type": "string", + "readOnly": true, + "maxLength": 100, + "x-nullable": true + }, + "postal_code": { + "title": "Postal code", + "type": "string", + "readOnly": true, + "maxLength": 20, + "x-nullable": true + } + } + }, + "ReverseGeolocationResponse": { + "type": "object", + "properties": { + "latitude": { "title": "Latitude", "type": "number", "readOnly": true }, + "longitude": { + "title": "Longitude", + "type": "number", + "readOnly": true + }, + "city": { + "title": "City", + "type": "string", + "readOnly": true, + "maxLength": 100, + "minLength": 1, + "x-nullable": true + }, + "country": { + "title": "Country", + "type": "string", + "readOnly": true, + "maxLength": 100, + "minLength": 1, + "x-nullable": true + }, + "country_code": { + "title": "Country code", + "type": "string", + "readOnly": true, + "maxLength": 10, + "minLength": 1, + "x-nullable": true + }, + "accuracy_radius": { + "title": "Accuracy radius", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "time_zone": { + "title": "Time zone", + "type": "string", + "readOnly": true, + "maxLength": 100, + "x-nullable": true + }, + "postal_code": { + "title": "Postal code", + "type": "string", + "readOnly": true, + "maxLength": 20, + "x-nullable": true + } + } + }, + "LocationHistory": { + "required": ["lat", "lon"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "lat": { "title": "Lat", "type": "number" }, + "lon": { "title": "Lon", "type": "number" }, + "country": { + "title": "Country", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "city": { + "title": "City", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "selected_manually": { + "title": "Selected manually", + "type": "boolean", + "x-nullable": true + }, + "ip": { + "title": "Ip", + "type": "string", + "maxLength": 255, + "minLength": 1, + "x-nullable": true + }, + "timezone": { + "title": "Timezone", + "type": "string", + "maxLength": 60, + "x-nullable": true + } + } + }, + "UserNotification": { + "required": ["service", "title", "message"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "service": { "title": "Service", "type": "string", "minLength": 1 }, + "title": { "title": "Title", "type": "string", "minLength": 1 }, + "message": { "title": "Message", "type": "string", "minLength": 1 }, + "data": { "title": "Data", "type": "string", "readOnly": true }, + "image": { "title": "Image", "type": "string", "readOnly": true }, + "is_read": { "title": "Is Read", "type": "boolean" }, + "created_at": { + "title": "Created At", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "notif_data": { + "title": "Notif data", + "type": "string", + "readOnly": true + } + } + }, + "Provider": { + "required": [ + "public_name", + "description", + "service", + "birthdate", + "phone_number", + "wa_number" + ], + "type": "object", + "properties": { + "public_name": { + "title": "Public name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + }, + "service": { + "title": "Service", + "type": "string", + "enum": [ + "hussainiya", + "net", + "library", + "talk", + "shop", + "travel", + "meet", + "habibnet" + ] + }, + "birthdate": { + "title": "Birthdate", + "type": "string", + "format": "date" + }, + "phone_number": { + "title": "Phone number", + "type": "string", + "minLength": 1 + }, + "wa_number": { "title": "Wa number", "type": "string", "minLength": 1 }, + "social_medias": { + "title": "Social medias", + "description": "[{\"type\": \"instagram\", \"link\": \"https://www.instagram.com\"}]", + "type": "object", + "default": [] + }, + "status": { + "title": "Status", + "type": "string", + "enum": ["pending", "rejected", "accepted"], + "readOnly": true + } + } + }, + "UserSettings": { + "type": "object", + "properties": { + "settings": { + "title": "Settings", + "type": "string", + "x-nullable": true + }, + "is_reminder": { "title": "Reminder Active", "type": "boolean" }, + "notification_settings": { + "description": "List of notification services: hussainiyah, meet, talk, library", + "type": "array", + "items": { "type": "string", "minLength": 1 }, + "default": ["hussainiyah", "meet", "talk", "library"] + } + } + }, + "ReviewList": { + "required": [ + "platform", + "review_id", + "last_modified_ts", + "app_identifier" + ], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "platform": { + "title": "Platform", + "type": "string", + "enum": [ + "google_play", + "app_store", + "whatsapp", + "telegram", + "habib_talk" + ] + }, + "review_id": { + "title": "Review id", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "author_name": { + "title": "Author name", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "text": { "title": "Text", "type": "string" }, + "review_status": { + "title": "Review status", + "type": "string", + "enum": ["pending", "responded", "escalated", "resolved"] + }, + "needs_human_intervention": { + "title": "Needs human intervention", + "type": "boolean" + }, + "last_modified_ts": { + "title": "Last modified ts", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808 + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "user_identifier": { + "title": "User identifier", + "description": "Phone number for WhatsApp, Chat ID for Telegram, etc.", + "type": "string", + "maxLength": 255 + }, + "app_identifier": { + "title": "App identifier", + "description": "Package name, bundle ID یا شناسه کانال/گروه بسته به پلتفرم", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "rating": { + "title": "Rating", + "type": "integer", + "maximum": 32767, + "minimum": 0, + "x-nullable": true + } + } + }, + "ReviewDetail": { + "required": [ + "platform", + "app_identifier", + "review_id", + "last_modified_ts" + ], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "platform": { + "title": "Platform", + "type": "string", + "enum": [ + "google_play", + "app_store", + "whatsapp", + "telegram", + "habib_talk" + ] + }, + "app_identifier": { + "title": "App identifier", + "description": "Package name, bundle ID یا شناسه کانال/گروه بسته به پلتفرم", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "user_identifier": { + "title": "User identifier", + "description": "Phone number for WhatsApp, Chat ID for Telegram, etc.", + "type": "string", + "maxLength": 255 + }, + "review_id": { + "title": "Review id", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "author_name": { + "title": "Author name", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "rating": { + "title": "Rating", + "type": "integer", + "maximum": 32767, + "minimum": 0, + "x-nullable": true + }, + "title": { "title": "Title", "type": "string", "maxLength": 255 }, + "text": { "title": "Text", "type": "string" }, + "device": { "title": "Device", "type": "string", "maxLength": 255 }, + "reviewer_language": { + "title": "Reviewer language", + "type": "string", + "maxLength": 10 + }, + "android_os_version": { + "title": "Android os version", + "type": "integer", + "maximum": 32767, + "minimum": 0, + "x-nullable": true + }, + "app_version_code": { + "title": "App version code", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "app_version_name": { + "title": "App version name", + "type": "string", + "maxLength": 50 + }, + "device_product_name": { + "title": "Device product name", + "type": "string", + "maxLength": 255 + }, + "device_manufacturer": { + "title": "Device manufacturer", + "type": "string", + "maxLength": 100 + }, + "device_class": { + "title": "Device class", + "type": "string", + "maxLength": 50 + }, + "screen_width_px": { + "title": "Screen width px", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "screen_height_px": { + "title": "Screen height px", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "screen_density_dpi": { + "title": "Screen density dpi", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "ram_mb": { + "title": "Ram mb", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "last_modified_ts": { + "title": "Last modified ts", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": -9223372036854775808 + }, + "raw_data": { + "title": "Raw data", + "type": "object", + "x-nullable": true + }, + "sent_to_telegram": { "title": "Sent to telegram", "type": "boolean" }, + "category": { + "title": "Category", + "type": "string", + "enum": [ + "appreciation", + "inspiring", + "feature_request", + "bug_report", + "account_issue", + "financial_issue", + "content_complaint", + "critical", + "general_question", + "spam", + "other" + ] + }, + "review_status": { + "title": "Review status", + "type": "string", + "enum": ["pending", "responded", "escalated", "resolved"] + }, + "needs_human_intervention": { + "title": "Needs human intervention", + "type": "boolean" + }, + "prevent_auto_reply": { + "title": "غیرفعال‌سازی پاسخ خودکار (بلاک مکالمه اتوماتیک)", + "type": "boolean" + }, + "conversation_history": { + "title": "Conversation history", + "description": "List of message dicts for this user's entire conversation", + "type": "object" + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "talk_provider_profile": { + "required": ["languages", "avatar"], + "type": "object", + "properties": { + "full_name": { + "title": "Full name", + "type": "string", + "maxLength": 254, + "minLength": 1, + "x-nullable": true + }, + "bio": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "birthdate": { + "title": "Birthdate", + "type": "string", + "format": "date", + "x-nullable": true + }, + "email": { + "title": "Email", + "type": "string", + "format": "email", + "maxLength": 254, + "x-nullable": true + }, + "wa_number": { + "title": "Whatsapp number", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "institution_name": { + "title": "Name", + "description": "Name of the institute", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "languages": { "type": "array", "items": { "type": "string" } }, + "avatar": { "title": "Avatar", "type": "string", "minLength": 1 }, + "social_medias": { + "title": "Social medias", + "description": "Provider social media profiles", + "type": "object" + } + } + }, + "BookmarkSerializers": { + "required": ["service", "content_id"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "related_object": { + "title": "Related object", + "type": "string", + "readOnly": true + }, + "service": { + "title": "Service", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "content_id": { + "title": "Content id", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "text": { "title": "Text", "type": "string", "x-nullable": true }, + "status": { "title": "Status", "type": "boolean", "readOnly": true }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "user": { "title": "User", "type": "integer", "readOnly": true } + } + }, + "Calendar": { + "required": ["type"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "countries": { + "title": "Countries", + "type": "string", + "readOnly": true + }, + "type": { "title": "Type", "type": "string", "minLength": 1 }, + "event_type": { + "title": "Event type", + "type": "string", + "enum": ["national", "international", "religious"], + "x-nullable": true + }, + "holiday_in_countries": { + "title": "Holiday in countries", + "type": "string", + "readOnly": true + }, + "dates": { "title": "Dates", "type": "string", "readOnly": true }, + "is_yearly": { + "title": "Is yearly", + "description": "check this field if event is annually", + "type": "boolean" + }, + "has_occasion_detail": { + "title": "Has occasion detail", + "type": "string", + "readOnly": true + } + } + }, + "Language": { + "required": ["name", "code"], + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "code": { + "title": "Code", + "type": "string", + "maxLength": 2, + "minLength": 1 + } + } + }, + "MasaelCategories": { + "required": ["language"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "masael_index": { + "title": "Masael index", + "type": "string", + "readOnly": true + }, + "language": { "$ref": "#/definitions/Language" }, + "children": { "title": "Children", "type": "string", "readOnly": true } + } + }, + "CheckupParameterDetailSerializerV2": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + }, + "hadith": { "title": "Hadith", "type": "string", "readOnly": true } + } + }, + "CommandHelp": { + "required": ["service"], + "type": "object", + "properties": { + "service": { + "title": "Service", + "type": "string", + "enum": [ + "hussainiyah", + "library", + "Talk", + "meet", + "mafatih", + "hadith", + "quran", + "ahkam", + "coin", + "calendar", + "qiblah", + "elalHabib", + "main" + ] + }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + } + } + }, + "CommandSuggestion": { + "required": ["language_code"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "x-nullable": true }, + "language_code": { + "title": "Language code", + "description": "Language code (e.g., en, fa)", + "type": "string", + "maxLength": 10, + "minLength": 1 + } + } + }, + "DonateUser": { + "required": ["amount"], + "type": "object", + "properties": { + "amount": { "title": "Amount", "type": "string", "format": "decimal" }, + "phone": { + "title": "Phone", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "pay_method": { + "title": "Pay method", + "type": "string", + "enum": ["paypal", "vtb", "stripe"], + "default": "stripe" + } + } + }, + "DontKillApp": { + "required": ["brand", "sdk_version", "description"], + "type": "object", + "properties": { + "brand": { + "type": "array", + "items": { + "title": "Brand", + "type": "string", + "maxLength": 100, + "minLength": 1 + } + }, + "sdk_version": { + "type": "array", + "items": { + "title": "Sdk version", + "type": "integer", + "maximum": 35, + "minimum": 0 + } + }, + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + } + } + }, + "EightmagCategories": { + "required": ["name"], + "type": "object", + "properties": { + "url": { "title": "Url", "type": "string", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 512, + "minLength": 1 + }, + "thumbnails": { + "title": "Thumbnails", + "type": "string", + "readOnly": true + }, + "children": { "title": "Children", "type": "string", "readOnly": true } + } + }, + "EightmagCategoriesInList": { + "required": ["name"], + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string", + "maxLength": 512, + "minLength": 1 + }, + "url": { "title": "Url", "type": "string", "readOnly": true } + } + }, + "EightmagList": { + "required": ["title"], + "type": "object", + "properties": { + "url": { "title": "Url", "type": "string", "readOnly": true }, + "categories": { + "type": "array", + "items": { "$ref": "#/definitions/EightmagCategoriesInList" }, + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "event": { "$ref": "#/definitions/Calendar" }, + "created_at": { + "title": "Created at", + "type": "string", + "readOnly": true + }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "summary": { + "title": "Summary", + "description": "we use it for seo and short description of post", + "type": "string", + "x-nullable": true + }, + "as_special": { + "title": "As special", + "description": "enable as special blog for showing in home page", + "type": "boolean" + }, + "pin_top": { + "title": "Pin top", + "description": "چسباندن پست به بالا", + "type": "boolean" + }, + "status": { + "title": "Status", + "description": "model status to be shown or not", + "type": "boolean" + }, + "author": { + "title": "Author", + "type": "string", + "maxLength": 119, + "minLength": 1, + "x-nullable": true + }, + "like_count": { + "title": "Like count", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "source": { "title": "Source", "type": "integer", "x-nullable": true }, + "publisher": { + "title": "Publisher", + "type": "integer", + "x-nullable": true + } + } + }, + "EightmagDetails": { + "required": ["title", "content"], + "type": "object", + "properties": { + "url": { "title": "Url", "type": "string", "readOnly": true }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "categories": { + "type": "array", + "items": { "$ref": "#/definitions/EightmagCategoriesInList" }, + "readOnly": true + }, + "author": { "title": "Author", "type": "string", "readOnly": true }, + "event": { "$ref": "#/definitions/Calendar" }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "content": { "title": "Content", "type": "string", "minLength": 1 }, + "summary": { + "title": "Summary", + "description": "we use it for seo and short description of post", + "type": "string", + "x-nullable": true + }, + "as_special": { + "title": "As special", + "description": "enable as special blog for showing in home page", + "type": "boolean" + }, + "pin_top": { + "title": "Pin top", + "description": "چسباندن پست به بالا", + "type": "boolean" + }, + "status": { + "title": "Status", + "description": "model status to be shown or not", + "type": "boolean" + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "like_count": { + "title": "Like count", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "source": { "title": "Source", "type": "integer", "x-nullable": true }, + "publisher": { + "title": "Publisher", + "type": "integer", + "x-nullable": true + } + } + }, + "ElalHabib": { + "type": "object", + "properties": { + "title": { "title": "نام موکب", "type": "object" }, + "nationalities": { + "type": "array", + "items": { "type": "string", "x-nullable": true }, + "default": [], + "x-nullable": true + }, + "capacity": { + "title": "ظرفیت اسکان", + "type": "integer", + "maximum": 32767, + "minimum": 0, + "x-nullable": true + }, + "options": { "title": "Options", "type": "string", "readOnly": true }, + "after_amood": { + "title": "After amood", + "type": "string", + "readOnly": true + }, + "events": { "title": "Events", "type": "string", "readOnly": true }, + "description": { + "title": "توضیحات", + "type": "string", + "x-nullable": true + } + } + }, + "ElalHabibSingerInList": { + "required": ["slug"], + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 255, + "minLength": 1 + } + } + }, + "DiscountCodeUsage": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "discount_code": { + "title": "Discount code", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "user_username": { + "title": "User username", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "service_name": { + "title": "Service name", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "object_id": { + "title": "Object ID", + "type": "integer", + "readOnly": true + }, + "original_price": { + "title": "Original Price", + "type": "string", + "format": "decimal", + "readOnly": true + }, + "discounted_price": { + "title": "Discounted Price", + "type": "string", + "format": "decimal", + "readOnly": true + }, + "discount_amount": { + "title": "Discount Amount", + "type": "string", + "format": "decimal", + "readOnly": true + }, + "used_at": { + "title": "Used At", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "Package": { + "required": ["coin_count", "price"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "package_type": { + "title": "Package type", + "type": "string", + "enum": ["normal", "timely", "evently"] + }, + "coin_count": { + "title": "Coin count", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "purchase_id": { + "title": "Purchase ID", + "description": "Unique identifier for products purchased on Google Play and App Store, used for tracking transactions.", + "type": "string", + "maxLength": 55, + "x-nullable": true + }, + "price": { "title": "Price", "type": "string", "format": "decimal" }, + "off_price": { + "title": "Off price", + "description": "Optional", + "type": "string", + "format": "decimal", + "x-nullable": true + }, + "discount_percentage": { + "title": "Discount percentage", + "type": "string", + "readOnly": true + }, + "expiration_duration_days": { + "title": "Expiration duration days", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "event_name": { + "title": "Event name", + "type": "string", + "maxLength": 100, + "x-nullable": true + } + } + }, + "Support": { + "required": ["type", "description", "whatsapp_number"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "user": { "title": "User", "type": "integer", "readOnly": true }, + "type": { + "title": "Type", + "type": "string", + "enum": ["technical", "billing", "general"] + }, + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + }, + "whatsapp_number": { + "title": "Whatsapp number", + "type": "string", + "maxLength": 15, + "minLength": 1 + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "service": { "title": "Service", "type": "string", "minLength": 1 } + } + }, + "Transactions": { + "required": ["payment_method", "price", "coin_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "status": { + "title": "Status", + "type": "string", + "enum": ["pending", "success", "failed"] + }, + "payment_method": { + "title": "Payment method", + "type": "string", + "maxLength": 20, + "minLength": 1 + }, + "price": { "title": "Price", "type": "integer" }, + "coin_count": { "title": "Coin count", "type": "integer" }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "package": { "$ref": "#/definitions/Package" } + } + }, + "UserCoinUsage": { + "required": ["package", "coin_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "package": { "$ref": "#/definitions/Package" }, + "service_details": { + "title": "Service details", + "type": "object", + "readOnly": true + }, + "at_time": { + "title": "At time", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "coin_count": { + "title": "Coin count", + "type": "integer", + "maximum": 32767, + "minimum": 0 + } + } + }, + "UserPackage": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "coin_count": { + "title": "Coin count", + "type": "integer", + "readOnly": true + }, + "price": { "title": "Price", "type": "integer", "readOnly": true }, + "used_count": { + "title": "Used count", + "type": "integer", + "readOnly": true + }, + "remaining_count": { + "title": "Remaining count", + "type": "integer", + "readOnly": true + }, + "package": { "$ref": "#/definitions/Package" } + } + }, + "MeetSerializer": { + "required": ["name", "online_users_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "description": "Name of the meet", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "description": { + "title": "Description", + "description": "Description of the meet", + "type": "string", + "x-nullable": true + }, + "next_session_subject": { + "title": "Next Session Subject", + "description": "Subject of the next session", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "next_session_schedule": { + "title": "Next Session Schedule", + "description": "Scheduled date and time for the next session", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "is_suggested": { + "title": "Is Suggested", + "description": "Is this meet suggested?", + "type": "boolean" + }, + "provider": { "title": "Provider", "type": "string", "readOnly": true }, + "is_free": { + "title": "Is Free", + "description": "Is this meet free?", + "type": "boolean" + }, + "price": { + "title": "Price", + "description": "Price of the meet if it is not free", + "type": "string", + "format": "decimal", + "x-nullable": true + }, + "is_live": { + "title": "Is Live", + "description": "Is the meet currently live?", + "type": "boolean" + }, + "is_closed": { + "title": "Is closed", + "type": "string", + "readOnly": true + }, + "online_users_count": { + "title": "Online users count", + "type": "integer" + }, + "language": { "title": "Language", "type": "string", "readOnly": true }, + "categories": { + "title": "Categories", + "description": "Categories related to the meet", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "organizer": { + "title": "Organizer", + "type": "string", + "readOnly": true + }, + "is_provider": { + "title": "Is provider", + "type": "string", + "readOnly": true + }, + "has_access": { + "title": "Has access", + "type": "string", + "readOnly": true + }, + "is_reminder": { + "title": "Is reminder", + "type": "string", + "readOnly": true + }, + "live_session_id": { + "title": "Live session id", + "type": "string", + "readOnly": true + }, + "has_archive": { + "title": "Has archive", + "type": "string", + "readOnly": true + }, + "has_recordings": { + "title": "Has recordings", + "type": "string", + "readOnly": true + }, + "access": { + "title": "Access", + "description": "Access type of the meet (public or private)", + "type": "string", + "enum": ["public", "private"] + }, + "password": { + "title": "Password", + "description": "Password for private meets", + "type": "string", + "maxLength": 50, + "x-nullable": true + } + } + }, + "MeetCreate": { + "required": ["name", "language"], + "type": "object", + "properties": { + "name": { + "title": "Name", + "description": "Name of the meet", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "price": { + "title": "Price", + "type": "string", + "format": "decimal", + "default": "0.00", + "x-nullable": true + }, + "language": { "title": "Language", "type": "string", "minLength": 1 }, + "description": { + "title": "Description", + "description": "Description of the meet", + "type": "string", + "x-nullable": true + }, + "is_free": { + "title": "Is Free", + "description": "Is this meet free?", + "type": "boolean" + } + } + }, + "MeetCreateV2": { + "required": ["name", "language"], + "type": "object", + "properties": { + "name": { + "title": "Name", + "description": "Name of the meet", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "price": { + "title": "Price", + "type": "string", + "format": "decimal", + "default": "0.00", + "x-nullable": true + }, + "language": { "title": "Language", "type": "string", "minLength": 1 }, + "description": { + "title": "Description", + "description": "Description of the meet", + "type": "string", + "x-nullable": true + }, + "is_free": { + "title": "Is Free", + "description": "Is this meet free?", + "type": "boolean" + }, + "access": { + "title": "Access", + "type": "string", + "enum": ["public", "private"], + "default": "public" + }, + "password": { + "title": "Password", + "type": "string", + "maxLength": 50, + "x-nullable": true + } + } + }, + "MeetProviderProfile": { + "required": ["languages"], + "type": "object", + "properties": { + "full_name": { + "title": "Full name", + "type": "string", + "maxLength": 254, + "minLength": 1, + "x-nullable": true + }, + "bio": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "birthdate": { + "title": "Birthdate", + "type": "string", + "format": "date", + "x-nullable": true + }, + "email": { + "title": "Email", + "type": "string", + "format": "email", + "maxLength": 254, + "x-nullable": true + }, + "wa_number": { + "title": "Whatsapp number", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "institution_name": { + "title": "Name", + "description": "Name of the institute", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "languages": { "type": "array", "items": { "type": "string" } }, + "avatar": { "title": "Avatar", "type": "string", "minLength": 1 }, + "social_medias": { + "title": "Social medias", + "description": "Provider social media profiles", + "type": "object" + } + } + }, + "ProviderMeetSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "email": { "title": "Email", "type": "string", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "bio": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "slogn": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + } + } + }, + "ProviderDetailMeetSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "email": { "title": "Email", "type": "string", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "slogn": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "bio": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "other_provider_services": { + "title": "Other provider services", + "type": "string", + "readOnly": true + } + } + }, + "MeetProviderRoom": { + "required": ["name", "reminder_count", "purchase_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "description": "Name of the meet", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "next_session_subject": { + "title": "Next Session Subject", + "description": "Subject of the next session", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "next_session_schedule": { + "title": "Next Session Schedule", + "description": "Scheduled date and time for the next session", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "language": { "title": "Language", "type": "string", "readOnly": true }, + "is_free": { + "title": "Is Free", + "description": "Is this meet free?", + "type": "boolean" + }, + "price": { + "title": "Price", + "description": "Price of the meet if it is not free", + "type": "string", + "format": "decimal", + "x-nullable": true + }, + "is_closed": { + "title": "Is closed", + "type": "string", + "readOnly": true + }, + "description": { + "title": "Description", + "description": "Description of the meet", + "type": "string", + "x-nullable": true + }, + "provider": { "title": "Provider", "type": "string", "readOnly": true }, + "reminder_count": { "title": "Reminder count", "type": "integer" }, + "categories": { + "title": "Categories", + "description": "Categories related to the meet", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "purchase_count": { "title": "Purchase count", "type": "integer" }, + "archive_count": { + "title": "Archive count", + "type": "string", + "readOnly": true + }, + "is_active": { + "title": "Is Active", + "description": "Is this meet currently active?", + "type": "boolean" + }, + "status": { "title": "Status", "type": "string", "readOnly": true }, + "access": { + "title": "Access", + "type": "string", + "enum": ["public", "private"], + "readOnly": true + }, + "password": { + "title": "Password", + "type": "string", + "readOnly": true, + "maxLength": 50, + "minLength": 1, + "x-nullable": true + } + } + }, + "MeetDetailSerializer": { + "required": ["name", "online_users_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "description": "Name of the meet", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "description": { + "title": "Description", + "description": "Description of the meet", + "type": "string", + "x-nullable": true + }, + "next_session_subject": { + "title": "Next Session Subject", + "description": "Subject of the next session", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "next_session_schedule": { + "title": "Next Session Schedule", + "description": "Scheduled date and time for the next session", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "is_suggested": { + "title": "Is Suggested", + "description": "Is this meet suggested?", + "type": "boolean" + }, + "provider": { "title": "Provider", "type": "string", "readOnly": true }, + "is_free": { + "title": "Is Free", + "description": "Is this meet free?", + "type": "boolean" + }, + "price": { + "title": "Price", + "description": "Price of the meet if it is not free", + "type": "string", + "format": "decimal", + "x-nullable": true + }, + "is_live": { + "title": "Is Live", + "description": "Is the meet currently live?", + "type": "boolean" + }, + "is_closed": { + "title": "Is closed", + "type": "string", + "readOnly": true + }, + "online_users_count": { + "title": "Online users count", + "type": "integer" + }, + "language": { "title": "Language", "type": "string", "readOnly": true }, + "categories": { + "title": "Categories", + "description": "Categories related to the meet", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "organizer": { + "title": "Organizer", + "type": "string", + "readOnly": true + }, + "is_provider": { + "title": "Is provider", + "type": "string", + "readOnly": true + }, + "live_session_id": { + "title": "Live session id", + "type": "string", + "readOnly": true + }, + "has_archive": { + "title": "Has archive", + "type": "string", + "readOnly": true + }, + "recordings": { + "title": "Recordings", + "type": "string", + "readOnly": true + }, + "access": { + "title": "Access", + "type": "string", + "enum": ["public", "private"] + }, + "password": { + "title": "Password", + "type": "string", + "maxLength": 50, + "x-nullable": true + }, + "has_recording": { + "title": "Has recording", + "type": "string", + "readOnly": true + } + } + }, + "SessionArchiveSerializer": { + "required": ["recorded_file", "session_id"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "meet": { + "title": "Meet", + "description": "The meet this session belongs to", + "type": "integer", + "readOnly": true + }, + "started_at": { + "title": "Started At", + "description": "Session start time", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "ended_at": { + "title": "Ended At", + "description": "Session end time", + "type": "string", + "format": "date-time", + "readOnly": true, + "x-nullable": true + }, + "recorded_file": { + "title": "Recorded file", + "type": "string", + "minLength": 1 + }, + "subject": { + "title": "Subject", + "description": "Subject of the session", + "type": "string", + "readOnly": true, + "minLength": 1, + "x-nullable": true + }, + "session_id": { "title": "Session id", "type": "integer" } + } + }, + "ReportSerializer": { + "required": ["report_type"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "meet_id": { "title": "Meet id", "type": "integer", "readOnly": true }, + "description": { + "title": "Description", + "description": "Description of the report", + "type": "string", + "x-nullable": true + }, + "report_type": { + "title": "Type", + "description": "Type of the report", + "type": "string", + "enum": ["bug", "feedback", "other"] + } + } + }, + "SessionCreate": { + "required": ["name", "is_start"], + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "minLength": 1 }, + "date_time": { + "title": "Date time", + "description": "Enter the date and time in the format YYYY-MM-DD HH:MM:SS", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "is_start": { "title": "Is start", "type": "boolean" } + } + }, + "SessionRecordingCreateUpdateSerializer": { + "required": ["session", "file", "recording_type"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "description": "Title of the recording", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "session": { "title": "Session", "type": "integer" }, + "file": { "title": "File", "type": "string", "minLength": 1 }, + "file_time": { + "title": "File Duration", + "description": "Duration of the recording file", + "type": "string", + "x-nullable": true + }, + "recording_type": { + "title": "Recording type", + "type": "string", + "enum": ["voice", "video"] + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "created_at": { + "title": "Created At", + "description": "Time the recording was created", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated At", + "description": "The datetime when the recording was last updated", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "SessionFileUpload": { + "type": "object", + "properties": { + "recorded_file": { + "title": "Recorded File", + "description": "File of the recorded session", + "type": "string", + "readOnly": true, + "x-nullable": true, + "format": "uri" + } + } + }, + "CenterTag": { + "required": ["id", "name"], + "type": "object", + "properties": { + "id": { "title": "Id", "type": "integer" }, + "name": { "title": "Name", "type": "object" } + } + }, + "CenterList": { + "required": ["name", "slogan"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slogan": { + "title": "Slogan", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "tags": { + "type": "array", + "items": { "$ref": "#/definitions/CenterTag" }, + "readOnly": true + }, + "country": { + "title": "Country", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "city": { + "title": "City", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "lat": { "title": "Lat", "type": "number", "x-nullable": true }, + "lon": { "title": "Lon", "type": "number", "x-nullable": true }, + "distance": { "title": "Distance", "type": "string", "readOnly": true }, + "is_bookmarked": { + "title": "Is bookmarked", + "type": "string", + "readOnly": true + } + } + }, + "CenterDetail": { + "required": ["name", "slogan"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slogan": { + "title": "Slogan", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "header_image": { + "title": "Header image", + "type": "string", + "readOnly": true + }, + "tags": { + "type": "array", + "items": { "$ref": "#/definitions/CenterTag" }, + "readOnly": true + }, + "country": { + "title": "Country", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "city": { + "title": "City", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "lat": { "title": "Lat", "type": "number", "x-nullable": true }, + "lon": { "title": "Lon", "type": "number", "x-nullable": true }, + "address": { + "title": "Address", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "website": { + "title": "Website", + "type": "string", + "maxLength": 190, + "x-nullable": true + }, + "phone_numbers": { + "title": "Phone numbers", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "principal_name": { + "title": "Principal name", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "working_hours": { "title": "Working hours", "type": "object" }, + "social_medias": { "title": "Social medias", "type": "object" }, + "congregations_prayers": { + "title": "Congregations prayers", + "type": "object" + }, + "imam_name": { + "title": "Imam name", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "about_center": { + "title": "About center", + "type": "string", + "x-nullable": true + }, + "google_map_link": { + "title": "Google map link", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "stars": { "title": "Stars", "type": "number", "x-nullable": true }, + "gallery": { "title": "Gallery", "type": "string", "readOnly": true }, + "distance": { "title": "Distance", "type": "string", "readOnly": true }, + "is_bookmarked": { + "title": "Is bookmarked", + "type": "string", + "readOnly": true + } + } + }, + "CenterEvent": { + "required": ["title", "date", "description"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 119, + "minLength": 1 + }, + "start_time": { + "title": "Start time", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "end_time": { + "title": "End time", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "date": { "title": "Date", "type": "string", "format": "date-time" }, + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + }, + "image": { "title": "Image", "type": "string", "readOnly": true } + } + }, + "CenterProviderProfile": { + "required": [ + "provider_type", + "full_name", + "email", + "whatsapp_number", + "role" + ], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "provider_type": { + "title": "Provider type", + "description": "Type of provider: management team member or connected team member", + "type": "string", + "enum": ["management", "connected"] + }, + "full_name": { + "title": "Full name", + "description": "Full name of the provider", + "type": "string", + "maxLength": 550, + "minLength": 1 + }, + "email": { + "title": "Email", + "description": "Email address of the provider", + "type": "string", + "format": "email", + "maxLength": 254, + "minLength": 1 + }, + "whatsapp_number": { + "title": "Whatsapp number", + "description": "WhatsApp number (9-15 digits)", + "type": "string", + "maxLength": 55, + "minLength": 1 + }, + "role": { + "title": "Role", + "description": "Role or position of the provider", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "management_contact_name": { + "title": "Management contact name", + "description": "Name of management contact (optional, typically for connected team members)", + "type": "string", + "maxLength": 550, + "x-nullable": true + }, + "is_verified": { + "title": "Is verified", + "description": "Whether this provider profile has been verified", + "type": "boolean", + "readOnly": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "ChallengeList": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "image": { "title": "Image", "type": "string", "readOnly": true }, + "summary": { "title": "Summary", "type": "string", "readOnly": true }, + "is_unlimited": { "title": "Is unlimited", "type": "boolean" }, + "duration_days": { + "title": "Duration days", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "status": { "title": "Is it displayed?", "type": "boolean" }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "participant_count": { + "title": "Participant count", + "type": "string", + "readOnly": true + }, + "is_participant": { + "title": "Is participant", + "type": "string", + "readOnly": true + } + } + }, + "ChallengeDetail": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "image": { "title": "Image", "type": "string", "readOnly": true }, + "summary": { "title": "Summary", "type": "string", "readOnly": true }, + "is_unlimited": { "title": "Is unlimited", "type": "boolean" }, + "duration_days": { + "title": "Duration days", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "status": { "title": "Is it displayed?", "type": "boolean" }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "participant_count": { + "title": "Participant count", + "type": "string", + "readOnly": true + }, + "is_participant": { + "title": "Is participant", + "type": "string", + "readOnly": true + }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + } + } + }, + "UserChecklistItem": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "is_active": { "title": "Is active", "type": "boolean" }, + "custom_days": { + "type": "array", + "items": { "type": "string", "x-nullable": true } + }, + "has_details": { + "title": "Has details", + "type": "string", + "readOnly": true + }, + "task_type": { + "title": "Task type", + "type": "string", + "readOnly": true + } + } + }, + "ChecklistEntryList": { + "required": ["id", "title", "completed"], + "type": "object", + "properties": { + "id": { "title": "Id", "type": "integer" }, + "title": { "title": "Title", "type": "string", "minLength": 1 }, + "completed": { "title": "Completed", "type": "boolean" }, + "has_details": { + "title": "Has details", + "type": "boolean", + "default": false + } + } + }, + "ChecklistStats": { + "required": ["total_days", "completed_days", "percentage"], + "type": "object", + "properties": { + "total_days": { "title": "Total days", "type": "integer" }, + "completed_days": { "title": "Completed days", "type": "integer" }, + "percentage": { "title": "Percentage", "type": "number" } + } + }, + "ChecklistDetail": { + "required": ["content"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "content": { "title": "Content", "type": "string", "minLength": 1 }, + "language": { "title": "Language", "type": "integer" }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "HadisCategory": { + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "readOnly": true }, + "hadis_count": { + "title": "Hadis count", + "type": "string", + "readOnly": true + }, + "thumbnails": { + "title": "Thumbnails", + "type": "string", + "readOnly": true + }, + "children": { "title": "Children", "type": "string", "readOnly": true } + } + }, + "Reference": { + "type": "object", + "properties": { + "book": { + "title": "Book", + "type": "string", + "readOnly": true, + "x-nullable": true + }, + "ref_doc_numb": { + "title": "Vol", + "type": "string", + "maxLength": 64, + "x-nullable": true + }, + "ref_doc_page": { + "title": "Page", + "type": "string", + "maxLength": 64, + "x-nullable": true + }, + "ref_hadis_num": { + "title": "Number", + "type": "string", + "maxLength": 64, + "x-nullable": true + }, + "ref_text": { + "title": "Text", + "type": "string", + "maxLength": 200, + "x-nullable": true + } + }, + "x-nullable": true + }, + "Hadis": { + "required": ["number", "text", "total_grade", "level"], + "type": "object", + "properties": { + "number": { + "title": "Number", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "text": { "title": "Text", "type": "string", "minLength": 1 }, + "translation": { + "title": "Translation", + "type": "string", + "readOnly": true + }, + "narrated_by": { + "title": "Narrated by", + "type": "string", + "readOnly": true + }, + "references": { + "type": "array", + "items": { "$ref": "#/definitions/Reference" }, + "readOnly": true, + "x-nullable": true + }, + "total_grade": { + "title": "Total grade", + "type": "integer", + "x-nullable": true + }, + "level": { "title": "Level", "type": "integer", "x-nullable": true } + } + }, + "Interest": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "icon": { + "title": "Icon name", + "description": "Fontawesome icon name", + "type": "string", + "maxLength": 64, + "x-nullable": true + } + } + }, + "Narrator": { + "required": ["hadis_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "hadis_count": { + "title": "Hadis count", + "type": "integer", + "x-nullable": true + }, + "photo": { + "title": "Photo", + "type": "string", + "readOnly": true, + "x-nullable": true, + "format": "uri" + } + } + }, + "Resources": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + } + } + }, + "Trend": { + "type": "object", + "properties": { + "title": { "title": "Title", "type": "string", "readOnly": true }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "hadis_count": { + "title": "Hadis count", + "type": "string", + "readOnly": true + }, + "hadis_id_list": { + "title": "Hadis id list", + "type": "string", + "readOnly": true + } + } + }, + "UserInterest": { + "required": ["interests_ids", "gender", "age"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "user": { + "title": "User", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "interests": { + "type": "array", + "items": { "$ref": "#/definitions/Interest" }, + "readOnly": true + }, + "interests_ids": { "type": "array", "items": { "type": "integer" } }, + "gender": { + "title": "Gender", + "type": "string", + "enum": ["male", "female"] + }, + "age": { + "title": "Age", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "tend_to_marry": { + "title": "Tend to marry", + "type": "boolean", + "x-nullable": true + }, + "marital_status": { + "title": "Marital status", + "type": "boolean", + "x-nullable": true + }, + "has_children": { + "title": "Has children", + "type": "boolean", + "x-nullable": true + } + } + }, + "HadisSerializerV2": { + "required": ["number", "text", "total_grade", "level"], + "type": "object", + "properties": { + "number": { + "title": "Number", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "text": { "title": "Text", "type": "string", "minLength": 1 }, + "translation": { + "title": "Translation", + "type": "string", + "readOnly": true + }, + "narrated_by": { + "title": "Narrated by", + "type": "string", + "readOnly": true + }, + "references": { + "type": "array", + "items": { "$ref": "#/definitions/Reference" }, + "readOnly": true, + "x-nullable": true + }, + "total_grade": { + "title": "Total grade", + "type": "integer", + "x-nullable": true + }, + "level": { "title": "Level", "type": "integer", "x-nullable": true }, + "tags": { "title": "Tags", "type": "string", "readOnly": true } + } + }, + "NarratorSerializerV2": { + "required": ["hadis_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "hadis_count": { + "title": "Hadis count", + "type": "integer", + "x-nullable": true + }, + "photo": { + "title": "Photo", + "type": "string", + "readOnly": true, + "x-nullable": true, + "format": "uri" + }, + "hadis_index": { + "title": "Hadis index", + "type": "string", + "readOnly": true + } + } + }, + "AlbumList": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "dates": { "title": "Dates", "type": "object" }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 2147483647, + "minimum": -2147483648 + }, + "songs_count": { + "title": "Songs count", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "singer_type_counts": { + "title": "Singer type counts", + "type": "string", + "readOnly": true + } + } + }, + "SingersList": { + "required": ["slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "singer_type": { + "title": "Singer type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + "songs_count": { + "title": "Songs count", + "type": "integer", + "readOnly": true + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 255, + "minLength": 1 + }, + "languages": { + "type": "array", + "items": { "type": "string" }, + "readOnly": true, + "uniqueItems": true + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "lang": { + "title": "Lang", + "type": "string", + "readOnly": true, + "minLength": 1 + } + } + }, + "GenreList": { + "required": ["title"], + "type": "object", + "properties": { + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 119, + "minLength": 1 + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + } + } + }, + "Publisher": { + "required": ["name", "songs_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "url": { + "title": "Url", + "type": "string", + "format": "uri", + "maxLength": 200, + "x-nullable": true + }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "description": { + "title": "Description", + "type": "string", + "maxLength": 1024, + "x-nullable": true + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "readOnly": true + }, + "type": { + "title": "Type", + "type": "string", + "enum": ["YT", "IT", "WS", "TG", "AP"] + }, + "languages": { + "type": "array", + "items": { "$ref": "#/definitions/Language" }, + "readOnly": true + }, + "songs_count": { + "title": "Songs count", + "type": "integer", + "x-nullable": true + } + } + }, + "SongsList": { + "required": ["slug"], + "type": "object", + "properties": { + "relative_url": { + "title": "Relative url", + "type": "string", + "readOnly": true + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 50, + "minLength": 1 + }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "singers": { + "type": "array", + "items": { "$ref": "#/definitions/SingersList" }, + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "genre": { "$ref": "#/definitions/GenreList" }, + "song_type": { + "title": "Song type", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + "file": { "title": "File", "type": "string", "readOnly": true }, + "published_date": { + "title": "Published date", + "type": "string", + "format": "date", + "x-nullable": true + }, + "subtitle_languages": { + "type": "array", + "items": { "$ref": "#/definitions/Language" }, + "readOnly": true + }, + "language": { + "type": "array", + "items": { "$ref": "#/definitions/Language" }, + "readOnly": true + }, + "publisher": { "$ref": "#/definitions/Publisher" }, + "like_count": { + "title": "Like count", + "type": "string", + "readOnly": true + }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0 + }, + "is_liked": { "title": "Is liked", "type": "string", "readOnly": true }, + "is_youtube": { + "title": "Is youtube", + "type": "boolean", + "readOnly": true + }, + "is_playlist": { + "title": "Is playlist", + "type": "string", + "readOnly": true + } + } + }, + "CollectionList": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "collection_type": { + "title": "Collection type", + "type": "string", + "enum": ["all", "audio", "video", "youtube"], + "x-nullable": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "songs_count": { + "title": "Songs count", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "songs": { "title": "Songs", "type": "string", "readOnly": true } + } + }, + "CollectionDetail": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "collection_type": { + "title": "Collection type", + "type": "string", + "enum": ["all", "audio", "video", "youtube"], + "x-nullable": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "songs_count": { + "title": "Songs count", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "songs": { "title": "Songs", "type": "string", "readOnly": true } + } + }, + "DashboardAlbumRow": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "translations": { "title": "Title", "type": "object" }, + "dates": { "title": "Dates", "type": "object" }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "status": { "title": "Status", "type": "boolean" }, + "is_pinned": { "title": "Pinned", "type": "boolean" }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 2147483647, + "minimum": -2147483648 + }, + "song_count": { + "title": "Song count", + "type": "integer", + "readOnly": true + }, + "langs": { "title": "Langs", "type": "string", "readOnly": true }, + "letter": { "title": "Letter", "type": "string", "readOnly": true }, + "updated": { + "title": "Updated", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "DashboardAlbumInput": { + "type": "object", + "properties": { + "translations": { "title": "Title", "type": "object" }, + "dates": { "title": "Dates", "type": "object" }, + "status": { "title": "Status", "type": "boolean" }, + "is_pinned": { "title": "Pinned", "type": "boolean" }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "x-nullable": true + } + } + }, + "_AlbumAutocomplete": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true } + } + }, + "_GenreAutocomplete": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + } + } + }, + "_PublisherAutocomplete": { + "required": ["name"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + } + } + }, + "_SingerAutocomplete": { + "required": ["slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 255, + "minLength": 1 + }, + "singer_type": { + "title": "Singer type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + } + } + }, + "_SongAutocomplete": { + "required": ["slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 50, + "minLength": 1 + } + } + }, + "_TagAutocomplete": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true } + } + }, + "DashboardCollectionRow": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "object" }, + "title_display": { + "title": "Title display", + "type": "string", + "readOnly": true + }, + "dates": { "title": "Dates", "type": "object" }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "status": { "title": "Status", "type": "boolean" }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "ordering": { + "title": "Display order", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "song_count": { + "title": "Song count", + "type": "integer", + "readOnly": true + }, + "songs": { "title": "Songs", "type": "string", "readOnly": true }, + "letter": { "title": "Letter", "type": "string", "readOnly": true }, + "updated": { + "title": "Updated", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "DashboardCollectionInput": { + "type": "object", + "properties": { + "title": { "title": "Title", "type": "object" }, + "dates": { "title": "Dates", "type": "object" }, + "status": { "title": "Status", "type": "boolean" }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "ordering": { + "title": "Display order", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "songs": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "x-nullable": true + } + } + }, + "DashboardGenreRow": { + "required": ["title"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 119, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "song_count": { + "title": "Song count", + "type": "integer", + "readOnly": true + }, + "letter": { "title": "Letter", "type": "string", "readOnly": true } + } + }, + "DashboardGenreInput": { + "required": ["title"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 119, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$" + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "x-nullable": true + } + } + }, + "ImportItemRow": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "source": { + "title": "Source", + "type": "string", + "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"], + "readOnly": true + }, + "input_kind": { + "title": "Input kind", + "type": "string", + "enum": ["direct_link", "channel_page"], + "readOnly": true + }, + "origin": { + "title": "Origin", + "type": "string", + "enum": ["direct_link", "channel_page", "scheduled_task"], + "readOnly": true + }, + "source_url": { + "title": "Source url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "canonical_url": { + "title": "Canonical url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "external_id": { + "title": "External id", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "title": { + "title": "Title", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "singer_name": { + "title": "Singer name", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "duration_seconds": { + "title": "Duration seconds", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "source_published_at": { + "title": "Source published at", + "type": "string", + "format": "date-time", + "readOnly": true, + "x-nullable": true + }, + "status": { + "title": "Status", + "type": "string", + "enum": [ + "queued", + "discovering", + "downloading", + "processing", + "ai_detecting", + "metadata_review", + "ready_to_publish", + "published", + "duplicate", + "failed", + "cancelled" + ], + "readOnly": true + }, + "stage": { + "title": "Stage", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "progress": { + "title": "Progress", + "type": "integer", + "readOnly": true + }, + "ai_status": { + "title": "AI status", + "type": "string", + "enum": ["pending", "running", "success", "failed", "skipped"], + "readOnly": true + }, + "ai_confidence": { + "title": "AI confidence", + "type": "number", + "readOnly": true, + "x-nullable": true + }, + "needs_metadata_review": { + "title": "Needs metadata review", + "type": "boolean", + "readOnly": true + }, + "error_message": { + "title": "Error message", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "song_id": { "title": "Song id", "type": "string", "readOnly": true }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + } + } + }, + "ImportItemCreate": { + "required": ["source_url"], + "type": "object", + "properties": { + "source_url": { + "title": "Source url", + "type": "string", + "maxLength": 1024, + "minLength": 1 + } + } + }, + "ImportItemDetail": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "source": { + "title": "Source", + "type": "string", + "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"], + "readOnly": true + }, + "input_kind": { + "title": "Input kind", + "type": "string", + "enum": ["direct_link", "channel_page"], + "readOnly": true + }, + "origin": { + "title": "Origin", + "type": "string", + "enum": ["direct_link", "channel_page", "scheduled_task"], + "readOnly": true + }, + "source_url": { + "title": "Source url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "canonical_url": { + "title": "Canonical url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "external_id": { + "title": "External id", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "title": { + "title": "Title", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "singer_name": { + "title": "Singer name", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "duration_seconds": { + "title": "Duration seconds", + "type": "integer", + "readOnly": true, + "x-nullable": true + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "source_published_at": { + "title": "Source published at", + "type": "string", + "format": "date-time", + "readOnly": true, + "x-nullable": true + }, + "status": { + "title": "Status", + "type": "string", + "enum": [ + "queued", + "discovering", + "downloading", + "processing", + "ai_detecting", + "metadata_review", + "ready_to_publish", + "published", + "duplicate", + "failed", + "cancelled" + ], + "readOnly": true + }, + "stage": { + "title": "Stage", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "progress": { + "title": "Progress", + "type": "integer", + "readOnly": true + }, + "ai_status": { + "title": "AI status", + "type": "string", + "enum": ["pending", "running", "success", "failed", "skipped"], + "readOnly": true + }, + "ai_confidence": { + "title": "AI confidence", + "type": "number", + "readOnly": true, + "x-nullable": true + }, + "needs_metadata_review": { + "title": "Needs metadata review", + "type": "boolean", + "readOnly": true + }, + "error_message": { + "title": "Error message", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "song_id": { "title": "Song id", "type": "string", "readOnly": true }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "task_id": { "title": "Task id", "type": "string", "readOnly": true }, + "run_id": { "title": "Run id", "type": "string", "readOnly": true }, + "attempts": { + "title": "Attempts", + "type": "integer", + "readOnly": true + }, + "max_attempts": { + "title": "Max attempts", + "type": "integer", + "readOnly": true + }, + "resolved_metadata": { + "title": "Resolved metadata", + "type": "object", + "readOnly": true + }, + "ai_metadata": { + "title": "Ai metadata", + "type": "object", + "readOnly": true + }, + "raw_metadata": { + "title": "Raw metadata", + "type": "object", + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + } + } + }, + "ImportItemMetadata": { + "type": "object", + "properties": { + "title": { "title": "Title", "type": "string", "maxLength": 512 }, + "singer_name": { + "title": "Singer name", + "type": "string", + "maxLength": 255 + }, + "ai_metadata": { "title": "Ai metadata", "type": "object" }, + "needs_metadata_review": { + "title": "Needs metadata review", + "type": "boolean" + }, + "status": { + "title": "Status", + "type": "string", + "enum": [ + "queued", + "discovering", + "downloading", + "processing", + "ai_detecting", + "metadata_review", + "ready_to_publish", + "published", + "duplicate", + "failed", + "cancelled" + ] + } + } + }, + "DashboardPleaseRow": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "translations": { "title": "Title", "type": "object" }, + "live_title": { "title": "Live title", "type": "object" }, + "dates": { "title": "Dates", "type": "object" }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "status": { "title": "Status", "type": "boolean" }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "is_active": { + "title": "Active", + "description": "Use this field to activate or deactivate this entry. If active, it will be shown to users.", + "type": "boolean" + }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 2147483647, + "minimum": -2147483648 + }, + "song_count": { + "title": "Song count", + "type": "integer", + "readOnly": true + }, + "songs": { "title": "Songs", "type": "string", "readOnly": true }, + "live_stream_link": { + "title": "Live link", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "langs": { "title": "Langs", "type": "string", "readOnly": true }, + "letter": { "title": "Letter", "type": "string", "readOnly": true }, + "updated": { + "title": "Updated", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "DashboardPleaseInput": { + "type": "object", + "properties": { + "translations": { "title": "Title", "type": "object" }, + "live_title": { "title": "Live title", "type": "object" }, + "dates": { "title": "Dates", "type": "object" }, + "status": { "title": "Status", "type": "boolean" }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "is_active": { + "title": "Active", + "description": "Use this field to activate or deactivate this entry. If active, it will be shown to users.", + "type": "boolean" + }, + "live_stream_link": { + "title": "Live link", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "songs": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "x-nullable": true + } + } + }, + "DashboardPublisherRow": { + "required": ["name"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "type": { + "title": "Type", + "type": "string", + "enum": ["YT", "IT", "WS", "TG", "AP"] + }, + "url": { + "title": "Url", + "type": "string", + "format": "uri", + "maxLength": 200, + "x-nullable": true + }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "languages": { + "title": "Languages", + "type": "string", + "readOnly": true + }, + "description": { + "title": "Description", + "type": "string", + "maxLength": 1024, + "x-nullable": true + }, + "instagram": { + "title": "Instagram", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "youtube": { + "title": "Youtube", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "telegram": { + "title": "Telegram", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "website": { + "title": "Telegram", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "letter": { "title": "Letter", "type": "string", "readOnly": true }, + "updated": { + "title": "Updated", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "DashboardPublisherInput": { + "required": ["name"], + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "type": { + "title": "Type", + "type": "string", + "enum": ["YT", "IT", "WS", "TG", "AP"] + }, + "url": { + "title": "Url", + "type": "string", + "format": "uri", + "maxLength": 200, + "x-nullable": true + }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "languages": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "description": { + "title": "Description", + "type": "string", + "maxLength": 1024, + "x-nullable": true + }, + "instagram": { + "title": "Instagram", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "youtube": { + "title": "Youtube", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "telegram": { + "title": "Telegram", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "website": { + "title": "Telegram", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "avatar_url": { + "title": "Avatar url", + "type": "string", + "x-nullable": true + } + } + }, + "ImportRunRow": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "task_id": { "title": "Task id", "type": "string", "readOnly": true }, + "source": { + "title": "Source", + "type": "string", + "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"], + "readOnly": true + }, + "source_url": { + "title": "Source url", + "type": "string", + "format": "uri", + "readOnly": true, + "minLength": 1 + }, + "scope": { "title": "Scope", "type": "object", "readOnly": true }, + "status": { + "title": "Status", + "type": "string", + "enum": ["running", "success", "failed", "cancelled"], + "readOnly": true + }, + "discovered_count": { + "title": "Discovered count", + "type": "integer", + "readOnly": true + }, + "created_count": { + "title": "Created count", + "type": "integer", + "readOnly": true + }, + "duplicate_count": { + "title": "Duplicate count", + "type": "integer", + "readOnly": true + }, + "failed_count": { + "title": "Failed count", + "type": "integer", + "readOnly": true + }, + "summary": { + "title": "Summary", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "error_message": { + "title": "Error message", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "started_at": { + "title": "Started at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "finished_at": { + "title": "Finished at", + "type": "string", + "format": "date-time", + "readOnly": true, + "x-nullable": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "DashboardSinger": { + "required": ["slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "latin": { "title": "Latin", "type": "string", "readOnly": true }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "letter": { "title": "Letter", "type": "string", "readOnly": true }, + "type": { "title": "Type", "type": "string", "readOnly": true }, + "singer_type": { + "title": "Singer type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + "works": { "title": "Works", "type": "integer", "readOnly": true }, + "langs": { "title": "Langs", "type": "string", "readOnly": true }, + "sub_langs": { + "title": "Sub langs", + "type": "string", + "readOnly": true + }, + "status": { "title": "Status", "type": "string", "readOnly": true }, + "updated": { "title": "Updated", "type": "string", "readOnly": true }, + "desc": { "title": "Desc", "type": "string", "readOnly": true }, + "panelId": { + "title": "Panelid", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 255, + "minLength": 1 + }, + "translations": { "title": "Name", "type": "object" }, + "view_count": { + "title": "View count", + "type": "integer", + "readOnly": true + }, + "is_pinned": { "title": "Pinned", "type": "boolean" }, + "ordering": { + "title": "Display order", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0 + } + } + }, + "DashboardSingerInput": { + "type": "object", + "properties": { + "translations": { "title": "Name", "type": "object" }, + "singer_type": { + "title": "Singer type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-\\w]+$" + }, + "biography": { + "title": "Biography", + "description": "could be empty", + "type": "string", + "x-nullable": true + }, + "status": { "title": "Status", "type": "boolean" }, + "languages": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "sub_languages": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "is_pinned": { "title": "Pinned", "type": "boolean" }, + "ordering": { + "title": "Display order", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0 + }, + "avatar_url": { + "title": "Avatar url", + "type": "string", + "x-nullable": true + } + } + }, + "_GenreMin": { + "required": ["title"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 119, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + } + } + }, + "_SingerMin": { + "required": ["slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 255, + "minLength": 1 + } + } + }, + "_PublisherMin": { + "required": ["name"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + } + } + }, + "_TagMin": { + "required": ["title"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 119, + "minLength": 1 + } + } + }, + "DashboardSongRow": { + "required": ["slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 50, + "minLength": 1 + }, + "types": { "title": "Types", "type": "string", "readOnly": true }, + "genre": { "$ref": "#/definitions/_GenreMin" }, + "singers": { + "type": "array", + "items": { "$ref": "#/definitions/_SingerMin" }, + "readOnly": true + }, + "langs": { "title": "Langs", "type": "string", "readOnly": true }, + "status": { "title": "Status", "type": "boolean" }, + "publisher": { "$ref": "#/definitions/_PublisherMin" }, + "published_date": { + "title": "Published date", + "type": "string", + "format": "date", + "x-nullable": true + }, + "tags": { + "type": "array", + "items": { "$ref": "#/definitions/_TagMin" }, + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "file": { "title": "File", "type": "string", "readOnly": true }, + "letter": { "title": "Letter", "type": "string", "readOnly": true }, + "updated": { + "title": "Updated", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "is_pinned": { "title": "Pinned", "type": "boolean" }, + "ordering": { + "title": "Display order", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + } + } + }, + "DashboardSongInput": { + "required": ["slug", "genre", "singers", "language"], + "type": "object", + "properties": { + "title": { "title": "Title", "type": "object" }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 50, + "minLength": 1 + }, + "song_type": { + "title": "Song type", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + "genre": { "title": "Genre", "type": "integer" }, + "singers": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "albums": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "language": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "subtitle_languages": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true + }, + "tags": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "publisher": { + "title": "Publisher", + "type": "integer", + "x-nullable": true + }, + "status": { "title": "Status", "type": "boolean" }, + "youtube_link": { + "title": "Youtube link", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "audio_file_remote_server": { + "title": "Audio file remote url", + "type": "string", + "format": "uri", + "maxLength": 200, + "x-nullable": true + }, + "file_remote_server": { + "title": "File remote url", + "description": "Upload file from remote server", + "type": "string", + "format": "uri", + "maxLength": 200, + "x-nullable": true + }, + "lyric": { + "title": "Lyric", + "description": "could be empty", + "type": "string", + "x-nullable": true + }, + "published_date": { + "title": "Published date", + "type": "string", + "format": "date", + "x-nullable": true + }, + "is_pinned": { "title": "Pinned", "type": "boolean" }, + "ordering": { + "title": "Display order", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "thumbnail_url": { + "title": "Thumbnail url", + "type": "string", + "x-nullable": true + } + } + }, + "ImportSourceTaskRow": { + "required": ["page_url"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "maxLength": 255 }, + "source": { + "title": "Source", + "type": "string", + "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"] + }, + "page_url": { + "title": "Page url", + "type": "string", + "format": "uri", + "maxLength": 1024, + "minLength": 1 + }, + "external_id": { + "title": "External id", + "type": "string", + "maxLength": 255 + }, + "frequency_days": { + "title": "Frequency days", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "run_time": { "title": "Run time", "type": "string" }, + "max_items_per_run": { + "title": "Max items per run", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "only_new_items": { "title": "Only new items", "type": "boolean" }, + "ignore_duplicates": { + "title": "Ignore duplicates", + "type": "boolean" + }, + "auto_stop_on_errors": { + "title": "Auto stop on errors", + "type": "boolean" + }, + "notify_on_error": { "title": "Notify on error", "type": "boolean" }, + "enabled": { "title": "Enabled", "type": "boolean" }, + "last_run_at": { + "title": "Last run at", + "type": "string", + "format": "date-time", + "readOnly": true, + "x-nullable": true + }, + "next_run_at": { + "title": "Next run at", + "type": "string", + "format": "date-time", + "readOnly": true, + "x-nullable": true + }, + "last_run_status": { + "title": "Last run status", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "new_items_last_run": { + "title": "New items last run", + "type": "integer", + "readOnly": true + }, + "error_streak": { + "title": "Error streak", + "type": "integer", + "readOnly": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "ImportSourceTaskInput": { + "required": ["page_url"], + "type": "object", + "properties": { + "title": { "title": "Title", "type": "string", "maxLength": 255 }, + "source": { + "title": "Source", + "type": "string", + "enum": ["youtube", "nava", "kashoob", "remote_file", "unknown"] + }, + "page_url": { + "title": "Page url", + "type": "string", + "format": "uri", + "maxLength": 1024, + "minLength": 1 + }, + "frequency_days": { + "title": "Frequency days", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "run_time": { "title": "Run time", "type": "string" }, + "max_items_per_run": { + "title": "Max items per run", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "only_new_items": { "title": "Only new items", "type": "boolean" }, + "ignore_duplicates": { + "title": "Ignore duplicates", + "type": "boolean" + }, + "auto_stop_on_errors": { + "title": "Auto stop on errors", + "type": "boolean" + }, + "notify_on_error": { "title": "Notify on error", "type": "boolean" }, + "enabled": { "title": "Enabled", "type": "boolean" } + } + }, + "DashboardTagRow": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "translations": { + "title": "Translations", + "type": "string", + "readOnly": true + }, + "slug": { + "title": "Slug", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "song_count": { + "title": "Song count", + "type": "integer", + "readOnly": true + }, + "letter": { "title": "Letter", "type": "string", "readOnly": true } + } + }, + "DashboardTagInput": { + "type": "object", + "properties": { + "translations": { "title": "Translations", "type": "object" }, + "slug": { "title": "Slug", "type": "string" } + } + }, + "_Upload": { + "type": "object", + "properties": { + "file": { + "title": "File", + "type": "string", + "readOnly": true, + "format": "uri" + } + } + }, + "YoutubeInfo": { + "required": ["youtube_link"], + "type": "object", + "properties": { + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "title": { + "title": "Title", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "youtube_link": { + "title": "Youtube link", + "type": "string", + "format": "uri", + "minLength": 1 + }, + "language_code": { + "title": "Language code", + "type": "string", + "readOnly": true, + "minLength": 1, + "x-nullable": true + } + } + }, + "ShrineLive": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "live_title": { + "title": "Live title", + "type": "string", + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "live_stream_link": { + "title": "Live stream link", + "type": "string", + "readOnly": true + }, + "status": { "title": "Status", "type": "boolean" }, + "pin_to_top": { "title": "Pin to top", "type": "boolean" }, + "live_count": { + "title": "Live count", + "type": "string", + "readOnly": true + } + } + }, + "HussainiyaProviderProfileSerializer": { + "required": ["role", "languages", "avatar"], + "type": "object", + "properties": { + "full_name": { + "title": "Full name", + "type": "string", + "maxLength": 254, + "minLength": 1, + "x-nullable": true + }, + "bio": { + "title": "Bio", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "role": { + "title": "Role", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + "birthdate": { + "title": "Birthdate", + "type": "string", + "format": "date", + "x-nullable": true + }, + "email": { + "title": "Email", + "type": "string", + "format": "email", + "maxLength": 254, + "x-nullable": true + }, + "wa_number": { + "title": "Whatsapp number", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "institution_name": { + "title": "Name", + "description": "Name of the institute", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "languages": { "type": "array", "items": { "type": "string" } }, + "avatar": { "title": "Avatar", "type": "string", "minLength": 1 }, + "social_medias": { + "title": "Social medias", + "description": "Provider social media profiles", + "type": "object" + } + } + }, + "CreateSong": { + "required": ["genre", "albums", "title", "language"], + "type": "object", + "properties": { + "youtube_link": { + "title": "Youtube link", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "file_path": { + "title": "File path", + "type": "string", + "x-nullable": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "x-nullable": true + }, + "genre": { "title": "Genre", "type": "integer" }, + "albums": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "title": { + "type": "array", + "items": { + "type": "object", + "required": ["title", "language_code"], + "properties": { + "title": { "title": "title", "type": "string" }, + "language_code": { + "title": "language code", + "description": "eg. en, da", + "type": "string" + } + } + } + }, + "slug": { "title": "Slug", "type": "string", "readOnly": true }, + "language": { + "description": "eg. [en, fa, ...]", + "type": "array", + "items": { "type": "string", "minLength": 1 } + } + } + }, + "UpdateSong": { + "required": ["genre", "albums"], + "type": "object", + "properties": { + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "x-nullable": true + }, + "genre": { "title": "Genre", "type": "integer" }, + "albums": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "title": { + "type": "array", + "items": { + "type": "object", + "required": ["title", "language_code"], + "properties": { + "title": { "title": "title", "type": "string" }, + "language_code": { + "title": "language code", + "description": "eg. en, da", + "type": "string" + } + } + } + }, + "language": { + "description": "eg. [en, fa, ...]", + "type": "array", + "items": { "type": "string", "minLength": 1 } + } + } + }, + "PlaylistTabCollection": { + "required": ["id", "title", "song_count", "is_personal", "editable"], + "type": "object", + "properties": { + "id": { "title": "Id", "type": "string", "minLength": 1 }, + "title": { + "title": "Title", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "song_count": { "title": "Song count", "type": "integer" }, + "is_personal": { "title": "Is personal", "type": "boolean" }, + "editable": { "title": "Editable", "type": "boolean" } + } + }, + "SingerSong": { + "required": ["slug"], + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "readOnly": true }, + "singer_type": { + "title": "Singer type", + "type": "string", + "enum": ["lecturer", "madah", "singer"] + }, + "songs_count": { + "title": "Songs count", + "type": "integer", + "readOnly": true + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 255, + "minLength": 1 + }, + "languages": { + "type": "array", + "items": { "type": "string" }, + "readOnly": true, + "uniqueItems": true + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "songs": { "title": "Songs", "type": "string", "readOnly": true } + } + }, + "Seo": { + "type": "object", + "properties": { + "title": { + "title": "Seo title", + "description": "maximum length of page title is 70 characters and minimum length is 30", + "type": "string", + "maxLength": 140, + "x-nullable": true + }, + "keywords": { + "title": "Keywords", + "description": "keywords in the content that make it possible for people to find the site via search engines", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "description": { + "title": "Description", + "description": "describes and summarizes the contents of the page for the benefit of users and search engines", + "type": "string", + "maxLength": 170, + "x-nullable": true + } + } + }, + "SongDetail": { + "required": ["slug"], + "type": "object", + "properties": { + "title": { "title": "Title", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "maxLength": 50, + "minLength": 1 + }, + "singers": { + "type": "array", + "items": { "$ref": "#/definitions/SingersList" }, + "readOnly": true + }, + "file": { "title": "File", "type": "string", "readOnly": true }, + "song_type": { + "title": "Song type", + "type": "string", + "enum": ["audio", "video", "youtube"] + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "lyric": { + "title": "Lyric", + "description": "could be empty", + "type": "string", + "x-nullable": true + }, + "published_date": { + "title": "Published date", + "type": "string", + "format": "date", + "x-nullable": true + }, + "info": { "title": "Info", "type": "object", "x-nullable": true }, + "genre": { "$ref": "#/definitions/GenreList" }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0 + }, + "like_count": { + "title": "Like count", + "type": "string", + "readOnly": true + }, + "language": { + "type": "array", + "items": { "$ref": "#/definitions/Language" }, + "readOnly": true + }, + "is_playlist": { + "title": "Is playlist", + "type": "string", + "readOnly": true + }, + "seo_fields": { "$ref": "#/definitions/Seo" }, + "publisher": { "$ref": "#/definitions/Publisher" }, + "is_liked": { "title": "Is liked", "type": "string", "readOnly": true }, + "is_youtube": { + "title": "Is youtube", + "type": "string", + "readOnly": true + }, + "youtube_audio_file": { + "title": "Youtube audio file", + "type": "string", + "readOnly": true + } + } + }, + "ImportantNotice": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "x-nullable": true }, + "subtitle": { + "title": "Subtitle", + "type": "string", + "x-nullable": true + }, + "alert_color": { + "title": "Alert color", + "type": "string", + "enum": ["#FF0000", "#FFFF00", "#00FF00", "#0000FF"], + "x-nullable": true + }, + "alert_color_display": { + "title": "Alert color display", + "type": "string", + "readOnly": true, + "minLength": 1 + }, + "small_image": { + "title": "Small image", + "type": "string", + "readOnly": true, + "x-nullable": true, + "format": "uri" + }, + "target_route": { + "title": "Target route", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "language": { + "title": "Language", + "type": "integer", + "x-nullable": true + }, + "status": { "title": "Status", "type": "boolean" } + } + }, + "GroupKhatm": { + "required": ["group_type"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "minLength": 1 }, + "slug": { "title": "Slug", "type": "string", "readOnly": true }, + "language_code": { + "title": "Language code", + "type": "string", + "readOnly": true + }, + "language_name": { + "title": "Language name", + "type": "string", + "readOnly": true + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "users_count": { + "title": "Users count", + "type": "string", + "readOnly": true + }, + "current_round": { + "title": "Current round", + "type": "string", + "readOnly": true + }, + "total_pages_read": { + "title": "Total pages read", + "type": "integer", + "readOnly": true + }, + "created_by": { + "title": "Created by", + "type": "string", + "readOnly": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "group_type": { + "title": "Group type", + "type": "string", + "enum": ["public", "private"] + }, + "progress_percentage": { + "title": "Progress percentage", + "type": "string", + "readOnly": true + }, + "pages": { "title": "Pages", "type": "string", "readOnly": true } + } + }, + "ReadPage": { + "required": ["page_user_id"], + "type": "object", + "properties": { + "page_user_id": { + "title": "Page user id", + "type": "integer", + "minimum": 1 + }, + "last_page_read": { + "title": "Last page read", + "type": "integer", + "readOnly": true + }, + "total_pages_read_group": { + "title": "Total pages read group", + "type": "integer", + "readOnly": true + }, + "remaining_pages": { + "title": "Remaining pages", + "type": "string", + "readOnly": true + } + } + }, + "IndividualKhatm": { + "required": ["name", "session_type", "session_value"], + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "minLength": 1 }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "session_type": { + "title": "Session type", + "type": "string", + "enum": ["page", "juz"] + }, + "session_value": { "title": "Session value", "type": "integer" }, + "last_session_read": { + "title": "Last session read", + "type": "integer", + "readOnly": true + }, + "total_sessions": { + "title": "Total Sessions", + "type": "integer", + "readOnly": true + }, + "total_count_info": { + "title": "Total count info", + "type": "string", + "readOnly": true + }, + "progress_percentage": { + "title": "Progress percentage", + "type": "string", + "readOnly": true + }, + "total_pages_read": { + "title": "Pages read", + "type": "string", + "readOnly": true + } + } + }, + "IndividualKhatmUpdate": { + "required": ["name"], + "type": "object", + "properties": { + "name": { + "title": "Name", + "type": "string", + "maxLength": 100, + "minLength": 1 + } + } + }, + "IndividualReadPage": { + "required": ["session"], + "type": "object", + "properties": { + "session": { "title": "Session", "type": "integer" }, + "remaining_pages": { + "title": "Remaining pages", + "type": "integer", + "readOnly": true + } + } + }, + "UserGroupKhatm": { + "required": ["khatm", "from_page", "to_page", "pages_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "khatm": { "$ref": "#/definitions/GroupKhatm" }, + "guest_fullname": { + "title": "Guest fullname", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "guest_wa_number": { + "title": "Guest whatsapp number", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "from_page": { + "title": "From page", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "to_page": { + "title": "To page", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "pages_count": { + "title": "Pages count", + "type": "integer", + "maximum": 32767, + "minimum": 0 + }, + "last_page_read": { + "title": "Last page read", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "created_at": { + "title": "Joined at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "BannerList": { + "required": ["description"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + }, + "covers": { "title": "Covers", "type": "string", "readOnly": true } + } + }, + "Author": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true } + } + }, + "BookList": { + "required": ["title", "author", "type"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "price": { + "title": "Price (Coin)", + "type": "string", + "format": "decimal" + }, + "author": { + "type": "array", + "items": { "$ref": "#/definitions/Author" } + }, + "type": { "title": "Type", "type": "string", "minLength": 1 }, + "rates": { "title": "Rates", "type": "string", "readOnly": true }, + "is_bookmark": { + "title": "Is bookmark", + "type": "boolean", + "default": false + } + } + }, + "BookListSerializerEditorSuggestion": { + "required": ["author"], + "type": "object", + "properties": { + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "author": { + "type": "array", + "items": { "$ref": "#/definitions/Author" } + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "summary": { + "title": "Summary", + "description": "could be null", + "type": "string", + "maxLength": 512, + "x-nullable": true + } + } + }, + "BookListV2": { + "required": ["title", "author", "file_types"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "price": { + "title": "Price (Coin)", + "type": "string", + "format": "decimal" + }, + "discount_percentage": { + "title": "Discount Percentage", + "description": "Discount percentage as an integer between 0 and 100", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "final_price": { + "title": "Final Price (Coin)", + "description": "This field is automatically calculated based on the discount percentage.", + "type": "string", + "format": "decimal" + }, + "author": { + "type": "array", + "items": { "$ref": "#/definitions/Author" } + }, + "file_types": { + "type": "array", + "items": { "type": "string", "minLength": 1 } + }, + "rates": { "title": "Rates", "type": "string", "readOnly": true }, + "is_bookmark": { + "title": "Is bookmark", + "type": "boolean", + "default": false + } + } + }, + "BookFiles": { + "required": ["title"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "file": { + "title": "File", + "type": "string", + "readOnly": true, + "format": "uri" + }, + "pages_count": { + "title": "Number of Pages", + "description": "eg. 34", + "type": "string", + "maxLength": 255, + "minLength": 1, + "x-nullable": true + } + } + }, + "BookPublisher": { + "required": ["username", "name"], + "type": "object", + "properties": { + "username": { + "title": "Username", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "name": { "title": "Name", "type": "string", "minLength": 1 }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true } + } + }, + "BookDetail": { + "required": ["title", "author", "type", "files", "language", "publisher"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "is_bookmark": { + "title": "Is bookmark", + "type": "boolean", + "default": false + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "price": { + "title": "Price (Coin)", + "type": "string", + "format": "decimal" + }, + "author": { + "type": "array", + "items": { "$ref": "#/definitions/Author" } + }, + "type": { "title": "Type", "type": "string", "minLength": 1 }, + "narrator": { "title": "Narrator", "type": "string", "readOnly": true }, + "files": { + "type": "array", + "items": { "$ref": "#/definitions/BookFiles" } + }, + "pages_count": { + "title": "Number of Pages", + "description": "eg. 34", + "type": "string", + "maxLength": 255, + "minLength": 1, + "x-nullable": true + }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0 + }, + "download_count": { + "title": "Download count", + "type": "integer", + "default": 9 + }, + "language": { + "type": "array", + "items": { "$ref": "#/definitions/Language" } + }, + "summary": { + "title": "Summary", + "description": "could be null", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "publisher": { "$ref": "#/definitions/BookPublisher" }, + "rates": { "title": "Rates", "type": "string", "readOnly": true }, + "related": { "title": "Related", "type": "string", "readOnly": true } + } + }, + "UserRate": { + "type": "object", + "properties": { + "name": { "title": "Name", "type": "string", "readOnly": true }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "rate": { + "title": "Rate", + "type": "integer", + "maximum": 32767, + "minimum": 0, + "x-nullable": true + }, + "note": { + "title": "Note", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "date": { + "title": "Date", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "Category": { + "required": ["icon", "book_count"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "readOnly": true, + "x-nullable": true + }, + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "icon": { + "title": "Icon", + "description": "fontawesome icon. eg. fa-book", + "type": "string", + "maxLength": 32, + "minLength": 1 + }, + "book_count": { + "title": "Book count", + "type": "integer", + "x-nullable": true + } + } + }, + "Files": { + "required": ["title", "pdf_file"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "pdf_file": { "title": "Pdf file", "type": "string", "minLength": 1 }, + "pages_count": { + "title": "Number of Pages", + "description": "eg. 34", + "type": "string", + "maxLength": 255, + "minLength": 1, + "x-nullable": true + } + } + }, + "CreateBook": { + "required": ["title", "thumbnail", "files"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "price": { + "title": "Price (Coin)", + "type": "string", + "format": "decimal" + }, + "summary": { + "title": "Summary", + "description": "could be null", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "description": { + "title": "Description", + "description": "could be null", + "type": "string", + "x-nullable": true + }, + "thumbnail": { "title": "Thumbnail", "type": "string", "minLength": 1 }, + "tags": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "categories": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "authors": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "translators": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "narrators": { + "type": "array", + "items": { "type": "integer" }, + "uniqueItems": true + }, + "publish_year": { + "title": "Publish year", + "description": "eg. 1998", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "vol_count": { + "title": "Number of Volumes", + "description": "eg. 3", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "isbn": { + "title": "ISBN", + "type": "string", + "maxLength": 225, + "x-nullable": true + }, + "files": { "type": "array", "items": { "$ref": "#/definitions/Files" } } + } + }, + "PublisherList": { + "required": ["full_name", "book_count"], + "type": "object", + "properties": { + "full_name": { + "title": "Full name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "book_count": { + "title": "Book count", + "type": "integer", + "x-nullable": true + }, + "id": { "title": "ID", "type": "integer", "readOnly": true } + } + }, + "BookFilesV2": { + "required": ["title"], + "type": "object", + "properties": { + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "file": { + "title": "File", + "type": "string", + "readOnly": true, + "format": "uri" + }, + "type": { + "title": "File Type", + "type": "string", + "enum": ["pdf", "html", "epub", "docx", "audio"] + }, + "pages_count": { + "title": "Number of Pages", + "description": "eg. 34", + "type": "string", + "maxLength": 255, + "minLength": 1, + "x-nullable": true + }, + "volume": { + "title": "Volume", + "description": "The volume number of the book, e.g., 1 for first volume.", + "type": "integer", + "maximum": 2147483647, + "minimum": -2147483648, + "x-nullable": true + } + } + }, + "BookDetailV2": { + "required": [ + "title", + "author", + "file_types", + "book_files", + "language", + "publisher", + "categories" + ], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "readOnly": true, + "minLength": 1 + }, + "is_bookmark": { + "title": "Is bookmark", + "type": "boolean", + "default": false + }, + "is_download": { + "title": "Is download", + "type": "boolean", + "default": false + }, + "price": { + "title": "Price (Coin)", + "type": "string", + "format": "decimal" + }, + "discount_percentage": { + "title": "Discount Percentage", + "description": "Discount percentage as an integer between 0 and 100", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "final_price": { + "title": "Final Price (Coin)", + "description": "This field is automatically calculated based on the discount percentage.", + "type": "string", + "format": "decimal" + }, + "thumbnail": { + "title": "Thumbnail", + "type": "string", + "readOnly": true + }, + "author": { + "type": "array", + "items": { "$ref": "#/definitions/Author" } + }, + "file_types": { + "type": "array", + "items": { "type": "string", "minLength": 1 } + }, + "view_count": { + "title": "View count", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0 + }, + "download_count": { + "title": "Download count", + "type": "string", + "readOnly": true + }, + "narrator": { "title": "Narrator", "type": "string", "readOnly": true }, + "book_files": { + "type": "array", + "items": { "$ref": "#/definitions/BookFilesV2" } + }, + "pages_count": { + "title": "Number of Pages", + "description": "eg. 34", + "type": "string", + "maxLength": 255, + "minLength": 1, + "x-nullable": true + }, + "language": { + "type": "array", + "items": { "$ref": "#/definitions/Language" } + }, + "description": { + "title": "Description", + "description": "could be null", + "type": "string", + "x-nullable": true + }, + "summary": { + "title": "Summary", + "description": "could be null", + "type": "string", + "maxLength": 512, + "x-nullable": true + }, + "publisher": { "$ref": "#/definitions/BookPublisher" }, + "categories": { + "type": "array", + "items": { "$ref": "#/definitions/Category" } + }, + "rates": { "title": "Rates", "type": "string", "readOnly": true }, + "sample_file": { + "title": "Sample file", + "type": "string", + "readOnly": true + }, + "related": { "title": "Related", "type": "string", "readOnly": true } + } + }, + "AuthorList": { + "required": ["slug", "book_count"], + "type": "object", + "properties": { + "slug": { "title": "Slug", "type": "string", "minLength": 1 }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true }, + "book_count": { + "title": "Book count", + "type": "integer", + "x-nullable": true + } + } + }, + "MafatihCategories": { + "required": ["language"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "thumbnails": { + "title": "Thumbnails", + "type": "string", + "readOnly": true + }, + "duas_index": { + "title": "Duas index", + "type": "string", + "readOnly": true + }, + "language": { "$ref": "#/definitions/Language" }, + "children": { "title": "Children", "type": "string", "readOnly": true } + } + }, + "DuaCategories": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "thumbnails": { + "title": "Thumbnails", + "type": "string", + "readOnly": true + }, + "duas_index": { + "title": "Duas index", + "type": "string", + "readOnly": true + }, + "language": { "title": "Language", "type": "string", "readOnly": true }, + "children": { "title": "Children", "type": "string", "readOnly": true } + } + }, + "MafatihDuaPart": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "dua_part_index": { + "title": "Dua part index", + "type": "string", + "readOnly": true + }, + "text": { "title": "Text", "type": "string", "x-nullable": true }, + "translation": { + "title": "Translation", + "type": "string", + "x-nullable": true + }, + "local_alpha": { + "title": "Local alpha", + "type": "string", + "x-nullable": true + }, + "mafatih_dua_id": { + "title": "Mafatih dua id", + "type": "string", + "readOnly": true + }, + "description": { + "title": "Description", + "type": "string", + "x-nullable": true + } + } + }, + "DuaPartSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "dua_part_index": { + "title": "Dua part index", + "type": "string", + "readOnly": true + }, + "text": { "title": "Text", "type": "string", "x-nullable": true }, + "translation": { + "title": "Translation", + "type": "string", + "readOnly": true + }, + "local_alpha": { + "title": "Local alpha", + "type": "string", + "readOnly": true + }, + "dua_id": { "title": "Dua id", "type": "string", "readOnly": true }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + } + } + }, + "MafatihDua": { + "required": ["title"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 192, + "minLength": 1 + }, + "duas_part_list": { + "type": "array", + "items": { "type": "integer" }, + "readOnly": true, + "uniqueItems": true + }, + "dates": { + "title": "Dates", + "description": "لیستی از تاریخ های قمری مربوط به قطعه", + "type": "object", + "x-nullable": true + }, + "weekdays": { "title": "Weekdays", "type": "string", "readOnly": true }, + "audio_sync_data": { + "title": "Audio sync data", + "type": "string", + "readOnly": true + }, + "audio": { "title": "Audio", "type": "string", "readOnly": true } + } + }, + "DuaAudioDetail": { + "required": ["reciter"], + "type": "object", + "properties": { + "reciter": { + "title": "Reciter", + "type": "string", + "maxLength": 119, + "minLength": 1 + }, + "audio": { "title": "Audio", "type": "string", "readOnly": true }, + "audio_sync_data": { "title": "Audio sync data", "type": "object" } + } + }, + "MafatihDuaSerializerV2": { + "required": ["title", "audios"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 192, + "minLength": 1 + }, + "duas_part_list": { + "type": "array", + "items": { "type": "integer" }, + "readOnly": true, + "uniqueItems": true + }, + "dates": { + "title": "Dates", + "description": "لیستی از تاریخ های قمری مربوط به قطعه", + "type": "object", + "x-nullable": true + }, + "weekdays": { "title": "Weekdays", "type": "string", "readOnly": true }, + "audios": { + "type": "array", + "items": { "$ref": "#/definitions/DuaAudioDetail" } + } + } + }, + "DuaAudioDetailV3": { + "type": "object", + "properties": { + "reciter": { "title": "Reciter", "type": "string", "readOnly": true }, + "audio": { "title": "Audio", "type": "string", "readOnly": true }, + "audio_sync_data": { "title": "Audio sync data", "type": "object" } + } + }, + "MafatihDuaSerializerV3": { + "required": ["audios"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "similar_titles": { + "title": "Similar Titles", + "type": "object", + "x-nullable": true + }, + "duas_part_list": { + "type": "array", + "items": { "type": "integer" }, + "readOnly": true, + "uniqueItems": true + }, + "dates": { + "title": "Dates", + "description": "لیستی از تاریخ های قمری مربوط به قطعه", + "type": "object", + "x-nullable": true + }, + "weekdays": { "title": "Weekdays", "type": "string", "readOnly": true }, + "audios": { + "type": "array", + "items": { "$ref": "#/definitions/DuaAudioDetailV3" } + } + } + }, + "DuaAudioList": { + "required": ["reciter"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "reciter": { + "title": "Reciter", + "type": "string", + "maxLength": 119, + "minLength": 1 + } + } + }, + "Masael": { + "required": ["title", "content"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "content": { "title": "Content", "type": "string", "minLength": 1 }, + "category": { "title": "Category", "type": "string", "readOnly": true }, + "root_id": { "title": "Root id", "type": "string", "readOnly": true } + } + }, + "MarjaaGuide": { + "required": ["language"], + "type": "object", + "properties": { + "title": { "title": "Title", "type": "string", "x-nullable": true }, + "language": { "$ref": "#/definitions/Language" }, + "answer": { "title": "Answer", "type": "string", "x-nullable": true }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 2147483647, + "minimum": -2147483648 + } + } + }, + "MasaelContent": { + "required": ["text"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "header": { "title": "Header", "type": "string", "x-nullable": true }, + "text": { "title": "Text", "type": "string", "minLength": 1 }, + "answer": { "title": "Answer", "type": "string", "x-nullable": true }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + } + } + }, + "MasaelSerializerV2": { + "required": ["title"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "priority": { + "title": "Priority", + "type": "integer", + "maximum": 2147483647, + "minimum": 0, + "x-nullable": true + }, + "category": { + "title": "Category", + "type": "integer", + "x-nullable": true + }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "contents": { + "type": "array", + "items": { "$ref": "#/definitions/MasaelContent" }, + "readOnly": true + } + } + }, + "Note": { + "required": ["service", "object_id", "note_text"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "service": { + "title": "Service", + "type": "string", + "enum": ["quran", "mafatih", "hadis", "habit"] + }, + "object_id": { + "title": "Object id", + "type": "integer", + "maximum": 2147483647, + "minimum": -2147483648 + }, + "user": { "title": "User", "type": "string", "readOnly": true }, + "note_text": { "title": "Note text", "type": "string", "minLength": 1 }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "feedback_count": { + "title": "Feedback count", + "type": "string", + "readOnly": true + }, + "language": { "title": "Language", "type": "string", "readOnly": true }, + "request_user_feedback": { + "title": "Request user feedback", + "type": "string", + "readOnly": true + } + } + }, + "NoteFeedback": { + "required": ["note"], + "type": "object", + "properties": { + "note": { "title": "Note", "type": "integer" }, + "is_positive": { "title": "Is positive", "type": "boolean" }, + "user": { + "title": "User", + "type": "integer", + "readOnly": true, + "x-nullable": true + } + } + }, + "Plan": { + "required": ["price"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "price": { "title": "Price", "type": "string", "format": "decimal" }, + "services": { "title": "Services", "type": "object" }, + "duration": { + "title": "Duration", + "description": "Duration in days", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + } + } + }, + "Subscribe": { + "required": ["plan"], + "type": "object", + "properties": { + "plan": { "title": "Plan", "type": "integer" }, + "activated_at": { + "title": "Activated at", + "type": "string", + "format": "date", + "readOnly": true + }, + "expire_at": { + "title": "Expire at", + "type": "string", + "format": "date", + "readOnly": true + }, + "remaining_days": { + "title": "Remaining days", + "type": "integer", + "readOnly": true + }, + "remaining_credits": { + "title": "Remaining credits", + "type": "object", + "readOnly": true + } + } + }, + "QuranPart": { + "required": ["index", "start_at", "end_at"], + "type": "object", + "properties": { + "index": { + "title": "Index", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "start_at": { + "title": "Start at", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "end_at": { + "title": "End at", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + } + } + }, + "QuranSuraTranslation": { + "required": ["text"], + "type": "object", + "properties": { + "sura_id": { "title": "Sura id", "type": "string", "readOnly": true }, + "text": { "title": "Text", "type": "string", "minLength": 1 } + } + }, + "QuranSura": { + "required": [ + "index", + "name", + "verse_count", + "nozul_type", + "start_at", + "end_at" + ], + "type": "object", + "properties": { + "index": { + "title": "Index", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 192, + "minLength": 1 + }, + "similar_names": { + "title": "Similar Names", + "type": "object", + "x-nullable": true + }, + "verse_count": { + "title": "Verse count", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "nozul_type": { + "title": "Nozul type", + "type": "string", + "enum": ["Meccan", "Medinan"] + }, + "start_at": { + "title": "Start at", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "end_at": { + "title": "End at", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + } + } + }, + "QuranTranslators": { + "required": ["translator", "language_code"], + "type": "object", + "properties": { + "translator": { + "title": "Translator", + "type": "string", + "maxLength": 192, + "minLength": 1 + }, + "translator_en": { + "title": "Translator en", + "type": "string", + "maxLength": 192, + "minLength": 1, + "x-nullable": true + }, + "language_code": { + "title": "Language code", + "type": "string", + "maxLength": 2, + "minLength": 1 + } + } + }, + "QuranVerseLocalization": { + "required": ["text"], + "type": "object", + "properties": { + "verse_id": { "title": "Verse id", "type": "string", "readOnly": true }, + "text": { "title": "Text", "type": "string", "minLength": 1 } + } + }, + "QuranVerseTranslation": { + "required": ["text"], + "type": "object", + "properties": { + "verse_id": { "title": "Verse id", "type": "string", "readOnly": true }, + "text": { "title": "Text", "type": "string", "minLength": 1 } + } + }, + "QuranVerse": { + "required": ["index", "number_in_surah", "juz", "text"], + "type": "object", + "properties": { + "index": { + "title": "Index", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "sura_id": { "title": "Sura id", "type": "string", "readOnly": true }, + "number_in_surah": { + "title": "Number in surah", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "juz": { + "title": "Juz", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "text": { "title": "Text", "type": "string", "minLength": 1 }, + "glyph_text": { + "title": "Glyph text", + "type": "string", + "maxLength": 500, + "x-nullable": true + }, + "raw_text": { + "title": "Raw text", + "type": "string", + "x-nullable": true + }, + "new_line_at": { + "title": "New line at", + "type": "string", + "maxLength": 255, + "x-nullable": true + } + } + }, + "QuranWordTranslation": { + "required": ["verse", "arabic", "translate", "language_code"], + "type": "object", + "properties": { + "verse": { "title": "Verse", "type": "integer" }, + "arabic": { + "title": "Arabic word", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "translate": { + "title": "Translate", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "language_code": { + "title": "Language code", + "type": "string", + "minLength": 1 + } + } + }, + "Adhan": { + "required": ["name"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "description": { + "title": "Description", + "description": "could be null", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "file_path": { + "title": "File path", + "type": "string", + "readOnly": true + } + } + }, + "Reminder": { + "required": ["service_name", "object_id", "text"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "service_name": { + "title": "Service Name", + "description": "Name of the service (e.g., \"meet\", \"dua\", etc.)", + "type": "string", + "maxLength": 100, + "minLength": 1 + }, + "object_id": { + "title": "Object ID", + "description": "ID of the related object (meet ID, dua ID, etc.)", + "type": "string", + "maxLength": 100, + "minLength": 1 + }, + "text": { + "title": "Reminder Text", + "description": "The reminder message content", + "type": "string", + "minLength": 1 + }, + "created_at": { + "title": "Created At", + "description": "When the reminder was created", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "call_time": { + "title": "Call Time", + "description": "When the reminder should be triggered/called", + "type": "string", + "format": "date-time", + "x-nullable": true + }, + "is_sent": { + "title": "Is Sent", + "description": "Whether the reminder has been sent", + "type": "boolean" + }, + "is_read": { + "title": "Is Read", + "description": "Whether the user has opened/read the reminder", + "type": "boolean" + }, + "status": { + "title": "Status", + "description": "General status management for the reminder", + "type": "boolean" + } + } + }, + "ReminderUpdate": { + "type": "object", + "properties": { + "is_sent": { + "title": "Is Sent", + "description": "Whether the reminder has been sent", + "type": "boolean" + }, + "is_read": { + "title": "Is Read", + "description": "Whether the user has opened/read the reminder", + "type": "boolean" + }, + "status": { + "title": "Status", + "description": "General status management for the reminder", + "type": "boolean" + } + } + }, + "Report": { + "required": ["service_slug", "text"], + "type": "object", + "properties": { + "service_slug": { + "title": "Service slug", + "type": "string", + "enum": [ + "hussainiyah", + "quran", + "mafatih", + "qiblah", + "ahkam", + "calendar", + "talk", + "meet", + "library", + "hadis", + "habit", + "checkup", + "marriage" + ] + }, + "subject": { + "title": "Subject", + "type": "integer", + "x-nullable": true + }, + "description": { + "title": "Description", + "type": "string", + "x-nullable": true + }, + "text": { + "title": "Report Text", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "object_id": { + "title": "Object id", + "type": "integer", + "maximum": 9223372036854775807, + "minimum": 0, + "x-nullable": true + } + } + }, + "Subject": { + "required": ["name", "slug"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { + "title": "Name", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "maxLength": 50, + "minLength": 1 + }, + "service": { "title": "Service", "type": "string", "readOnly": true } + } + }, + "ServiceVersion": { + "required": ["version_number", "language"], + "type": "object", + "properties": { + "service": { "title": "Service", "type": "string", "readOnly": true }, + "version_number": { + "title": "Version Number", + "description": "Version number in format 1.3", + "type": "string", + "maxLength": 20, + "minLength": 1 + }, + "language": { "$ref": "#/definitions/Language" }, + "is_active": { + "title": "Is active", + "type": "string", + "readOnly": true + }, + "service_config": { + "title": "Service config", + "type": "string", + "readOnly": true + }, + "created_at": { + "title": "Created At", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "app_intros": { + "title": "App intros", + "type": "string", + "readOnly": true + }, + "service_intros": { + "title": "Service intros", + "type": "string", + "readOnly": true + } + } + }, + "ShareApp": { + "required": ["description"], + "type": "object", + "properties": { + "description": { + "title": "Description", + "type": "string", + "minLength": 1 + }, + "image": { "title": "Image", "type": "string", "readOnly": true } + } + }, + "TafsirVerses": { + "required": ["from_verse", "to_verse", "text"], + "type": "object", + "properties": { + "from_verse": { + "title": "From verse", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "to_verse": { + "title": "To verse", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "text": { "title": "Text", "type": "string", "minLength": 1 }, + "surah": { "title": "Surah", "type": "string", "readOnly": true }, + "book": { "title": "Book", "type": "string", "readOnly": true }, + "ayahs_index": { + "title": "Ayahs index", + "type": "string", + "readOnly": true + } + } + }, + "TafsirBook": { + "required": ["title"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { + "title": "Title", + "type": "string", + "maxLength": 112, + "minLength": 1 + }, + "surahs": { "title": "Surahs", "type": "string", "readOnly": true } + } + }, + "Transaction": { + "required": ["coin_count"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "coin_count": { + "title": "Coin count", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + }, + "service": { + "title": "Service", + "type": "string", + "enum": ["hussainiya", "library", "talk", "meet"], + "x-nullable": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "WithdrawalRequest": { + "required": ["amount", "status"], + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "amount": { "title": "Amount", "type": "string", "format": "decimal" }, + "status": { + "title": "Status", + "type": "string", + "enum": ["pending", "completed", "failed"] + }, + "description": { + "title": "Description", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "created_at": { + "title": "Created at", + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated_at": { + "title": "Updated at", + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "DuaCompleteSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "slug": { "title": "Slug", "type": "string", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "parts": { "title": "Parts", "type": "string", "readOnly": true }, + "total_parts": { + "title": "Total parts", + "type": "string", + "readOnly": true + }, + "seo_field": { + "title": "Seo field", + "type": "string", + "readOnly": true + }, + "synced_at": { + "title": "Synced at", + "type": "string", + "readOnly": true + } + } + }, + "Web_DuaCategoriesSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "slug": { "title": "Slug", "type": "string", "readOnly": true }, + "thumbnails": { + "title": "Thumbnails", + "type": "string", + "readOnly": true + }, + "language": { "title": "Language", "type": "string", "readOnly": true }, + "children": { "title": "Children", "type": "string", "readOnly": true } + } + }, + "Web_DuaSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "title": { "title": "Title", "type": "string", "readOnly": true }, + "slug": { "title": "Slug", "type": "string", "readOnly": true }, + "not_synced": { + "title": "Not synced", + "type": "boolean", + "default": false + }, + "seo_field": { + "title": "Seo field", + "type": "string", + "readOnly": true + } + } + }, + "Web_DuaPartSerializer": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "dua_part_index": { + "title": "Dua part index", + "type": "string", + "readOnly": true + }, + "text": { "title": "Text", "type": "string", "x-nullable": true }, + "translation": { + "title": "Translation", + "type": "string", + "readOnly": true + }, + "local_alpha": { + "title": "Local alpha", + "type": "string", + "readOnly": true + }, + "mafatih_dua_id": { + "title": "Mafatih dua id", + "type": "string", + "readOnly": true + }, + "description": { + "title": "Description", + "type": "string", + "readOnly": true + } + } + }, + "WebDuaAudio": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "reciter": { "title": "Reciter", "type": "string", "readOnly": true }, + "audio": { "title": "Audio", "type": "string", "readOnly": true }, + "audio_sync_data": { "title": "Audio sync data", "type": "object" } + } + }, + "DuaReciter": { + "type": "object", + "properties": { + "id": { "title": "ID", "type": "integer", "readOnly": true }, + "name": { "title": "Name", "type": "string", "readOnly": true }, + "slug": { + "title": "Slug", + "type": "string", + "format": "slug", + "pattern": "^[-a-zA-Z0-9_]+$", + "maxLength": 120 + }, + "avatar": { "title": "Avatar", "type": "string", "readOnly": true } + } + }, + "QuranSurahDetailVerse": { + "required": ["index", "number_in_surah", "juz", "text"], + "type": "object", + "properties": { + "index": { + "title": "Index", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "sura_id": { "title": "Sura id", "type": "string", "readOnly": true }, + "number_in_surah": { + "title": "Number in surah", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "juz": { + "title": "Juz", + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "text": { "title": "Text", "type": "string", "minLength": 1 }, + "glyph_text": { + "title": "Glyph text", + "type": "string", + "maxLength": 500, + "x-nullable": true + }, + "raw_text": { + "title": "Raw text", + "type": "string", + "x-nullable": true + }, + "new_line_at": { + "title": "New line at", + "type": "string", + "maxLength": 255, + "x-nullable": true + }, + "text_translation": { + "title": "Text translation", + "type": "string", + "readOnly": true + } + } + } + } +} diff --git a/src/app/[lang]/layout.tsx b/src/app/[lang]/layout.tsx index c0ec596..3929f2c 100644 --- a/src/app/[lang]/layout.tsx +++ b/src/app/[lang]/layout.tsx @@ -22,9 +22,7 @@ export default async function LocaleLayout({ return ( -
- {children} -
+
{children}
); } diff --git a/src/app/[lang]/questions-list/[slug]/page.tsx b/src/app/[lang]/questions-list/[slug]/page.tsx index f78c120..1c42417 100644 --- a/src/app/[lang]/questions-list/[slug]/page.tsx +++ b/src/app/[lang]/questions-list/[slug]/page.tsx @@ -1,6 +1,6 @@ +import QuestionDetailPage from "@/app/questions-list/[slug]/page"; import { getQuestionListItems } from "@/data/question-data"; import { locales } from "@/translations/config"; -import QuestionDetailPage from "@/app/questions-list/[slug]/page"; export function generateStaticParams() { return locales.flatMap((lang) => diff --git a/src/app/[lang]/test-webview/page.tsx b/src/app/[lang]/test-webview/page.tsx index 03538ce..f0ab110 100644 --- a/src/app/[lang]/test-webview/page.tsx +++ b/src/app/[lang]/test-webview/page.tsx @@ -1,8 +1,8 @@ "use client"; -import { useState, useEffect } from "react"; -import { useFlutterBridge } from "@/hooks/useFlutterBridge"; +import { useEffect, useState } from "react"; import Button from "@/components/ui/button"; +import { useFlutterBridge } from "@/hooks/useFlutterBridge"; export default function TestWebViewPage() { const { sendToFlutter, logs, lastEvent, events, isReady } = useFlutterBridge({ @@ -24,7 +24,7 @@ export default function TestWebViewPage() { window.dispatchEvent( new CustomEvent("flutterEvent", { detail: { type, payload, timestamp: Date.now() }, - }) + }), ); }; @@ -183,7 +183,7 @@ export default function TestWebViewPage() {
{new Date(lastEvent.timestamp || Date.now()).toLocaleString( - "fa-IR" + "fa-IR", )}
@@ -289,9 +289,9 @@ export default function TestWebViewPage() { {event.type} - {new Date(event.timestamp || Date.now()).toLocaleTimeString( - "fa-IR" - )} + {new Date( + event.timestamp || Date.now(), + ).toLocaleTimeString("fa-IR")}
diff --git a/src/app/api/dev-storage/route.ts b/src/app/api/dev-storage/route.ts
index 4b8dc35..668bf02 100644
--- a/src/app/api/dev-storage/route.ts
+++ b/src/app/api/dev-storage/route.ts
@@ -1,4 +1,4 @@
-import { NextRequest } from "next/server";
+import type { NextRequest } from "next/server";
 
 export const dynamic = "force-dynamic";
 export const runtime = "nodejs";
@@ -10,7 +10,10 @@ export async function POST(request: NextRequest) {
 
   try {
     const data = await request.json();
-    console.log("\x1b[35m💾 [DEV STORAGE VALUES]\x1b[0m", JSON.stringify(data, null, 2));
+    console.log(
+      "\x1b[35m💾 [DEV STORAGE VALUES]\x1b[0m",
+      JSON.stringify(data, null, 2),
+    );
     return Response.json({ success: true });
   } catch (error) {
     console.error("Failed to process dev storage request:", error);
diff --git a/src/app/api/open-in-ide/route.ts b/src/app/api/open-in-ide/route.ts
index aa25ed0..4c4f0a3 100644
--- a/src/app/api/open-in-ide/route.ts
+++ b/src/app/api/open-in-ide/route.ts
@@ -1,5 +1,5 @@
-import { NextRequest } from "next/server";
 import { exec } from "child_process";
+import type { NextRequest } from "next/server";
 import os from "os";
 
 export const dynamic = "force-dynamic";
@@ -23,11 +23,15 @@ export async function POST(request: NextRequest) {
 
     exec(command, (error) => {
       if (error) {
-        console.error(`[open-in-ide] Primary CLI command failed: ${error.message}. Trying URL scheme fallback...`);
+        console.error(
+          `[open-in-ide] Primary CLI command failed: ${error.message}. Trying URL scheme fallback...`,
+        );
         const fallbackCmd = `start "" "antigravity://file/${locator}"`;
         exec(fallbackCmd, (fallbackErr) => {
           if (fallbackErr) {
-            console.error(`[open-in-ide] Fallback failed: ${fallbackErr.message}`);
+            console.error(
+              `[open-in-ide] Fallback failed: ${fallbackErr.message}`,
+            );
           }
         });
       }
diff --git a/src/app/api/proxy/route.ts b/src/app/api/proxy/route.ts
index e7f4159..9f6198e 100644
--- a/src/app/api/proxy/route.ts
+++ b/src/app/api/proxy/route.ts
@@ -303,8 +303,6 @@ async function proxyRequest(request: NextRequest) {
 
     logProxyResponse(upstreamResponse, responseBody);
 
-
-
     const responseHeaders = getResponseHeaders(upstreamResponse.headers);
 
     // Force no caching on API proxy responses – always fetch fresh data
diff --git a/src/app/api/remote-logs/route.ts b/src/app/api/remote-logs/route.ts
index 13c501d..f9d60ee 100644
--- a/src/app/api/remote-logs/route.ts
+++ b/src/app/api/remote-logs/route.ts
@@ -1,4 +1,4 @@
-import { NextRequest } from "next/server";
+import type { NextRequest } from "next/server";
 
 export const dynamic = "force-dynamic";
 export const runtime = "nodejs";
@@ -15,8 +15,8 @@ export async function POST(request: NextRequest) {
       type === "error"
         ? "\x1b[31m📱 [MOBILE ERROR]\x1b[0m" // Red color in terminal
         : type === "warn"
-          ? "\x1b[33m📱 [MOBILE WARN]\x1b[0m"  // Yellow color in terminal
-          : "\x1b[36m📱 [MOBILE LOG]\x1b[0m";   // Cyan color in terminal
+          ? "\x1b[33m📱 [MOBILE WARN]\x1b[0m" // Yellow color in terminal
+          : "\x1b[36m📱 [MOBILE LOG]\x1b[0m"; // Cyan color in terminal
 
     const message = args
       .map((arg: any) => {
diff --git a/src/app/api/remote-network/route.ts b/src/app/api/remote-network/route.ts
index 1d35997..71b178c 100644
--- a/src/app/api/remote-network/route.ts
+++ b/src/app/api/remote-network/route.ts
@@ -1,4 +1,4 @@
-import { NextRequest } from "next/server";
+import type { NextRequest } from "next/server";
 
 export const dynamic = "force-dynamic";
 export const runtime = "nodejs";
@@ -9,7 +9,8 @@ export async function POST(request: NextRequest) {
   }
 
   try {
-    const { method, url, status, requestBody, responseBody, duration } = await request.json();
+    const { method, url, status, requestBody, responseBody, duration } =
+      await request.json();
 
     const statusColor =
       status >= 500
@@ -23,12 +24,20 @@ export async function POST(request: NextRequest) {
     const resetColor = "\x1b[0m";
     const headerPrefix = "\x1b[35m📱 🌐 [HTTP]\x1b[0m"; // Magenta
 
-    console.log(`\n${headerPrefix} ${method} ${url} -> ${statusColor}${status}${resetColor} (${duration}ms)`);
+    console.log(
+      `\n${headerPrefix} ${method} ${url} -> ${statusColor}${status}${resetColor} (${duration}ms)`,
+    );
 
     if (requestBody) {
       try {
-        const parsedReq = typeof requestBody === "string" ? JSON.parse(requestBody) : requestBody;
-        console.log(`   \x1b[90mRequest Body:\x1b[0m`, JSON.stringify(parsedReq, null, 2));
+        const parsedReq =
+          typeof requestBody === "string"
+            ? JSON.parse(requestBody)
+            : requestBody;
+        console.log(
+          `   \x1b[90mRequest Body:\x1b[0m`,
+          JSON.stringify(parsedReq, null, 2),
+        );
       } catch {
         console.log(`   \x1b[90mRequest Body:\x1b[0m`, requestBody);
       }
@@ -36,8 +45,14 @@ export async function POST(request: NextRequest) {
 
     if (responseBody) {
       try {
-        const parsedRes = typeof responseBody === "string" ? JSON.parse(responseBody) : responseBody;
-        console.log(`   \x1b[90mResponse Body:\x1b[0m`, JSON.stringify(parsedRes, null, 2));
+        const parsedRes =
+          typeof responseBody === "string"
+            ? JSON.parse(responseBody)
+            : responseBody;
+        console.log(
+          `   \x1b[90mResponse Body:\x1b[0m`,
+          JSON.stringify(parsedRes, null, 2),
+        );
       } catch {
         console.log(`   \x1b[90mResponse Body:\x1b[0m`, responseBody);
       }
diff --git a/src/app/candidate-contact/page.tsx b/src/app/candidate-contact/page.tsx
index 471c638..590cd9c 100644
--- a/src/app/candidate-contact/page.tsx
+++ b/src/app/candidate-contact/page.tsx
@@ -50,7 +50,7 @@ export default function CandidateContactPage() {
           
         
 
-        
diff --git a/src/app/finding-match/page.tsx b/src/app/finding-match/page.tsx index fe0ae51..12d6681 100644 --- a/src/app/finding-match/page.tsx +++ b/src/app/finding-match/page.tsx @@ -2,16 +2,16 @@ import Image from "next/image"; import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; import { FaPen } from "react-icons/fa6"; import AdvisorActionsCard from "@/components/ui/advisor-actions-card"; import NavigationButton from "@/components/ui/navigation-button"; import { PageBackground } from "@/components/utils/page-background"; -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; +import { getSubmitPath } from "@/lib/get-submit-path"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; -import { getSubmitPath } from "@/lib/get-submit-path"; const advisorAvatars = [ { id: "advisor-primary", src: "/assets/images/Avatar Image.png" }, @@ -46,7 +46,7 @@ export default function FindingMatchPage() { <> -
diff --git a/src/app/globals.css b/src/app/globals.css index d3a1473..245533e 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -11,11 +11,11 @@ @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); + --font-sans: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; --font-mono: var(--font-geist-mono); - --font-arabic: var(--font-amiri); - --font-ryling: var(--font-amiri); - --font-faminela: var(--font-faminela-local); + --font-arabic: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + --font-ryling: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + --font-faminela: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; } /* Typography Configuration - Centralized Design System Scale */ @@ -66,12 +66,12 @@ body { html:lang(ar) body, :lang(ar) { - font-family: var(--font-arabic), "Times New Roman", serif; + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; } .font-arabic, .font-ryling { - font-family: var(--font-arabic), "Times New Roman", serif; + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; } .font-faminela:lang(ar), @@ -79,8 +79,9 @@ html:lang(ar) body, [dir="rtl"] .font-faminela, [dir="rtl"] .font-ryling, [dir="rtl"].font-faminela, -[dir="rtl"].font-ryling { - font-family: var(--font-arabic), "Times New Roman", serif; +[dir="rtl"].font-ryling, +.font-faminela { + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; } .app-shell { @@ -163,7 +164,9 @@ body[data-page-background="custom"] .app-shell { /* 3 Dots Bouncing Line Circle Loader for Buttons */ @keyframes button-dot-bounce { - 0%, 80%, 100% { + 0%, + 80%, + 100% { transform: translateY(0) scale(0.7); opacity: 0.4; } diff --git a/src/app/intro/page.tsx b/src/app/intro/page.tsx index 1aafaf5..ae2f38c 100644 --- a/src/app/intro/page.tsx +++ b/src/app/intro/page.tsx @@ -1,17 +1,17 @@ "use client"; import Image from "next/image"; -import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/navigation"; +import { useEffect, useRef, useState } from "react"; import Button from "@/components/ui/button"; import NavigationButton from "@/components/ui/navigation-button"; import ReportActionsSheet from "@/components/ui/report-actions-sheet"; -import { authBridge } from "@/lib/auth-bridge"; -import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; import type { MarriageProfileResponse } from "@/hooks/marriage/types"; +import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; +import { authBridge } from "@/lib/auth-bridge"; +import { getSubmitPath } from "@/lib/get-submit-path"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; -import { getSubmitPath } from "@/lib/get-submit-path"; const REDIRECT_SESSION_KEY = "redirect"; @@ -104,7 +104,10 @@ export default function Intro() { const { data: freshProfile } = await refetch(); profileResponse = freshProfile ?? profile; } catch (refetchError) { - console.warn("Could not refetch profile data – using fallback", refetchError); + console.warn( + "Could not refetch profile data – using fallback", + refetchError, + ); } const nextPath = localizePath(getSubmitPath(profileResponse), locale); @@ -210,11 +213,15 @@ export default function Intro() { />
-
-
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6c3f6b3..cf78adc 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -169,7 +169,10 @@ export default function RootLayout({ }} /> - + {isDevelopment ? (
diff --git a/src/app/new-match/page.tsx b/src/app/new-match/page.tsx index 5de9915..4c9b592 100644 --- a/src/app/new-match/page.tsx +++ b/src/app/new-match/page.tsx @@ -2,14 +2,12 @@ import Image from "next/image"; import Link from "next/link"; -import { useEffect, useMemo } from "react"; import { useRouter } from "next/navigation"; -import { localizePath } from "@/translations/config"; -import { getSubmitPath } from "@/lib/get-submit-path"; +import { useEffect, useMemo } from "react"; import { FaLock } from "react-icons/fa6"; import AdvisorActionsCard from "@/components/ui/advisor-actions-card"; -import NavigationButton from "@/components/ui/navigation-button"; import { DotsLoader } from "@/components/ui/button"; +import NavigationButton from "@/components/ui/navigation-button"; import { PageBackground } from "@/components/utils/page-background"; import type { MarriageField, @@ -18,8 +16,10 @@ import type { MarriagePhoneFieldValue, } from "@/hooks/marriage/types"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; -import { useI18n } from "@/translations/provider"; import { useViewPaddings } from "@/hooks/use-view-paddings"; +import { getSubmitPath } from "@/lib/get-submit-path"; +import { localizePath } from "@/translations/config"; +import { useI18n } from "@/translations/provider"; const advisorAvatars = [ { id: "advisor-primary", src: "/assets/images/Avatar Image.png" }, @@ -29,10 +29,30 @@ const advisorAvatars = [ const fieldCandidates = { name: ["name", "full_name", "fullname", "first_name", "display_name"], - occupation: ["occupation", "job", "profession", "career", "work", "education", "highest_level_of_education"], + occupation: [ + "occupation", + "job", + "profession", + "career", + "work", + "education", + "highest_level_of_education", + ], age: ["age"], - city: ["city", "current_city", "residence_city", "location", "residence", "birth_city"], - maritalStatus: ["marital_status", "maritalstatus", "relationship_status", "current_marital_status"], + city: [ + "city", + "current_city", + "residence_city", + "location", + "residence", + "birth_city", + ], + maritalStatus: [ + "marital_status", + "maritalstatus", + "relationship_status", + "current_marital_status", + ], cityPreference: [ "city_preference", "citypreference", @@ -222,7 +242,10 @@ export default function NewMatchPage() {
@@ -244,7 +267,9 @@ export default function NewMatchPage() { alt="notification" />
-

{matchHeadingTitle}

+

+ {matchHeadingTitle} +

{matchHeadingDescription}

@@ -316,13 +341,13 @@ export default function NewMatchPage() { getAdvisorHref="/questions-list" /> -
- - - - Profile locked - +
+ + + + Profile locked +
diff --git a/src/app/new-match/profile/page.tsx b/src/app/new-match/profile/page.tsx index 37abd4d..4d85ea6 100644 --- a/src/app/new-match/profile/page.tsx +++ b/src/app/new-match/profile/page.tsx @@ -221,7 +221,11 @@ export default function NewMatchProfilePage() { const [isRejectSheetOpen, setIsRejectSheetOpen] = useState(false); const [isDismissReasonSheetOpen, setIsDismissReasonSheetOpen] = useState(false); - const { data: profile, isLoading, refetch: refetchProfile } = useMarriageProfileQuery(); + const { + data: profile, + isLoading, + refetch: refetchProfile, + } = useMarriageProfileQuery(); useEffect(() => { if (!profile) { @@ -361,7 +365,9 @@ export default function NewMatchProfilePage() {
); - } else if (!item || !isQuestionListItemVisibleForProfile(item, profileContext)) { + } else if ( + !item || + !isQuestionListItemVisibleForProfile(item, profileContext) + ) { return null; } @@ -637,7 +662,8 @@ export default function QuestionDetailClient({ ); } - const bulletKey = item.slug === "glasser_5_needs_test" ? "glasser" : "personality"; + const bulletKey = + item.slug === "glasser_5_needs_test" ? "glasser" : "personality"; const bullets = t.questions.testIntroBullets[bulletKey]; return ( @@ -684,7 +710,6 @@ export default function QuestionDetailClient({ ); } - const dobQuestion = visibleQuestions.find( (question) => question.title === "Date of Birth", ); @@ -743,4 +768,3 @@ export default function QuestionDetailClient({ ); } - diff --git a/src/app/questions-list/[slug]/test-intro-client.tsx b/src/app/questions-list/[slug]/test-intro-client.tsx index 4a59530..70de7cc 100644 --- a/src/app/questions-list/[slug]/test-intro-client.tsx +++ b/src/app/questions-list/[slug]/test-intro-client.tsx @@ -1,10 +1,10 @@ "use client"; import { useRouter } from "next/navigation"; +import TestIntroPage from "@/components/questions/test-intro-page"; import NavigationButton from "@/components/ui/navigation-button"; import StickyHeader from "@/components/ui/sticky-header"; import { PageBackground } from "@/components/utils/page-background"; -import TestIntroPage from "@/components/questions/test-intro-page"; type TestIntroClientProps = { title: string; diff --git a/src/app/questions-list/page.tsx b/src/app/questions-list/page.tsx index 92e9af0..b3dab6f 100644 --- a/src/app/questions-list/page.tsx +++ b/src/app/questions-list/page.tsx @@ -4,6 +4,11 @@ import Image from "next/image"; import { useRouter } from "next/navigation"; import { useMemo, useState } from "react"; import { IoClose } from "react-icons/io5"; +import { + getLocalSectionProgress, + getStoredAge, +} from "@/components/questions/progress-helper"; +import { hasQuestionAnswerValue } from "@/components/questions/question-answer-storage"; import QuestionCard from "@/components/questions/question-card"; import RequiredStepsCard from "@/components/questions/required-steps-card"; import Button from "@/components/ui/button"; @@ -17,20 +22,18 @@ import { isQuestionVisibleForProfile, type QuestionListItem, } from "@/data/question-data"; -import { hasQuestionAnswerValue } from "@/components/questions/question-answer-storage"; +import { toFrontendSlug } from "@/data/section-slug-map"; +import { useStartMarriageMatchMutation } from "@/hooks/marriage/use-match-start"; +import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; +import { useMarriageSectionsQuery } from "@/hooks/marriage/use-sections"; +import { useCloseServiceOnBack } from "@/hooks/use-close-service-on-back"; import { clearMatchStartGrace, markMatchStarted, } from "@/lib/match-start-grace"; -import { useStartMarriageMatchMutation } from "@/hooks/marriage/use-match-start"; -import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; -import { useMarriageSectionsQuery } from "@/hooks/marriage/use-sections"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; -import { toFrontendSlug } from "@/data/section-slug-map"; import SectionsRequest from "./sections-request"; -import { getStoredAge, getLocalSectionProgress } from "@/components/questions/progress-helper"; -import { useCloseServiceOnBack } from "@/hooks/use-close-service-on-back"; export default function QuestionsListPage() { useCloseServiceOnBack(); @@ -70,7 +73,10 @@ export default function QuestionsListPage() { sections?.forEach((section) => { const frontendSlug = toFrontendSlug(section.slug); - const progress = Math.max(0, Math.min(100, Math.round(section.completion_percent))); + const progress = Math.max( + 0, + Math.min(100, Math.round(section.completion_percent)), + ); progressBySlug.set(frontendSlug, progress); progressBySlug.set(section.slug, progress); }); @@ -106,13 +112,12 @@ export default function QuestionsListPage() { const isProfileBlocked = profileStatus === "in_case" || profileStatus === "matched"; const canStartMatch = - !isProfileSuspended && - !isProfileBlocked && - allRequiredSectionsCompleted; + !isProfileSuspended && !isProfileBlocked && allRequiredSectionsCompleted; const isStartMatchDisabled = startMatchMutation.isPending || !canStartMatch; const hasIncompleteOptionalSections = useMemo(() => { return questionListItems.some( - (item) => !item.required && (sectionProgressBySlug.get(item.slug) ?? 0) < 100, + (item) => + !item.required && (sectionProgressBySlug.get(item.slug) ?? 0) < 100, ); }, [questionListItems, sectionProgressBySlug]); diff --git a/src/app/request-accepted/page.tsx b/src/app/request-accepted/page.tsx index d35f3c8..803667a 100644 --- a/src/app/request-accepted/page.tsx +++ b/src/app/request-accepted/page.tsx @@ -4,15 +4,17 @@ import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; -import { getSubmitPath } from "@/lib/get-submit-path"; import { FiCopy, FiPhone } from "react-icons/fi"; +import { DotsLoader } from "@/components/ui/button"; import CallResultSheet from "@/components/ui/call-result-sheet"; import FemaleConsentSheet from "@/components/ui/female-consent-sheet"; import NavigationButton from "@/components/ui/navigation-button"; import SubscriptionRequiredSheet from "@/components/ui/subscription-required-sheet"; -import { DotsLoader } from "@/components/ui/button"; import { PageBackground } from "@/components/utils/page-background"; -import type { MarriageField, MarriagePhoneFieldValue } from "@/hooks/marriage/types"; +import type { + MarriageField, + MarriagePhoneFieldValue, +} from "@/hooks/marriage/types"; import { useMarriageContactInfoQuery } from "@/hooks/marriage/use-contact-info"; import { useSubmitMarriageContactStatusMutation } from "@/hooks/marriage/use-contact-status"; import { @@ -20,6 +22,7 @@ import { useHabcoinPaymentMutation, } from "@/hooks/marriage/use-habcoin-payment"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; +import { getSubmitPath } from "@/lib/get-submit-path"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; @@ -99,27 +102,37 @@ function ContactInfoPhoneCard({ item }: { item: ContactInfoPhoneItem }) {

{item.label}

-

{item.phoneNumber}

+

+ {item.phoneNumber} +

- copy + copy
@@ -152,11 +165,14 @@ export default function RequestAcceptedPage() { const caseStatus = profile?.active_case?.status; const recommendedPlanId = profile?.recommended_plan?.id; const paymentMutation = useHabcoinPaymentMutation(); - const contactStatusMutation = useSubmitMarriageContactStatusMutation(caseId ?? "", { - onSuccess: () => { - router.push(localizePath("/finding-match", locale)); + const contactStatusMutation = useSubmitMarriageContactStatusMutation( + caseId ?? "", + { + onSuccess: () => { + router.push(localizePath("/finding-match", locale)); + }, }, - }); + ); const contactInfoQuery = useMarriageContactInfoQuery(caseId, { enabled: false, }); @@ -231,7 +247,8 @@ export default function RequestAcceptedPage() { if (!caseId || contactStatusMutation.isPending) return; await contactStatusMutation.mutateAsync({ action: "no_contact", - custom_note: "No contact reported by female candidate after decision window", + custom_note: + "No contact reported by female candidate after decision window", }); }; @@ -282,7 +299,7 @@ export default function RequestAcceptedPage() { /> ) : null} -
@@ -323,7 +340,11 @@ export default function RequestAcceptedPage() { className="max-w-[212px] cursor-pointer appearance-none border-0 bg-transparent p-0 text-left" >
- {contactStatusMutation.isPending ? : primaryActionText} + {contactStatusMutation.isPending ? ( + + ) : ( + primaryActionText + )}
) : ( @@ -343,7 +364,11 @@ export default function RequestAcceptedPage() { className="max-w-[212px] appearance-none border-0 bg-transparent p-0 text-left" >
- {paymentMutation.isPending ? : secondaryActionText} + {paymentMutation.isPending ? ( + + ) : ( + secondaryActionText + )}
diff --git a/src/app/request-sent/page.tsx b/src/app/request-sent/page.tsx index 83b7cf5..50683b7 100644 --- a/src/app/request-sent/page.tsx +++ b/src/app/request-sent/page.tsx @@ -1,17 +1,16 @@ "use client"; import Image from "next/image"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect } from "react"; import AdvisorActionsCard from "@/components/ui/advisor-actions-card"; import NavigationButton from "@/components/ui/navigation-button"; import { PageBackground } from "@/components/utils/page-background"; -import { useI18n } from "@/translations/provider"; -import Link from "next/link"; - -import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; -import { localizePath } from "@/translations/config"; import { getSubmitPath } from "@/lib/get-submit-path"; +import { localizePath } from "@/translations/config"; +import { useI18n } from "@/translations/provider"; const advisorAvatars = [ { id: "advisor-primary", src: "/assets/images/Avatar Image.png" }, @@ -39,7 +38,8 @@ export default function RequestSentPage() { const copy = t.findingMatch; const requestSentCopy = (t as any).requestSent ?? { title: "درخواست ارسال شد", - description: "درخواست معرفی شما از طرف ما به خانواده طرف مقابل ارسال شد. در صورت تایید ایشان، اطلاعات تماس به اطلاع شما خواهد رسید.", + description: + "درخواست معرفی شما از طرف ما به خانواده طرف مقابل ارسال شد. در صورت تایید ایشان، اطلاعات تماس به اطلاع شما خواهد رسید.", matchProfile: "مشاهده پروفایل گزینه", profileLocked: "پروفایل قفل است", }; @@ -48,7 +48,7 @@ export default function RequestSentPage() { <> -
@@ -79,11 +79,14 @@ export default function RequestSentPage() { {requestSentCopy.description}

- +
{requestSentCopy.matchProfile}
- +
diff --git a/src/components/dev/dev-click-to-component.tsx b/src/components/dev/dev-click-to-component.tsx index 3ce2122..a808144 100644 --- a/src/components/dev/dev-click-to-component.tsx +++ b/src/components/dev/dev-click-to-component.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; const IDE_SCHEMES = [ { @@ -48,10 +48,18 @@ function parseLocator(locator: string) { export function DevClickToComponent() { const [isInspecting, setIsInspecting] = useState(false); const [isMobile, setIsMobile] = useState(false); - const [position, setPosition] = useState<{ x: number; y: number } | null>(null); + const [position, setPosition] = useState<{ x: number; y: number } | null>( + null, + ); const [isDragging, setIsDragging] = useState(false); - - const dragStart = useRef({ x: 0, y: 0, buttonX: 0, buttonY: 0, hasMoved: false }); + + const dragStart = useRef({ + x: 0, + y: 0, + buttonX: 0, + buttonY: 0, + hasMoved: false, + }); // Detect mobile size useEffect(() => { @@ -127,13 +135,12 @@ export function DevClickToComponent() { body: JSON.stringify({ locator: locatorString, userAgent }), }).catch((err) => { console.error("[DevClickToComponent] Error sending API request:", err); - + // Fallback to URL scheme const ideUrl = IDE_SCHEMES.find(({ matches }) => matches.some((match) => userAgent.includes(match)), - )?.createUrl(locatorString) ?? - `antigravity://file/${locatorString}`; + )?.createUrl(locatorString) ?? `antigravity://file/${locatorString}`; try { window.location.href = ideUrl; @@ -172,7 +179,10 @@ export function DevClickToComponent() { ?.getAttribute("data-locator"); if (locator) { - console.log(`[DevClickToComponent] Inspect Mode matched element. Opening in IDE:`, locator); + console.log( + `[DevClickToComponent] Inspect Mode matched element. Opening in IDE:`, + locator, + ); // Flash target element outline briefly as visual feedback const element = target.closest("[data-locator]"); @@ -193,7 +203,10 @@ export function DevClickToComponent() { body: JSON.stringify({ locator, userAgent }), }); } catch (err) { - console.error("[DevClickToComponent] Error sending API request:", err); + console.error( + "[DevClickToComponent] Error sending API request:", + err, + ); } } @@ -202,7 +215,7 @@ export function DevClickToComponent() { // Use capturing phase to intercept clicks/taps before they trigger other actions document.addEventListener("click", handleInspectClick, true); - + return () => { document.removeEventListener("click", handleInspectClick, true); }; @@ -229,7 +242,11 @@ export function DevClickToComponent() { body: JSON.stringify({ type, args }), }); } catch (err) { - originalError.call(console, "[DevClickToComponent] Failed to forward log to server:", err); + originalError.call( + console, + "[DevClickToComponent] Failed to forward log to server:", + err, + ); } finally { isSending = false; } @@ -280,7 +297,8 @@ export function DevClickToComponent() { return originalFetch(input, init); } - const method = init?.method ?? (input instanceof Request ? input.method : "GET"); + const method = + init?.method ?? (input instanceof Request ? input.method : "GET"); const startTime = Date.now(); let requestBody: string | null = null; @@ -360,7 +378,12 @@ export function DevClickToComponent() { const originalOpen = XMLHttpRequest.prototype.open; const originalSend = XMLHttpRequest.prototype.send; - XMLHttpRequest.prototype.open = function (this: any, method: any, url: any, ...args: any[]) { + XMLHttpRequest.prototype.open = function ( + this: any, + method: any, + url: any, + ...args: any[] + ) { this._method = method; this._url = typeof url === "string" ? url : url.toString(); return originalOpen.apply(this, [method, url, ...args] as any); @@ -384,7 +407,7 @@ export function DevClickToComponent() { const duration = Date.now() - startTime; const status = this.status; let responseBody = ""; - + try { responseBody = this.responseText; } catch { @@ -408,20 +431,22 @@ export function DevClickToComponent() { } } - window.fetch("/api/remote-network", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - method, - url, - status, - requestBody, - responseBody, - duration, - }), - }).catch(() => {}); + window + .fetch("/api/remote-network", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + method, + url, + status, + requestBody, + responseBody, + duration, + }), + }) + .catch(() => {}); }); return originalSend.apply(this, [body]); @@ -437,8 +462,8 @@ export function DevClickToComponent() { const handlePointerDown = (e: React.PointerEvent) => { e.currentTarget.setPointerCapture(e.pointerId); setIsDragging(true); - const startX = position?.x ?? (window.innerWidth - 66); - const startY = position?.y ?? (window.innerHeight - 126); + const startX = position?.x ?? window.innerWidth - 66; + const startY = position?.y ?? window.innerHeight - 126; dragStart.current = { x: e.clientX, y: e.clientY, @@ -452,13 +477,19 @@ export function DevClickToComponent() { if (!isDragging) return; const dx = e.clientX - dragStart.current.x; const dy = e.clientY - dragStart.current.y; - + if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { dragStart.current.hasMoved = true; } - const newX = Math.max(16, Math.min(window.innerWidth - 66, dragStart.current.buttonX + dx)); - const newY = Math.max(16, Math.min(window.innerHeight - 126, dragStart.current.buttonY + dy)); + const newX = Math.max( + 16, + Math.min(window.innerWidth - 66, dragStart.current.buttonX + dx), + ); + const newY = Math.max( + 16, + Math.min(window.innerHeight - 126, dragStart.current.buttonY + dy), + ); setPosition({ x: newX, y: newY }); }; @@ -481,7 +512,7 @@ export function DevClickToComponent() { const handleSendStorageClick = async () => { if (dragStart.current.hasMoved) return; if (isSendingStorage) return; - + setIsSendingStorage(true); setSendSuccess(false); @@ -512,7 +543,10 @@ export function DevClickToComponent() { setTimeout(() => setSendSuccess(false), 2000); } } catch (err) { - console.error("[DevClickToComponent] Failed to send localStorage values:", err); + console.error( + "[DevClickToComponent] Failed to send localStorage values:", + err, + ); } finally { setIsSendingStorage(false); } @@ -553,24 +587,65 @@ export function DevClickToComponent() { alignItems: "center", justifyContent: "center", cursor: isDragging ? "grabbing" : "pointer", - transition: isDragging ? "none" : "background-color 0.25s, transform 0.25s, box-shadow 0.25s", + transition: isDragging + ? "none" + : "background-color 0.25s, transform 0.25s, box-shadow 0.25s", outline: "none", transform: isSendingStorage ? "scale(0.95)" : "scale(1)", }} title="Send LocalStorage to Terminal API" > {isSendingStorage ? ( - - - + + + ) : sendSuccess ? ( - - + + ) : ( - - + + )} @@ -590,26 +665,50 @@ export function DevClickToComponent() { backgroundColor: isInspecting ? "#3b82f6" : "#1f2937", color: "#ffffff", border: "none", - boxShadow: isInspecting - ? "0 0 15px rgba(59, 130, 246, 0.6)" + boxShadow: isInspecting + ? "0 0 15px rgba(59, 130, 246, 0.6)" : "0 4px 12px rgba(0,0,0,0.35)", display: "flex", alignItems: "center", justifyContent: "center", cursor: isDragging ? "grabbing" : "pointer", - transition: isDragging ? "none" : "background-color 0.25s, transform 0.25s, box-shadow 0.25s", + transition: isDragging + ? "none" + : "background-color 0.25s, transform 0.25s, box-shadow 0.25s", outline: "none", transform: isInspecting ? "scale(1.1)" : "scale(1)", }} title="Toggle Dev Inspect Mode (Drag to move)" > {isInspecting ? ( - - + + ) : ( - - + + )} diff --git a/src/components/questions/progress-helper.ts b/src/components/questions/progress-helper.ts index 4060573..3b90efe 100644 --- a/src/components/questions/progress-helper.ts +++ b/src/components/questions/progress-helper.ts @@ -1,14 +1,16 @@ import { - type QuestionListItem, - isQuestionVisibleForProfile, isQuestionRequiredForProfile, + isQuestionVisibleForProfile, + type QuestionListItem, } from "@/data/question-data"; import { hasQuestionAnswerValue } from "./question-answer-storage"; export function getStoredAge(): number | null { try { if (typeof window === "undefined") return null; - const rawValue = window.localStorage.getItem("marriage:sections:personal_info:answers"); + const rawValue = window.localStorage.getItem( + "marriage:sections:personal_info:answers", + ); if (!rawValue) return null; const storedAnswers = JSON.parse(rawValue); const ageField = storedAnswers.fields?.find((f: any) => f.label === "Age"); @@ -16,7 +18,9 @@ export function getStoredAge(): number | null { const num = Number(ageField.value); if (Number.isFinite(num)) return num; } - const dobField = storedAnswers.fields?.find((f: any) => f.label === "Date of Birth"); + const dobField = storedAnswers.fields?.find( + (f: any) => f.label === "Date of Birth", + ); if (dobField && dobField.value) { const dob = new Date(dobField.value); if (!Number.isNaN(dob.getTime())) { @@ -29,11 +33,27 @@ export function getStoredAge(): number | null { return age >= 0 ? age : null; } } - } catch (e) { } + } catch (e) {} return null; } -export function getLocalSectionProgress(item: QuestionListItem, profile: any, age: number | null): number | null { +function isFieldAnswered(q: any, field: any): boolean { + if (!field || !hasQuestionAnswerValue(field.value)) { + return false; + } + if (q.type === "birthplace") { + const strVal = String(field.value); + const parts = strVal.split(",").map((p) => p.trim()); + return parts.length >= 2 && parts[0].length > 0 && parts[1].length > 0; + } + return true; +} + +export function getLocalSectionProgress( + item: QuestionListItem, + profile: any, + age: number | null, +): number | null { try { if (typeof window === "undefined") return null; const storageKey = `marriage:sections:${item.slug}:answers`; @@ -45,7 +65,11 @@ export function getLocalSectionProgress(item: QuestionListItem, profile: any, ag if (storedValue && storedValue.completed) { return 100; } - if (!storedValue || !Array.isArray(storedValue.fields) || storedValue.fields.length === 0) { + if ( + !storedValue || + !Array.isArray(storedValue.fields) || + storedValue.fields.length === 0 + ) { return null; } @@ -55,7 +79,9 @@ export function getLocalSectionProgress(item: QuestionListItem, profile: any, ag }; const visibleQuestions = item.questions - .filter((question) => isQuestionVisibleForProfile(question, profileContext)) + .filter((question) => + isQuestionVisibleForProfile(question, profileContext), + ) .map((question) => ({ ...question, required: isQuestionRequiredForProfile(question, profileContext), @@ -67,22 +93,40 @@ export function getLocalSectionProgress(item: QuestionListItem, profile: any, ag return 100; } const answeredCount = visibleQuestions.filter((q, index) => { - const slugifyTitle = (title: string) => title.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, ""); + const slugifyTitle = (title: string) => + title + .normalize("NFKD") + .replace(/[\u0300-\u036f]/g, "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, "_") + .replace(/^_+|_+$/g, ""); const fieldKey = `q${index + 1}_${slugifyTitle(q.title)}`; - const field = storedValue.fields.find((f: any) => f.key === fieldKey || f.label === q.title); - return field && hasQuestionAnswerValue(field.value); + const field = storedValue.fields.find( + (f: any) => f.key === fieldKey || f.label === q.title, + ); + return isFieldAnswered(q, field); }).length; return Math.round((answeredCount / visibleQuestions.length) * 100); } const answeredRequiredCount = requiredQuestions.filter((q) => { - const originalIndex = item.questions.findIndex((origQ) => origQ.title === q.title); + const originalIndex = item.questions.findIndex( + (origQ) => origQ.title === q.title, + ); if (originalIndex === -1) return false; - const slugifyTitle = (title: string) => title.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, ""); + const slugifyTitle = (title: string) => + title + .normalize("NFKD") + .replace(/[\u0300-\u036f]/g, "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, "_") + .replace(/^_+|_+$/g, ""); const fieldKey = `q${originalIndex + 1}_${slugifyTitle(q.title)}`; - const field = storedValue.fields.find((f: any) => f.key === fieldKey || f.label === q.title); - return field && hasQuestionAnswerValue(field.value); + const field = storedValue.fields.find( + (f: any) => f.key === fieldKey || f.label === q.title, + ); + return isFieldAnswered(q, field); }).length; return Math.round((answeredRequiredCount / requiredQuestions.length) * 100); diff --git a/src/components/questions/question-answer-storage.tsx b/src/components/questions/question-answer-storage.tsx index ac79fef..d7306dc 100644 --- a/src/components/questions/question-answer-storage.tsx +++ b/src/components/questions/question-answer-storage.tsx @@ -11,16 +11,19 @@ import { useState, } from "react"; import type { QuestionField } from "@/data/question-data"; +import { toBackendSlug } from "@/data/section-slug-map"; import { pathParam } from "@/hooks/marriage/path-param"; -import { getApiRequestUrl } from "@/lib/http"; import type { MarriageField, MarriageFieldValue, MarriagePhoneFieldValue, UpdateMarriageSectionDataPayload, } from "@/hooks/marriage/types"; -import { useUpdateMarriageSectionDataMutation, useMarriageSectionDataQuery } from "@/hooks/marriage/use-section-data"; -import { toBackendSlug } from "@/data/section-slug-map"; +import { + useMarriageSectionDataQuery, + useUpdateMarriageSectionDataMutation, +} from "@/hooks/marriage/use-section-data"; +import { getApiRequestUrl } from "@/lib/http"; const STORAGE_VERSION = 1; @@ -123,7 +126,9 @@ function isMarriageField(value: unknown): value is MarriageField { ); } -function isMarriagePhoneFieldValue(value: unknown): value is MarriagePhoneFieldValue { +function isMarriagePhoneFieldValue( + value: unknown, +): value is MarriagePhoneFieldValue { if (!value || typeof value !== "object") { return false; } @@ -175,7 +180,10 @@ function getOrderedFields( return orderedFields; } -function getCurrentStep(fields: MarriageField[], questions: readonly QuestionField[]) { +function getCurrentStep( + fields: MarriageField[], + questions: readonly QuestionField[], +) { return questions.filter((question, index) => { if (!question.required || question.logic?.dependsOn) { return false; @@ -192,7 +200,7 @@ function createPayload( ): UpdateMarriageSectionDataPayload { const fields = getOrderedFields(answers, questions); const targetQuestions = questions.filter( - (q) => q.required && !q.logic?.dependsOn + (q) => q.required && !q.logic?.dependsOn, ); return { @@ -271,7 +279,9 @@ function writeStoredAnswers( function getKeepalivePatchUrl(slug: string) { const backendSlug = toBackendSlug(slug); - return getApiRequestUrl(`/api/marriage/sections/${pathParam(backendSlug)}/data/`); + return getApiRequestUrl( + `/api/marriage/sections/${pathParam(backendSlug)}/data/`, + ); } export function QuestionAnswersProvider({ diff --git a/src/components/questions/question-birthplace.tsx b/src/components/questions/question-birthplace.tsx new file mode 100644 index 0000000..890a99a --- /dev/null +++ b/src/components/questions/question-birthplace.tsx @@ -0,0 +1,716 @@ +"use client"; + +import { useCallback, useEffect, useRef, useState } from "react"; +import { getCountryList, COUNTRIES_EN, COUNTRIES_FA } from "@/data/countries"; +import type { QuestionField } from "@/data/question-data"; +import { useI18n } from "@/translations/provider"; +import { useQuestionAnswers } from "./question-answer-storage"; +import QuestionTitle from "./question-title"; + +type QuestionBirthplaceProps = { + question: QuestionField; + questionIndex: number; + disabled?: boolean; +}; + +type BirthplaceValue = { + country?: string; + city?: string; +}; + +function parseValue(rawValue: unknown): { country: string; city: string } { + if (!rawValue) return { country: "", city: "" }; + + if (typeof rawValue === "object" && rawValue !== null) { + const obj = rawValue as BirthplaceValue; + return { + country: typeof obj.country === "string" ? obj.country : "", + city: typeof obj.city === "string" ? obj.city : "", + }; + } + + if (typeof rawValue === "string") { + let str = rawValue.trim(); + // Clean legacy country names with parentheses containing commas + str = str.replace( + "United Kingdom (UK, England, Wales, Scotland, Northern Ireland)", + "United Kingdom (UK)", + ); + str = str.replace("United States (US, USA, America)", "United States (US)"); + str = str.replace( + "United Arab Emirates (UAE, Dubai, Abu Dhabi)", + "United Arab Emirates (UAE)", + ); + str = str.replace("Congo (Congo-Brazzaville)", "Congo"); + str = str.replace("Czechia (Czech Republic)", "Czechia"); + str = str.replace("Myanmar (formerly Burma)", "Myanmar"); + str = str.replace( + "امارات متحده عربی (دبی، ابوظبی، UAE)", + "امارات متحده عربی (UAE)", + ); + str = str.replace( + "بریتانیا (انگلستان، اسکاتلند، ولز، ایرلند شمالی، UK)", + "بریتانیا (UK)", + ); + str = str.replace( + "ایالات متحده آمریکا (آمریکا، US، USA)", + "ایالات متحده آمریکا (US)", + ); + + if (str.includes(",")) { + const parts = str.split(",").map((s) => s.trim()); + return { city: parts[0] || "", country: parts[1] || "" }; + } + if (str.includes(" - ")) { + const parts = str.split(" - ").map((s) => s.trim()); + return { country: parts[0] || "", city: parts[1] || "" }; + } + const isCountry = COUNTRIES_EN.includes(str) || COUNTRIES_FA.includes(str); + if (isCountry) { + return { country: str, city: "" }; + } + return { country: "", city: str }; + } + + return { country: "", city: "" }; +} + +export function QuestionBirthplace({ + question, + questionIndex, + disabled, +}: QuestionBirthplaceProps) { + const { dictionary: t, locale } = useI18n(); + const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); + const rawValue = getAnswerValue(question, questionIndex); + + const initial = parseValue(rawValue); + const [selectedCountry, setSelectedCountry] = useState(initial.country); + const [cityInput, setCityInput] = useState(initial.city); + + const [isOpen, setIsOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + const containerRef = useRef(null); + const listRef = useRef(null); + const searchInputRef = useRef(null); + + const isResidence = + question.title.toLowerCase().includes("residence") || + question.title.includes("سکونت"); + + const [mode, setMode] = useState<"auto" | "manual">("auto"); + const [isDetecting, setIsDetecting] = useState(false); + const [detectedLocation, setDetectedLocation] = useState(""); + + const updateAnswers = (country: string, city: string) => { + const formatted = + city && country ? `${city}, ${country}` : city || country || null; + setAnswerValue(question, questionIndex, formatted); + }; + + // GeoIP detection logic + const detectLocation = (force = false) => { + const alreadyChecked = + typeof window !== "undefined" + ? localStorage.getItem("hasCheckedGeoIPResidence") + : "true"; + if (alreadyChecked && !force) { + if (rawValue) { + const parsed = parseValue(rawValue); + if (parsed.country && parsed.city) { + setDetectedLocation(`${parsed.city}, ${parsed.country}`); + setMode("auto"); + } else { + setMode("manual"); + } + } else { + setMode("auto"); + } + return; + } + + // If there is already a saved value and we are not forcing, do not fetch again + if (rawValue && !force) { + const parsed = parseValue(rawValue); + if (parsed.country && parsed.city) { + setDetectedLocation(`${parsed.city}, ${parsed.country}`); + setMode("auto"); + } else { + setMode("manual"); + } + return; + } + + setIsDetecting(true); + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPResidence", "true"); + } + fetch("https://ipapi.co/json/") + .then((res) => res.json()) + .then((data) => { + if (data && data.city && data.country_name) { + const city = data.city; + const country = data.country_name; + setSelectedCountry(country); + setCityInput(city); + setDetectedLocation(`${city}, ${country}`); + updateAnswers(country, city); + setMode("auto"); + } else { + throw new Error("Missing data"); + } + }) + .catch(() => { + fetch("https://ipwho.is/") + .then((res) => res.json()) + .then((data) => { + if (data && data.city && data.country) { + const city = data.city; + const country = data.country; + setSelectedCountry(country); + setCityInput(city); + setDetectedLocation(`${city}, ${country}`); + updateAnswers(country, city); + setMode("auto"); + } else { + setMode("manual"); + } + }) + .catch(() => { + setMode("manual"); + }); + }) + .finally(() => { + setIsDetecting(false); + }); + }; + + useEffect(() => { + if (isResidence) { + detectLocation(); + } + }, [isResidence]); + + const handleAutoClick = () => { + setMode("auto"); + detectLocation(true); + }; + + const handleManualClick = () => { + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPResidence", "true"); + } + setMode("manual"); + setSelectedCountry(""); + setCityInput(""); + updateAnswers("", ""); + }; + + // Synchronize state if rawValue changes externally + useEffect(() => { + const updated = parseValue(rawValue); + if (updated.country !== selectedCountry) { + setSelectedCountry(updated.country); + } + if (updated.city.trim() !== cityInput.trim()) { + setCityInput(updated.city); + } + if (updated.country && updated.city) { + setDetectedLocation(`${updated.city}, ${updated.country}`); + } + }, [rawValue]); + + // Lock page scroll when dropdown is open + useEffect(() => { + if (isOpen) { + document.body.classList.add("dropdown-open"); + document.body.style.overflow = "hidden"; + document.documentElement.style.overflow = "hidden"; + } else { + document.body.classList.remove("dropdown-open"); + document.body.style.overflow = ""; + document.documentElement.style.overflow = ""; + } + return () => { + document.body.classList.remove("dropdown-open"); + document.body.style.overflow = ""; + document.documentElement.style.overflow = ""; + }; + }, [isOpen]); + + useEffect(() => { + if (isOpen) { + const timer = setTimeout(() => { + searchInputRef.current?.focus(); + }, 50); + return () => clearTimeout(timer); + } + }, [isOpen]); + + const handleListWheel = useCallback((e: React.WheelEvent) => { + e.stopPropagation(); + const el = listRef.current; + if (!el) return; + + const atTop = el.scrollTop <= 0 && e.deltaY < 0; + const atBottom = + el.scrollTop + el.clientHeight >= el.scrollHeight && e.deltaY > 0; + + if (atTop || atBottom) { + e.preventDefault(); + } + }, []); + + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + setIsOpen(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); + + const options = getCountryList(locale); + const filteredOptions = options.filter((option) => + option.toLowerCase().includes(searchQuery.toLowerCase()), + ); + + const handleSelectCountry = (country: string) => { + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPResidence", "true"); + } + setSelectedCountry(country); + setCityInput(""); + setIsOpen(false); + updateAnswers(country, ""); + }; + + const handleCityChange = (e: React.ChangeEvent) => { + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPResidence", "true"); + } + const newCity = e.target.value; + setCityInput(newCity); + updateAnswers(selectedCountry, newCity); + }; + + const isRtl = locale === "fa" || locale === "ar" || locale === "ur"; + const selectCountryPlaceholder = isRtl ? "انتخاب کشور" : "Select country"; + const cityPlaceholder = + question.extras?.placeHolder || + (isRtl ? "شهر، منطقه یا محله" : "City, region, or neighborhood"); + + return ( +
+ + + {isResidence ? ( + <> + {/* GeoIP Auto/Manual selector UI */} +
+ {/* Left Side: Location Info */} +
+ + + + + {isDetecting + ? locale === "fa" + ? "در حال شناسایی..." + : "Detecting..." + : detectedLocation || + (locale === "fa" ? "نامشخص" : "Unknown")} + +
+ + {/* Right Side: Toggle Buttons */} +
+ {/* Auto Button */} + + + {/* Manual Button */} + +
+
+ + {mode === "manual" && ( +
+ {/* Country Selection Dropdown */} +
+ + + {isOpen && ( +
+ {options.length > 3 || searchQuery ? ( +
+ + + + + setSearchQuery(e.target.value)} + placeholder="Search..." + className="flex-1 bg-transparent text-[14px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" + /> + {searchQuery ? ( + + ) : null} +
+ ) : null} + +
e.stopPropagation()} + onTouchMove={(e) => e.stopPropagation()} + onTouchEnd={(e) => e.stopPropagation()} + className="flex max-h-[220px] flex-col gap-3.5 overflow-y-auto overscroll-contain pr-1" + > + {filteredOptions.length > 0 ? ( + filteredOptions.map((option) => { + const isSelected = selectedCountry === option; + + return ( + + ); + }) + ) : ( + + No options found + + )} +
+
+ )} +
+ + {/* City Text Input */} +
+ +
+
+ )} + + ) : ( + <> + {/* 1. Country Selection Dropdown */} +
+ + + {isOpen && ( +
+ {options.length > 3 || searchQuery ? ( +
+ + + + + setSearchQuery(e.target.value)} + placeholder="Search..." + className="flex-1 bg-transparent text-[14px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" + /> + {searchQuery ? ( + + ) : null} +
+ ) : null} + +
e.stopPropagation()} + onTouchMove={(e) => e.stopPropagation()} + onTouchEnd={(e) => e.stopPropagation()} + className="flex max-h-[220px] flex-col gap-3.5 overflow-y-auto overscroll-contain pr-1" + > + {filteredOptions.length > 0 ? ( + filteredOptions.map((option) => { + const isSelected = selectedCountry === option; + + return ( + + ); + }) + ) : ( + + No options found + + )} +
+
+ )} +
+ + {/* 2. City Text Input */} +
+ +
+ + )} +
+ ); +} + +export default QuestionBirthplace; diff --git a/src/components/questions/question-card.tsx b/src/components/questions/question-card.tsx index 07222b4..a83c95f 100644 --- a/src/components/questions/question-card.tsx +++ b/src/components/questions/question-card.tsx @@ -1,3 +1,4 @@ +import Image from "next/image"; import Link from "next/link"; import type { IconType } from "react-icons"; import { @@ -11,7 +12,6 @@ import { import type { QuestionCardIcon, QuestionListItem } from "@/data/question-data"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; -import Image from "next/image"; type QuestionCardProps = { item: QuestionListItem; diff --git a/src/components/questions/question-date.tsx b/src/components/questions/question-date.tsx index daa4669..9375e66 100644 --- a/src/components/questions/question-date.tsx +++ b/src/components/questions/question-date.tsx @@ -2,9 +2,9 @@ import { useEffect, useMemo, useState } from "react"; import type { QuestionField } from "@/data/question-data"; +import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; -import { useI18n } from "@/translations/provider"; type QuestionDateProps = { question: QuestionField; @@ -36,7 +36,9 @@ const DAYS = Array.from({ length: 31 }, (_, i) => { const MIN_AGE = 18; const currentYear = new Date().getFullYear(); const maxBirthYear = currentYear - MIN_AGE; -const YEARS = Array.from({ length: 80 }, (_, i) => (maxBirthYear - i).toString()); +const YEARS = Array.from({ length: 80 }, (_, i) => + (maxBirthYear - i).toString(), +); export function QuestionDate({ question, @@ -76,7 +78,14 @@ export function QuestionDate({ const m = Number.parseInt(selectedMonth, 10); const d = Number.parseInt(selectedDay, 10); - if (!y || !m || !d || Number.isNaN(y) || Number.isNaN(m) || Number.isNaN(d)) { + if ( + !y || + !m || + !d || + Number.isNaN(y) || + Number.isNaN(m) || + Number.isNaN(d) + ) { return null; } @@ -103,7 +112,11 @@ export function QuestionDate({ if (y && m && d) { const formattedMonth = m.padStart(2, "0"); const formattedDay = d.padStart(2, "0"); - setAnswerValue(question, questionIndex, `${y}-${formattedMonth}-${formattedDay}`); + setAnswerValue( + question, + questionIndex, + `${y}-${formattedMonth}-${formattedDay}`, + ); } else { setAnswerValue(question, questionIndex, ""); } @@ -193,7 +206,9 @@ export function QuestionDate({ value={calculatedAge !== null ? calculatedAge : ""} className={[ "h-[54px] w-full rounded-[15px] border px-4 group-12 font-medium outline-none cursor-not-allowed disabled:bg-[#F5F2F1] disabled:text-[#7C7472]", - isUnder18 ? "border-[#F2465F] text-[#F2465F]" : "border-[#E7D8D5] text-[#7C7472]", + isUnder18 + ? "border-[#F2465F] text-[#F2465F]" + : "border-[#E7D8D5] text-[#7C7472]", ].join(" ")} /> {isUnder18 ? ( diff --git a/src/components/questions/question-dropdown.tsx b/src/components/questions/question-dropdown.tsx index 6de1ad0..ead5f14 100644 --- a/src/components/questions/question-dropdown.tsx +++ b/src/components/questions/question-dropdown.tsx @@ -1,7 +1,11 @@ "use client"; import { useCallback, useEffect, useRef, useState } from "react"; +import { getCountryList } from "@/data/countries"; +import { getLanguageList } from "@/data/languages"; +import { getNationalityList } from "@/data/nationalities"; import type { QuestionField } from "@/data/question-data"; +import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; @@ -16,6 +20,7 @@ export function QuestionDropdown({ questionIndex, disabled, }: QuestionDropdownProps) { + const { locale } = useI18n(); const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); const rawValue = getAnswerValue(question, questionIndex); @@ -31,6 +36,7 @@ export function QuestionDropdown({ const [searchQuery, setSearchQuery] = useState(""); const containerRef = useRef(null); const listRef = useRef(null); + const searchInputRef = useRef(null); // Lock page scroll when dropdown is open useEffect(() => { @@ -81,7 +87,43 @@ export function QuestionDropdown({ }; }, []); - const options = question.extras.options || []; + useEffect(() => { + if (isOpen) { + const timer = setTimeout(() => { + searchInputRef.current?.focus(); + }, 50); + return () => clearTimeout(timer); + } + }, [isOpen]); + + let options = question.extras.options || []; + const isNationalityDropdown = + question.title === "Current Nationality / Citizenship" || + question.title === "ملیت / تابعیت فعلی"; + + const isCountryDropdown = + !isNationalityDropdown && + (options.includes("United States") || + options.includes("ایالات متحده آمریکا") || + options.includes("Iran") || + options.includes("ایران")); + + if (isNationalityDropdown) { + options = getNationalityList(locale); + } else if (isCountryDropdown) { + options = getCountryList(locale); + } + + const isLanguageDropdown = + options.includes("Persian") || + options.includes("فارسی") || + options.includes("English") || + options.includes("انگلیسی"); + + if (isLanguageDropdown) { + options = getLanguageList(locale); + } + const filteredOptions = options.filter((option) => option.toLowerCase().includes(searchQuery.toLowerCase()), ); @@ -92,7 +134,9 @@ export function QuestionDropdown({ : question.extras.placeHolder || "Select" : singleValue || question.extras.placeHolder || "Select"; - const hasSelectedValue = isMulti ? selectedList.length > 0 : Boolean(singleValue); + const hasSelectedValue = isMulti + ? selectedList.length > 0 + : Boolean(singleValue); const toggleMultiOption = (option: string) => { let nextValue: string[]; @@ -101,7 +145,11 @@ export function QuestionDropdown({ } else { nextValue = [...selectedList, option]; } - setAnswerValue(question, questionIndex, nextValue.length > 0 ? nextValue : null); + setAnswerValue( + question, + questionIndex, + nextValue.length > 0 ? nextValue : null, + ); }; return ( @@ -121,7 +169,9 @@ export function QuestionDropdown({ onClick={() => setIsOpen(!isOpen)} className={[ "flex h-[54px] w-full items-center justify-between rounded-[16px] border bg-white px-4.5 text-start transition-all cursor-pointer outline-none", - isOpen ? "border-[#6F6F6F] ring-1 ring-[#6F6F6F]" : "border-[#D0D5DD] hover:border-[#98A2B3]", + isOpen + ? "border-[#6F6F6F] ring-1 ring-[#6F6F6F]" + : "border-[#D0D5DD] hover:border-[#98A2B3]", ].join(" ")} > setSearchQuery(e.target.value)} @@ -255,7 +309,9 @@ export function QuestionDropdown({ ); }) ) : ( - No options found + + No options found + )}
@@ -265,4 +321,3 @@ export function QuestionDropdown({ } export default QuestionDropdown; - diff --git a/src/components/questions/question-exit-navigation-button.tsx b/src/components/questions/question-exit-navigation-button.tsx index 00f3d23..8a27d74 100644 --- a/src/components/questions/question-exit-navigation-button.tsx +++ b/src/components/questions/question-exit-navigation-button.tsx @@ -5,9 +5,9 @@ import { useState } from "react"; import NavigationButton, { type NavigationButtonProps, } from "@/components/ui/navigation-button"; -import { useQuestionAnswers } from "./question-answer-storage"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; +import { useQuestionAnswers } from "./question-answer-storage"; export type QuestionExitNavigationButtonProps = NavigationButtonProps & { exitHref?: string; diff --git a/src/components/questions/question-file.tsx b/src/components/questions/question-file.tsx index 5580387..986896d 100644 --- a/src/components/questions/question-file.tsx +++ b/src/components/questions/question-file.tsx @@ -38,8 +38,14 @@ function resolveMediaType( return "file"; } -function isImageFile(fileName?: string | null, fileUrl?: string | null): boolean { - if (fileUrl && (fileUrl.startsWith("data:image/") || fileUrl.startsWith("blob:"))) { +function isImageFile( + fileName?: string | null, + fileUrl?: string | null, +): boolean { + if ( + fileUrl && + (fileUrl.startsWith("data:image/") || fileUrl.startsWith("blob:")) + ) { if (fileUrl.startsWith("data:application/pdf")) return false; if (fileName && /\.(pdf|doc|docx|xls|xlsx|txt|zip|rar)$/i.test(fileName)) { return false; @@ -60,7 +66,7 @@ export function QuestionFile({ const initialFileName = typeof storedValue === "string" && storedValue.trim().length > 0 - ? storedValue.split("/").pop() ?? storedValue + ? (storedValue.split("/").pop() ?? storedValue) : null; const initialFileUrl = @@ -171,7 +177,8 @@ export function QuestionFile({ fieldName: "file", allowedExtensions: extensions, maxBytes: 10_485_760, // 10 MB - title: typeof question.title === "string" ? question.title : "Upload File", + title: + typeof question.title === "string" ? question.title : "Upload File", }); }, [question]); @@ -354,6 +361,3 @@ export function QuestionFile({ } export default QuestionFile; - - - diff --git a/src/components/questions/question-number.tsx b/src/components/questions/question-number.tsx index 6725e2b..9e10fd8 100644 --- a/src/components/questions/question-number.tsx +++ b/src/components/questions/question-number.tsx @@ -1,10 +1,10 @@ "use client"; -import { useMemo, useEffect } from "react"; +import { useEffect, useMemo } from "react"; import type { QuestionField } from "@/data/question-data"; +import { useI18n } from "@/translations/provider"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; -import { useI18n } from "@/translations/provider"; type QuestionNumberProps = { question: QuestionField; @@ -26,7 +26,7 @@ export default function QuestionNumber({ const { dictionary: t } = useI18n(); const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); const value = getAnswerValue(question, questionIndex); - + const derivedValue = derivedFromQuestion && derivedFromQuestionIndex !== undefined ? getAnswerValue(derivedFromQuestion, derivedFromQuestionIndex) @@ -39,7 +39,14 @@ export default function QuestionNumber({ setAnswerValue(question, questionIndex, age); } } - }, [derivedFromQuestion, derivedValue, question, questionIndex, setAnswerValue, value]); + }, [ + derivedFromQuestion, + derivedValue, + question, + questionIndex, + setAnswerValue, + value, + ]); useEffect(() => { if ( @@ -52,8 +59,13 @@ export default function QuestionNumber({ }, [question, questionIndex, setAnswerValue, value]); const [min, max] = question.extras.range; - - const numValue = typeof value === "number" ? value : (typeof value === "string" ? parseFloat(value) : NaN); + + const numValue = + typeof value === "number" + ? value + : typeof value === "string" + ? parseFloat(value) + : NaN; const isOutOfRange = useMemo(() => { if (Number.isNaN(numValue)) return false; if (min !== 0 && numValue < min) return true; @@ -93,7 +105,11 @@ export default function QuestionNumber({ setAnswerValue(question, questionIndex, null); } else { const parsed = parseFloat(nextValue); - setAnswerValue(question, questionIndex, Number.isNaN(parsed) ? nextValue : parsed); + setAnswerValue( + question, + questionIndex, + Number.isNaN(parsed) ? nextValue : parsed, + ); } }} className={[ @@ -103,7 +119,8 @@ export default function QuestionNumber({ /> {isOutOfRange ? ( - {t.common.rangeError || `Please enter a value between ${min} and ${max}`} + {t.common.rangeError || + `Please enter a value between ${min} and ${max}`} ) : null} diff --git a/src/components/questions/question-phone.tsx b/src/components/questions/question-phone.tsx index bfcc350..8392863 100644 --- a/src/components/questions/question-phone.tsx +++ b/src/components/questions/question-phone.tsx @@ -1,11 +1,12 @@ "use client"; -import { useEffect, useRef, useState } from "react"; import { PhoneNumberFormat, PhoneNumberUtil } from "google-libphonenumber"; +import { useEffect, useRef, useState, useMemo, useCallback } from "react"; import type { QuestionField } from "@/data/question-data"; import type { MarriagePhoneFieldValue } from "@/hooks/marriage/types"; import { useQuestionAnswers } from "./question-answer-storage"; import QuestionTitle from "./question-title"; +import { useI18n } from "@/translations/provider"; type QuestionPhoneProps = { question: QuestionField; @@ -39,7 +40,7 @@ function isMarriagePhoneFieldValue( function readPhoneValue(value: unknown, fallbackCode: string): PhoneValueParts { if (value === null) { return { - codeValue: "", + codeValue: fallbackCode, phoneValue: "", }; } @@ -62,7 +63,7 @@ function readPhoneValue(value: unknown, fallbackCode: string): PhoneValueParts { if (value.length === 0) { return { - codeValue: "", + codeValue: fallbackCode, phoneValue: "", }; } @@ -100,6 +101,34 @@ function readPhoneValue(value: unknown, fallbackCode: string): PhoneValueParts { }; } +function getMaxLengthForCountry(codeValue: string): number { + try { + const cleanCode = codeValue.replace(/[^\d]/g, ""); + if (!cleanCode) return 15; + const countryCode = Number(cleanCode); + const regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode); + if (!regionCode || regionCode === "ZZ") return 15; + + const exampleMobile = phoneUtil.getExampleNumberForType( + regionCode, + 1, // MOBILE + ); + const exampleGeneral = phoneUtil.getExampleNumber(regionCode); + + const lenMobile = exampleMobile + ? String(exampleMobile.getNationalNumber()).length + : 0; + const lenGeneral = exampleGeneral + ? String(exampleGeneral.getNationalNumber()).length + : 0; + const baseLen = Math.max(lenMobile, lenGeneral, 8); + + return baseLen + 1; + } catch { + return 15; + } +} + function writePhoneValue(codeValue: string, phoneValue: string) { if (!codeValue && !phoneValue) { return null; @@ -120,7 +149,10 @@ function toStoredPhoneValue( codeValue: string, phoneValue: string, ): MarriagePhoneFieldValue | null { - const normalizedCountryCode = sanitizeCountryCode(codeValue).replace(/^\+/, ""); + const normalizedCountryCode = sanitizeCountryCode(codeValue).replace( + /^\+/, + "", + ); const normalizedPhoneNumber = phoneValue.trim().replace(/\s+/g, ""); if (!normalizedCountryCode && !normalizedPhoneNumber) { @@ -195,6 +227,7 @@ export function QuestionPhone({ countryCode = "+98", disabled, }: QuestionPhoneProps) { + const { locale } = useI18n(); const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); const value = getAnswerValue(question, questionIndex); const defaultCodeValue = countryCode.trim() || "+98"; @@ -202,6 +235,14 @@ export function QuestionPhone({ const [codeValue, setCodeValue] = useState(initialValue.codeValue); const [phoneValue, setPhoneValue] = useState(initialValue.phoneValue); const lastCommittedValueRef = useRef(value); + const hasFetchedIpRef = useRef(false); + + const [isOpen, setIsOpen] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); + const containerRef = useRef(null); + const listRef = useRef(null); + const searchInputRef = useRef(null); + const normalizedPhoneState = getNormalizedPhoneValue(codeValue, phoneValue); const showInvalidState = codeValue.trim().length > 0 && @@ -212,18 +253,164 @@ export function QuestionPhone({ ? normalizedPhoneState.isValid || phoneValue.trim().length === 0 : normalizedPhoneState.isValid; + const countryList = useMemo(() => { + const regions = phoneUtil.getSupportedRegions(); + const displayNames = new Intl.DisplayNames([locale || "en"], { + type: "region", + }); + const list: { name: string; code: string; flag: string }[] = []; + const seen = new Set(); + + for (const region of regions) { + try { + const callingCode = phoneUtil.getCountryCodeForRegion(region); + if (!callingCode) continue; + + let name = displayNames.of(region); + if (!name) continue; + + if (region === "US") + name = locale === "fa" ? "ایالات متحده آمریکا" : "United States"; + if (region === "GB") + name = locale === "fa" ? "بریتانیا" : "United Kingdom"; + + const key = `${name}_+${callingCode}`; + if (seen.has(key)) continue; + seen.add(key); + + const codePoints = region + .toUpperCase() + .split("") + .map((char) => 127397 + char.charCodeAt(0)); + const flag = String.fromCodePoint(...codePoints); + + list.push({ + name, + code: `+${callingCode}`, + flag, + }); + } catch (e) {} + } + + return list.sort((a, b) => a.name.localeCompare(b.name)); + }, [locale]); + + const activeFlag = useMemo(() => { + if (!codeValue) return "🏳️"; + const cleanActiveCode = codeValue.replace(/[^\d]/g, ""); + const match = countryList.find( + (c) => c.code.replace(/[^\d]/g, "") === cleanActiveCode, + ); + return match ? match.flag : "🏳️"; + }, [codeValue, countryList]); + + const filteredCountries = useMemo(() => { + const q = searchQuery.toLowerCase().trim(); + if (!q) return countryList; + return countryList.filter( + (c) => + c.name.toLowerCase().includes(q) || c.code.toLowerCase().includes(q), + ); + }, [countryList, searchQuery]); + + // Lock page scroll when dropdown is open + useEffect(() => { + if (isOpen) { + document.body.classList.add("dropdown-open"); + document.body.style.overflow = "hidden"; + document.documentElement.style.overflow = "hidden"; + } else { + document.body.classList.remove("dropdown-open"); + document.body.style.overflow = ""; + document.documentElement.style.overflow = ""; + } + return () => { + document.body.classList.remove("dropdown-open"); + document.body.style.overflow = ""; + document.documentElement.style.overflow = ""; + }; + }, [isOpen]); + + useEffect(() => { + if (isOpen) { + const timer = setTimeout(() => { + searchInputRef.current?.focus(); + }, 50); + return () => clearTimeout(timer); + } + }, [isOpen]); + + // Close dropdown on click outside + useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + setIsOpen(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); + useEffect(() => { if (value === lastCommittedValueRef.current) { return; } const nextValue = readPhoneValue(value, defaultCodeValue); + const maxLen = getMaxLengthForCountry(nextValue.codeValue); + const truncatedPhone = nextValue.phoneValue.slice(0, maxLen); setCodeValue(nextValue.codeValue); - setPhoneValue(nextValue.phoneValue); + setPhoneValue(truncatedPhone); lastCommittedValueRef.current = value; }, [defaultCodeValue, value]); + useEffect(() => { + if (hasFetchedIpRef.current) return; + const alreadyChecked = + typeof window !== "undefined" + ? localStorage.getItem("hasCheckedGeoIPPhone") + : "true"; + if (alreadyChecked) return; + + if (!value) { + hasFetchedIpRef.current = true; + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPPhone", "true"); + } + fetch("https://ipapi.co/json/") + .then((res) => res.json()) + .then((data) => { + if (data && data.country_calling_code) { + const ipCode = data.country_calling_code.startsWith("+") + ? data.country_calling_code + : `+${data.country_calling_code}`; + setCodeValue(ipCode); + updateStoredValue(ipCode, phoneValue); + } + }) + .catch(() => { + fetch("https://ipwho.is/") + .then((res) => res.json()) + .then((data) => { + if (data && data.calling_code) { + const ipCode = data.calling_code.startsWith("+") + ? data.calling_code + : `+${data.calling_code}`; + setCodeValue(ipCode); + updateStoredValue(ipCode, phoneValue); + } + }) + .catch(() => {}); + }); + } + }, []); + const updateStoredValue = (nextCodeValue: string, nextPhoneValue: string) => { const draftValue = writePhoneValue(nextCodeValue, nextPhoneValue); const nextPhoneState = getNormalizedPhoneValue( @@ -241,12 +428,27 @@ export function QuestionPhone({ setAnswerValue(question, questionIndex, nextValue); }; + const handleSelectCountryCode = (selectedCode: string) => { + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPPhone", "true"); + } + const maxLen = getMaxLengthForCountry(selectedCode); + const truncatedPhone = phoneValue.slice(0, maxLen); + + setCodeValue(selectedCode); + setPhoneValue(truncatedPhone); + updateStoredValue(selectedCode, truncatedPhone); + setIsOpen(false); + setSearchQuery(""); + }; + return (
@@ -259,23 +461,34 @@ export function QuestionPhone({ ].join(" ")} >
- { - const nextCodeValue = sanitizeCountryCode(event.target.value); - - setCodeValue(nextCodeValue); - updateStoredValue(nextCodeValue, phoneValue); - }} - className="w-[33px] border-0 bg-transparent p-0 text-left group-12 leading-none text-[#181818] tabular-nums outline-none placeholder:text-[#9D8F8C]" - /> -
{ + if (typeof window !== "undefined") { + localStorage.setItem("hasCheckedGeoIPPhone", "true"); + } const nextPhoneValue = sanitizePhoneNumber(event.target.value); + const maxLen = getMaxLengthForCountry(codeValue); + const truncatedPhone = nextPhoneValue.slice(0, maxLen); - setPhoneValue(nextPhoneValue); - updateStoredValue(codeValue, nextPhoneValue); + setPhoneValue(truncatedPhone); + updateStoredValue(codeValue, truncatedPhone); }} dir="ltr" className="h-full w-full border-0 bg-transparent p-0 text-left group-12 leading-none text-[#181818] tabular-nums outline-none placeholder:text-[#9D8F8C]" @@ -300,6 +519,91 @@ export function QuestionPhone({ Enter a valid phone number with country code. ) : null} + + {/* Dropdown Options Panel */} + {isOpen && ( +
+ {/* Search Input Bar */} +
+ + + + + setSearchQuery(e.target.value)} + placeholder={ + locale === "fa" + ? "جستجوی کشور یا پیش‌شماره..." + : "Search country or dial code..." + } + className="flex-1 bg-transparent text-[14px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" + /> + {searchQuery ? ( + + ) : null} +
+ + {/* Country List */} +
+ {filteredCountries.length > 0 ? ( + filteredCountries.map((c) => { + return ( + + ); + }) + ) : ( + + {locale === "fa" ? "موردی یافت نشد" : "No options found"} + + )} +
+
+ )}
); } diff --git a/src/components/questions/question-photo.tsx b/src/components/questions/question-photo.tsx index aba427b..ce8717a 100644 --- a/src/components/questions/question-photo.tsx +++ b/src/components/questions/question-photo.tsx @@ -1,7 +1,7 @@ "use client"; import Image from "next/image"; -import { useCallback, useEffect, useId, useState, type ReactNode } from "react"; +import { type ReactNode, useCallback, useEffect, useId, useState } from "react"; import type { QuestionField } from "@/data/question-data"; import { useUploadTmpMediaMutation } from "@/hooks/marriage/use-upload-tmp-media"; import { getApiRequestUrl } from "@/lib/http"; @@ -110,9 +110,11 @@ export function QuestionPhoto({ returnAs: "upload", uploadUrl: `${process.env.NEXT_PUBLIC_API_BASE_URL ?? ""}/upload-tmp-media/`, fieldName: "file", - allowedExtensions: extensions.length > 0 ? extensions : ["jpg", "jpeg", "png", "webp"], + allowedExtensions: + extensions.length > 0 ? extensions : ["jpg", "jpeg", "png", "webp"], maxBytes: 10_485_760, // 10 MB - title: typeof question.title === "string" ? question.title : "Upload Photo", + title: + typeof question.title === "string" ? question.title : "Upload Photo", }); }, [question]); @@ -139,7 +141,11 @@ export function QuestionPhoto({ // Determine photo URL to display let displayUrl: string | null = localPreviewUrl; - if (!displayUrl && typeof storedValue === "string" && storedValue.trim().length > 0) { + if ( + !displayUrl && + typeof storedValue === "string" && + storedValue.trim().length > 0 + ) { const val = storedValue.trim(); if ( val.startsWith("http://") || @@ -163,7 +169,10 @@ export function QuestionPhoto({ disabled ? "pointer-events-none opacity-30" : "", ].join(" ")} > - + -
+
- + {children} diff --git a/src/components/questions/question-slider.tsx b/src/components/questions/question-slider.tsx index 8a1cb6f..66cc764 100644 --- a/src/components/questions/question-slider.tsx +++ b/src/components/questions/question-slider.tsx @@ -89,7 +89,13 @@ export function QuestionSlider({ max={max} step={1} value={value} - onChange={(event) => setAnswerValue(question, questionIndex, Number(event.target.value))} + onChange={(event) => + setAnswerValue( + question, + questionIndex, + Number(event.target.value), + ) + } disabled={disabled} className="question-slider-range w-full" style={{ diff --git a/src/components/questions/question-snap-list.tsx b/src/components/questions/question-snap-list.tsx index da2e68f..891b8a2 100644 --- a/src/components/questions/question-snap-list.tsx +++ b/src/components/questions/question-snap-list.tsx @@ -117,7 +117,8 @@ export function QuestionSnapList({ const isDisabled = questionElement.getAttribute("data-question-disabled") === "true" || - questionElement.querySelector("[data-question-disabled='true']") !== null; + questionElement.querySelector("[data-question-disabled='true']") !== + null; if (isDisabled) { continue; @@ -190,9 +191,10 @@ export function QuestionSnapList({ return; } - const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( - navigator.userAgent - ); + const isMobile = + /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( + navigator.userAgent, + ); firstFocusableInput.focus({ preventScroll: !isMobile }); @@ -331,16 +333,24 @@ export function QuestionSnapList({ let wrapperStyles = "w-full"; if (isActive) { - containerStyles = "top-[35%] left-0 -translate-y-1/2 z-10 opacity-100 scale-100 pointer-events-auto"; + containerStyles = + "top-0 left-0 bottom-0 z-10 opacity-100 scale-100 pointer-events-auto !justify-start"; + wrapperStyles = "w-full my-auto shrink-0"; } else if (isPrev) { - containerStyles = "top-4 left-0 z-0 opacity-0 pointer-events-none scale-[0.98]"; - wrapperStyles = "w-full max-h-[110px] overflow-hidden pointer-events-none"; + containerStyles = + "top-4 left-0 z-0 opacity-0 pointer-events-none scale-[0.98]"; + wrapperStyles = + "w-full max-h-[110px] overflow-hidden pointer-events-none"; } else if (isNext) { - containerStyles = "bottom-4 left-0 z-0 opacity-0 pointer-events-none scale-[0.98]"; - wrapperStyles = "w-full max-h-[110px] overflow-hidden pointer-events-none"; + containerStyles = + "bottom-4 left-0 z-0 opacity-0 pointer-events-none scale-[0.98]"; + wrapperStyles = + "w-full max-h-[110px] overflow-hidden pointer-events-none"; } else { - containerStyles = "top-1/2 left-0 -translate-y-1/2 z-0 opacity-0 pointer-events-none scale-[0.95]"; - wrapperStyles = "w-full max-h-[110px] overflow-hidden pointer-events-none"; + containerStyles = + "top-1/2 left-0 -translate-y-1/2 z-0 opacity-0 pointer-events-none scale-[0.95]"; + wrapperStyles = + "w-full max-h-[110px] overflow-hidden pointer-events-none"; } return ( @@ -357,9 +367,10 @@ export function QuestionSnapList({ containerStyles, ].join(" ")} > -
- {question} -
+
{question}
+ {isActive && ( + ); })} diff --git a/src/components/questions/question-text.tsx b/src/components/questions/question-text.tsx index 7328c2c..f593b60 100644 --- a/src/components/questions/question-text.tsx +++ b/src/components/questions/question-text.tsx @@ -29,7 +29,8 @@ export default function QuestionText({ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const isValidEmail = !isEmailQuestion || emailRegex.test(stringValue); - const showInvalidState = isEmailQuestion && stringValue.length > 0 && !isValidEmail; + const showInvalidState = + isEmailQuestion && stringValue.length > 0 && !isValidEmail; const isAnswered = question.required === false ? isValidEmail || stringValue.length === 0 @@ -56,7 +57,9 @@ export default function QuestionText({ setAnswerValue(question, questionIndex, e.target.value)} + onChange={(e) => + setAnswerValue(question, questionIndex, e.target.value) + } placeholder={question.extras.placeHolder} disabled={disabled} className="h-full w-full border-0 bg-transparent px-[18px] group-12 leading-none text-[#181818] outline-none placeholder:text-[#9D8F8C]" @@ -91,7 +94,9 @@ export default function QuestionText({ setAnswerValue(question, questionIndex, e.target.value)} + onChange={(e) => + setAnswerValue(question, questionIndex, e.target.value) + } placeholder={question.extras.placeHolder} disabled={disabled} className="h-[54px] w-full rounded-[15px] border border-[#E7D8D5] bg-white px-4 group-12 font-medium text-[#181818] outline-none transition-all placeholder:text-[#9D8F8C] focus:border-[#6F6F6F] disabled:bg-[#F5F2F1] disabled:text-[#7C7472]" diff --git a/src/components/questions/question-title.tsx b/src/components/questions/question-title.tsx index 085f812..c01e20f 100644 --- a/src/components/questions/question-title.tsx +++ b/src/components/questions/question-title.tsx @@ -2,9 +2,9 @@ import { useState } from "react"; import { IoEyeOff } from "react-icons/io5"; +import HelpModal from "@/components/ui/help-modal"; import type { QuestionField } from "@/data/question-data"; import { useI18n } from "@/translations/provider"; -import HelpModal from "@/components/ui/help-modal"; type QuestionTitleProps = { question: QuestionField; @@ -24,8 +24,7 @@ export function QuestionTitle({ question, className }: QuestionTitleProps) { className="shrink-0 text-[18px] text-[#D9383A]" /> - {t.questions.privateFieldNotice ?? - "Private Field (Visible to Habib Marriage advisors only)"} + {t.questions.privateFieldNotice ?? "Private (Advisors Only)"} ) : null} @@ -38,10 +37,12 @@ export function QuestionTitle({ question, className }: QuestionTitleProps) { .filter(Boolean) .join(" ")} > - {question.title} - {question.required ? ( - * - ) : null} + + {question.title} + {question.required ? ( + * + ) : null} + {question.description ? ( ({question.description}) diff --git a/src/components/questions/required-steps-card.tsx b/src/components/questions/required-steps-card.tsx index 4fc583b..34ee6c7 100644 --- a/src/components/questions/required-steps-card.tsx +++ b/src/components/questions/required-steps-card.tsx @@ -1,17 +1,20 @@ "use client"; +import { useMemo } from "react"; import { IoAlert, IoCheckmark } from "react-icons/io5"; +import { + getLocalSectionProgress, + getStoredAge, +} from "@/components/questions/progress-helper"; import { getQuestionListItems, isQuestionListItemVisibleForProfile, type QuestionListItem, } from "@/data/question-data"; +import { toFrontendSlug } from "@/data/section-slug-map"; import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; import { useMarriageSectionsQuery } from "@/hooks/marriage/use-sections"; import { useI18n } from "@/translations/provider"; -import { useMemo } from "react"; -import { toFrontendSlug } from "@/data/section-slug-map"; -import { getStoredAge, getLocalSectionProgress } from "@/components/questions/progress-helper"; type RequiredStepsCardProps = { items?: QuestionListItem[]; @@ -69,10 +72,16 @@ export default function RequiredStepsCard({ let progress = 0; if (localProgress !== null) { progress = localProgress; - } else if (progressBySlug && typeof progressBySlug.get(item.slug) === "number") { + } else if ( + progressBySlug && + typeof progressBySlug.get(item.slug) === "number" + ) { progress = progressBySlug.get(item.slug)!; } else if (section) { - progress = Math.max(0, Math.min(100, Math.round(section.completion_percent))); + progress = Math.max( + 0, + Math.min(100, Math.round(section.completion_percent)), + ); } else { progress = item.progress; } diff --git a/src/components/questions/test-loading-screen.tsx b/src/components/questions/test-loading-screen.tsx index 0e45854..ea356ec 100644 --- a/src/components/questions/test-loading-screen.tsx +++ b/src/components/questions/test-loading-screen.tsx @@ -3,7 +3,11 @@ import { DotsLoader } from "@/components/ui/button"; import { PageBackground } from "@/components/utils/page-background"; -export function AnalyzingIllustration({ className = "w-44 h-44" }: { className?: string }) { +export function AnalyzingIllustration({ + className = "w-44 h-44", +}: { + className?: string; +}) { return ( {/* Small text lines in header */} - - + + {/* Donut chart in header */} - + {/* Bar chart bars */} diff --git a/src/components/questions/test-questions-flow.tsx b/src/components/questions/test-questions-flow.tsx index 7b8998f..e4fc45b 100644 --- a/src/components/questions/test-questions-flow.tsx +++ b/src/components/questions/test-questions-flow.tsx @@ -1,13 +1,13 @@ "use client"; +import { useRouter } from "next/navigation"; import { useState } from "react"; import { GoArrowLeft, GoCheck } from "react-icons/go"; import { IoInformation } from "react-icons/io5"; +import Button from "@/components/ui/button"; import NavigationButton from "@/components/ui/navigation-button"; import StickyHeader from "@/components/ui/sticky-header"; import { PageBackground } from "@/components/utils/page-background"; -import Button from "@/components/ui/button"; -import { useRouter } from "next/navigation"; import TestLoadingScreen from "./test-loading-screen"; export type QuestionOption = { @@ -53,7 +53,9 @@ export default function TestQuestionsFlow({ const currentQuestion = questions[currentIndex] ?? questions[0]; const totalQuestions = questions.length; const isLastQuestion = currentIndex === totalQuestions - 1; - const selectedValue = currentQuestion ? answers[currentQuestion.id] : undefined; + const selectedValue = currentQuestion + ? answers[currentQuestion.id] + : undefined; const handleOptionSelect = (value: string | number) => { if (!currentQuestion) return; @@ -185,11 +187,15 @@ export default function TestQuestionsFlow({ : "border-2 border-[#C5C5C8] bg-transparent" }`} > - {isSelected ? : null} + {isSelected ? ( + + ) : null}
{/* Option Text */} - + {option.label} diff --git a/src/components/sliders/slider-page.tsx b/src/components/sliders/slider-page.tsx index a4fedf4..d2ed6e1 100644 --- a/src/components/sliders/slider-page.tsx +++ b/src/components/sliders/slider-page.tsx @@ -182,7 +182,7 @@ export default function SliderPage() {
-
diff --git a/src/components/sliders/slider-slide-four.tsx b/src/components/sliders/slider-slide-four.tsx index d0641fd..2655603 100644 --- a/src/components/sliders/slider-slide-four.tsx +++ b/src/components/sliders/slider-slide-four.tsx @@ -27,7 +27,9 @@ export function SliderSlideFour({ >
-

Submit Process

+

+ Submit Process +

{index + 1}/4 Registration Type

@@ -82,9 +84,7 @@ export function SliderSlideFour({ /> - - {option.label} - + {option.label} ); })} diff --git a/src/components/sliders/slider-slide-one.tsx b/src/components/sliders/slider-slide-one.tsx index b996ebe..c9bf7f9 100644 --- a/src/components/sliders/slider-slide-one.tsx +++ b/src/components/sliders/slider-slide-one.tsx @@ -19,7 +19,9 @@ export function SliderSlideOne({ index }: SliderSlideProps) { }} >
-

Submit Process

+

+ Submit Process +

{index + 1}/4 terms & conditions

@@ -48,7 +50,9 @@ export function SliderSlideOne({ index }: SliderSlideProps) {

- Identity Verification:{" "} + + Identity Verification: + {" "} Mandatory submission of valid government-issued ID upon registration. @@ -56,7 +60,9 @@ export function SliderSlideOne({ index }: SliderSlideProps) {

- Single Status Commitment:{" "} + + Single Status Commitment: + {" "} Users must provide proof of being single, or documents confirming divorce or spouse's death upon request. @@ -72,7 +78,9 @@ export function SliderSlideOne({ index }: SliderSlideProps) {

- General Health:{" "} + + General Health: + {" "} Self-declaration regarding mental health, absence of addiction, and no criminal record. @@ -86,7 +94,9 @@ export function SliderSlideOne({ index }: SliderSlideProps) {

- Content Security:{" "} + + Content Security: + {" "} Technical prevention of screenshots from profiles and chat environments. @@ -94,7 +104,9 @@ export function SliderSlideOne({ index }: SliderSlideProps) {

- Progressive Disclosure:{" "} + + Progressive Disclosure: + {" "} Sensitive information (face, contact details) revealed step-by-step only with mutual consent. diff --git a/src/components/sliders/slider-slide-two.tsx b/src/components/sliders/slider-slide-two.tsx index d4956d4..4809bbe 100644 --- a/src/components/sliders/slider-slide-two.tsx +++ b/src/components/sliders/slider-slide-two.tsx @@ -9,7 +9,9 @@ export function SliderSlideTwo({ index }: SliderSlideProps) { >

-

Submit Process

+

+ Submit Process +

{index + 1}/4 Watch Video

diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 440d615..69122e0 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -30,7 +30,9 @@ export type ButtonProps = Omit< export function DotsLoader({ className = "" }: { className?: string }) { return ( - + diff --git a/src/components/ui/female-consent-sheet.tsx b/src/components/ui/female-consent-sheet.tsx index d7b4640..843cf9b 100644 --- a/src/components/ui/female-consent-sheet.tsx +++ b/src/components/ui/female-consent-sheet.tsx @@ -1,9 +1,9 @@ "use client"; +import Image from "next/image"; import type { HTMLAttributes, ReactNode } from "react"; import { useEffect, useState } from "react"; import { useI18n } from "@/translations/provider"; -import Image from "next/image"; const EXIT_ANIMATION_MS = 220; @@ -140,7 +140,12 @@ export function FemaleConsentSheet({ aria-label="Close" className="items-center justify-center rounded-full text-[#A0A0A0]" > - close + close
diff --git a/src/components/ui/help-modal.tsx b/src/components/ui/help-modal.tsx index 63b7fb5..db20834 100644 --- a/src/components/ui/help-modal.tsx +++ b/src/components/ui/help-modal.tsx @@ -38,8 +38,7 @@ export function HelpModal({ description ?? (t.common as any)?.helpDescription ?? "Psychologically, this practice fosters a sense of empathy and contentment, which can reduce financial stress. Socially, lending strengthens neighborhood bonds and creates support networks that can lead to economic opportunities. This hadith encourages believers to lend dough, bread, and fire to increase their sustenance."; - const resolvedButtonText = - buttonText ?? (t.common as any)?.gotIt ?? "Got it"; + const resolvedButtonText = buttonText ?? (t.common as any)?.gotIt ?? "Got it"; const closeSheet = useCallback(() => { if (isClosing) return; @@ -128,10 +127,11 @@ export function HelpModal({ {(() => { const items = Array.isArray(resolvedDescription) ? resolvedDescription - : typeof resolvedDescription === "string" + : typeof resolvedDescription === "string" && + resolvedDescription.includes("\n") ? resolvedDescription - .split(/\.\s+/) - .map((s) => s.replace(/\.$/, "").trim()) + .split(/\r?\n/) + .map((s) => s.trim()) .filter(Boolean) : null; @@ -156,10 +156,7 @@ export function HelpModal({ })()}
-
diff --git a/src/components/ui/navigation-button.tsx b/src/components/ui/navigation-button.tsx index 534dc40..dbe9a91 100644 --- a/src/components/ui/navigation-button.tsx +++ b/src/components/ui/navigation-button.tsx @@ -5,8 +5,8 @@ import { useRouter } from "next/navigation"; import type { ButtonHTMLAttributes, ReactNode } from "react"; import { useState } from "react"; import { GoArrowLeft } from "react-icons/go"; -import { useI18n } from "@/translations/provider"; import HelpModal from "@/components/ui/help-modal"; +import { useI18n } from "@/translations/provider"; type NavigationButtonIcon = | "back" @@ -113,7 +113,9 @@ export function NavigationButton({ const resolvedHelpDescription = helpDescription ?? - (icon === "document" ? (t.questions as any)?.testIntroDisclaimer : undefined); + (icon === "document" + ? (t.questions as any)?.testIntroDisclaimer + : undefined); return ( <> @@ -131,7 +133,7 @@ export function NavigationButton({ if (icon === "back") { if (typeof window !== "undefined" && (window as any).HabibApp) { (window as any).HabibApp.postMessage( - JSON.stringify({ action: "close_service" }) + JSON.stringify({ action: "close_service" }), ); } else { router.back(); diff --git a/src/components/ui/report-actions-sheet.tsx b/src/components/ui/report-actions-sheet.tsx index 47b032f..aa75abd 100644 --- a/src/components/ui/report-actions-sheet.tsx +++ b/src/components/ui/report-actions-sheet.tsx @@ -4,10 +4,10 @@ import { useEffect, useState } from "react"; import Button from "@/components/ui/button"; import { useFlutterBridge } from "@/hooks/useFlutterBridge"; import { - downloadFile, copyToClipboard, - openExternalUrl, + downloadFile, isInFlutterWebView, + openExternalUrl, } from "@/lib/webview-actions"; const EXIT_ANIMATION_MS = 220; @@ -65,7 +65,9 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) { mimeType: "application/pdf", fileType: "document", }); - console.log(sent ? "📥 download_file ارسال شد" : "⚠️ Flutter WebView یافت نشد"); + console.log( + sent ? "📥 download_file ارسال شد" : "⚠️ Flutter WebView یافت نشد", + ); }; // ✅ تست copy_to_clipboard @@ -84,7 +86,9 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) { mode: "externalApplication", title: "test_open_url", }); - console.log(sent ? "🔗 open_external_url ارسال شد" : "⚠️ Flutter WebView یافت نشد"); + console.log( + sent ? "🔗 open_external_url ارسال شد" : "⚠️ Flutter WebView یافت نشد", + ); }; useEffect(() => { @@ -116,7 +120,9 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) { }, [isClosing, onClose]); useEffect(() => { - const handleFlutterResponse: NonNullable = (event) => { + const handleFlutterResponse: NonNullable = ( + event, + ) => { if (event.action === "get_location" && event.success && event.data) { const message = `Location: ${event.data.latitude}, ${event.data.longitude}`; alert(message); @@ -134,7 +140,9 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) { } }; - const unsubscribe = window.addFlutterResponseListener?.(handleFlutterResponse); + const unsubscribe = window.addFlutterResponseListener?.( + handleFlutterResponse, + ); return () => { unsubscribe?.(); @@ -171,7 +179,9 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) {
-

Settings & Support

+

+ Settings & Support +

- +
{/* Test WebView Actions */} @@ -206,7 +218,8 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) {
{!isInFlutterWebView() && (

- ⚠️ Outside WebView — copy_to_clipboard uses browser fallback, others require Flutter. + ⚠️ Outside WebView — copy_to_clipboard uses browser fallback, + others require Flutter.

)}
@@ -216,9 +229,7 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) {

🧪 Test Flutter Connection:

- +
{/* Last Received Event */} @@ -228,9 +239,7 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) { 📥 Last Event from Flutter:

-
- {lastEvent.type} -
+
{lastEvent.type}
{JSON.stringify(lastEvent.payload, null, 2)}
@@ -275,11 +284,9 @@ export function ReportActionsSheet({ onClose }: ReportActionsSheetProps) {

💡 راهنما: -
- • WEB_READY هنگام باز شدن این شیت به‌صورت خودکار از کانال +
• WEB_READY هنگام باز شدن این شیت به‌صورت خودکار از کانال HabibApp ارسال می‌شود -
- • نقطهٔ سبز یعنی کانال HabibApp در دسترس است +
• نقطهٔ سبز یعنی کانال HabibApp در دسترس است
• برای ارسال دستی، دکمه «ارسال WEB_READY» را بزنید

diff --git a/src/components/ui/token-switcher.tsx b/src/components/ui/token-switcher.tsx index 51b20f6..cc37dc9 100644 --- a/src/components/ui/token-switcher.tsx +++ b/src/components/ui/token-switcher.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { MdOutlineSwitchAccount } from "react-icons/md"; -import { setClientCookie, getClientCookie } from "@/lib/cookies"; +import { getClientCookie, setClientCookie } from "@/lib/cookies"; export const FEMALE_TOKEN = "545f61bb3e061ccb9b19f84715eb1b1ed4740331"; export const MALE_TOKEN = "f3a7543b44ef0a713d1ee0d4f7866b3825cf1308"; @@ -56,7 +56,7 @@ export function TokenSwitcher({ (window as any).HABIB_TOKEN = newToken; setCurrentToken(newToken); setIsOpen(false); - + // Navigate to the beginning of the flow (intro page) window.location.href = "/"; } diff --git a/src/components/utils/dev-click-to-component.tsx b/src/components/utils/dev-click-to-component.tsx index 0d798d2..114a09a 100644 --- a/src/components/utils/dev-click-to-component.tsx +++ b/src/components/utils/dev-click-to-component.tsx @@ -1 +1,4 @@ -export { DevClickToComponent, default } from "@/components/dev/dev-click-to-component"; +export { + DevClickToComponent, + default, +} from "@/components/dev/dev-click-to-component"; diff --git a/src/components/utils/fixed-bottom.tsx b/src/components/utils/fixed-bottom.tsx index 5310436..ae1a3fd 100644 --- a/src/components/utils/fixed-bottom.tsx +++ b/src/components/utils/fixed-bottom.tsx @@ -12,10 +12,7 @@ export function FixedBottom({ children, className }: FixedBottomProps) { const { bottom } = useViewPaddings(); return ( -
+
{children}
); diff --git a/src/data/cattell-fallback.ts b/src/data/cattell-fallback.ts index 4678eab..a427181 100644 --- a/src/data/cattell-fallback.ts +++ b/src/data/cattell-fallback.ts @@ -6,1686 +6,1062 @@ export type CattellFallbackQuestion = { export const cattellFallbackQuestions: CattellFallbackQuestion[] = [ { - "question_number": 1, - "text": "من حاضرم به هر سوال تا حد امکان صادقانه پاسخ دهم", - "options": [ - "بله", - "به اندازه کافی واضح نیست", - "نه" - ] - }, - { - "question_number": 2, - "text": "ترجیح میدم خونه داشته باشم", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 1, + text: "من حاضرم به هر سوال تا حد امکان صادقانه پاسخ دهم", + options: ["بله", "به اندازه کافی واضح نیست", "نه"], + }, + { + question_number: 2, + text: "ترجیح میدم خونه داشته باشم", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 3, - "text": "من می توانم انرژی لازم را برای رویارویی با مشکلاتی که با آن مواجه می شوم پیدا کنم", - "options": [ + question_number: 3, + text: "من می توانم انرژی لازم را برای رویارویی با مشکلاتی که با آن مواجه می شوم پیدا کنم", + options: [ "در محله ای قرار دارد که مردم به راحتی می توانند از یکدیگر دیدن کنند", "بین این دو", - "جدا شده در اعماق جنگل" - ] - }, - { - "question_number": 4, - "text": "من می توانم انرژی لازم را برای رویارویی با مشکلاتی که با آن مواجه می شوم پیدا کنم", - "options": [ - "همیشه", - "اغلب", - "به ندرت" - ] - }, - { - "question_number": 5, - "text": "من در مقابل حیوانات وحشی احساس ناراحتی می کنم حتی اگر آنها در قفس های امن محصور شوند", - "options": [ - "بله", - "مضطرب", - "نه" - ] - }, - { - "question_number": 6, - "text": "من از انتقاد از مردم، عقاید و نظرات آنها خودداری می کنم", - "options": [ - "درست است", - "گاهی اوقات", - "نادرست" - ] - }, - { - "question_number": 7, - "text": "من موسیقی کلاسیک را به موسیقی عامه پسند ترجیح می دهم", - "options": [ - "معمولا", - "گاهی اوقات", - "هرگز" - ] - }, - { - "question_number": 8, - "text": "من موسیقی کلاسیک را به موسیقی عامه پسند ترجیح می دهم", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] - }, - { - "question_number": 9, - "text": "اگر دیدم دو بچه همسایه در حال دعوا هستند", - "options": [ + "جدا شده در اعماق جنگل", + ], + }, + { + question_number: 4, + text: "من می توانم انرژی لازم را برای رویارویی با مشکلاتی که با آن مواجه می شوم پیدا کنم", + options: ["همیشه", "اغلب", "به ندرت"], + }, + { + question_number: 5, + text: "من در مقابل حیوانات وحشی احساس ناراحتی می کنم حتی اگر آنها در قفس های امن محصور شوند", + options: ["بله", "مضطرب", "نه"], + }, + { + question_number: 6, + text: "من از انتقاد از مردم، عقاید و نظرات آنها خودداری می کنم", + options: ["درست است", "گاهی اوقات", "نادرست"], + }, + { + question_number: 7, + text: "من موسیقی کلاسیک را به موسیقی عامه پسند ترجیح می دهم", + options: ["معمولا", "گاهی اوقات", "هرگز"], + }, + { + question_number: 8, + text: "من موسیقی کلاسیک را به موسیقی عامه پسند ترجیح می دهم", + options: ["بله", "من مطمئن نیستم", "نه"], + }, + { + question_number: 9, + text: "اگر دیدم دو بچه همسایه در حال دعوا هستند", + options: [ "من به آنها اجازه می دهم خودشان این موضوع را حل کنند", "نمی دانم چه کار کنم", - "من آنها را آشتی خواهم داد" - ] + "من آنها را آشتی خواهم داد", + ], }, { - "question_number": 10, - "text": "در جامعه", - "options": [ + question_number: 10, + text: "در جامعه", + options: [ "من سعی می کنم خود را مورد توجه قرار دهم", "بین این دو", - "ترجیح می دهم خودم را مورد توجه قرار ندهم" - ] + "ترجیح می دهم خودم را مورد توجه قرار ندهم", + ], }, { - "question_number": 11, - "text": "بودن جالب تر است", - "options": [ - "مهندس ساختمان", - "من نمی دانم", - "بازیگر نمایشی" - ] + question_number: 11, + text: "بودن جالب تر است", + options: ["مهندس ساختمان", "من نمی دانم", "بازیگر نمایشی"], }, { - "question_number": 12, - "text": "من معمولاً موفق می شوم با افراد خواستار کنار بیایم، حتی اگر آنها به خود ببالند یا خیلی از خود راضی به نظر برسند", - "options": [ - "درست است", - "من نمی دانم", - "نادرست" - ] + question_number: 12, + text: "من معمولاً موفق می شوم با افراد خواستار کنار بیایم، حتی اگر آنها به خود ببالند یا خیلی از خود راضی به نظر برسند", + options: ["درست است", "من نمی دانم", "نادرست"], }, { - "question_number": 13, - "text": "من معمولاً موفق می شوم با افراد خواستار کنار بیایم، حتی اگر آنها به خود ببالند یا خیلی از خود راضی به نظر برسند", - "options": [ - "درست است", - "کم و بیش", - "نادرست" - ] + question_number: 13, + text: "من معمولاً موفق می شوم با افراد خواستار کنار بیایم، حتی اگر آنها به خود ببالند یا خیلی از خود راضی به نظر برسند", + options: ["درست است", "کم و بیش", "نادرست"], }, { - "question_number": 14, - "text": "من تقریباً همیشه می توانم از چهره افراد بفهمم که آیا آنها نادرست هستند یا خیر", - "options": [ - "تقریبا همیشه", - "گاهی اوقات", - "هرگز" - ] + question_number: 14, + text: "من تقریباً همیشه می توانم از چهره افراد بفهمم که آیا آنها نادرست هستند یا خیر", + options: ["تقریبا همیشه", "گاهی اوقات", "هرگز"], }, { - "question_number": 15, - "text": "اگر تعطیلات (تعطیلات) طولانی تر باشد و همه موظف به گرفتن آن باشند، برای همه خوب است", - "options": [ - "موافقم", - "من مطمئن نیستم", - "من مخالفم" - ] + question_number: 15, + text: "اگر تعطیلات (تعطیلات) طولانی تر باشد و همه موظف به گرفتن آن باشند، برای همه خوب است", + options: ["موافقم", "من مطمئن نیستم", "من مخالفم"], }, { - "question_number": 16, - "text": "ترجیح می‌دهم شغلی را بپذیرم که در آن به طور نامنظم اما زیاد درآمد داشته باشم، به جای اینکه کاری را بپذیرم که در آن به طور منظم اما کم درآمد داشته باشم.", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 16, + text: "ترجیح می‌دهم شغلی را بپذیرم که در آن به طور نامنظم اما زیاد درآمد داشته باشم، به جای اینکه کاری را بپذیرم که در آن به طور منظم اما کم درآمد داشته باشم.", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 17, - "text": "من در مورد آنچه احساس می کنم صحبت می کنم", - "options": [ + question_number: 17, + text: "من در مورد آنچه احساس می کنم صحبت می کنم", + options: [ "فقط در صورت لزوم", "بین این دو", - "به ابتکار خودم هر زمان که فرصتی داشته باشم" - ] + "به ابتکار خودم هر زمان که فرصتی داشته باشم", + ], }, { - "question_number": 18, - "text": "من گاهی اوقات به دلایلی که نمی توانم توضیح دهم احساس خطر مبهم می کنم یا می ترسم", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 18, + text: "من گاهی اوقات به دلایلی که نمی توانم توضیح دهم احساس خطر مبهم می کنم یا می ترسم", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], }, { - "question_number": 19, - "text": "اگر به ناحق به خاطر عملی که مرتکب نشده ام، اما به من نسبت داده شده، مورد انتقاد قرار بگیرم", - "options": [ + question_number: 19, + text: "اگر به ناحق به خاطر عملی که مرتکب نشده ام، اما به من نسبت داده شده، مورد انتقاد قرار بگیرم", + options: [ "من اصلاً احساس گناه نمی کنم", "بین این دو", - "هنوز هم کمی احساس گناه می کنم" - ] + "هنوز هم کمی احساس گناه می کنم", + ], }, { - "question_number": 20, - "text": "با پول می توانید هر چیزی یا تقریباً هر چیزی را بدست آورید", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] + question_number: 20, + text: "با پول می توانید هر چیزی یا تقریباً هر چیزی را بدست آورید", + options: ["بله", "من مطمئن نیستم", "نه"], }, { - "question_number": 21, - "text": "تصمیمات من بیشتر دیکته می شود", - "options": [ - "احساسات", - "به همان اندازه با احساسات و عقل", - "دلیل" - ] + question_number: 21, + text: "تصمیمات من بیشتر دیکته می شود", + options: ["احساسات", "به همان اندازه با احساسات و عقل", "دلیل"], }, { - "question_number": 22, - "text": "بیشتر مردم اگر بیشتر در میان همسالان خود زندگی کنند و مانند آنها رفتار کنند، شادتر خواهند بود", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] + question_number: 22, + text: "بیشتر مردم اگر بیشتر در میان همسالان خود زندگی کنند و مانند آنها رفتار کنند، شادتر خواهند بود", + options: ["بله", "من مطمئن نیستم", "نه"], }, { - "question_number": 23, - "text": "وقتی در آینه نگاه می کنم، گاهی اوقات نمی دانم راست و چپم کجاست", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] + question_number: 23, + text: "وقتی در آینه نگاه می کنم، گاهی اوقات نمی دانم راست و چپم کجاست", + options: ["بله", "من مطمئن نیستم", "نه"], }, { - "question_number": 24, - "text": "وقتی صحبت می کنم، دوست دارم", - "options": [ + question_number: 24, + text: "وقتی صحبت می کنم، دوست دارم", + options: [ "چیزها را همانطور که به ذهنشان می رسد ارائه دهید", "بین این دو", - "از قبل ایده های سازمان یافته ای داشته باشید" - ] + "از قبل ایده های سازمان یافته ای داشته باشید", + ], }, { - "question_number": 25, - "text": "وقتی چیزی من را عصبانی می کند، خیلی سریع آرام می شوم", - "options": [ - "بله", - "بین این دو", - "نه" - ] + question_number: 25, + text: "وقتی چیزی من را عصبانی می کند، خیلی سریع آرام می شوم", + options: ["بله", "بین این دو", "نه"], }, { - "question_number": 26, - "text": "کار کردن به همان تعداد ساعت و با حقوق مساوی، بهتر است", - "options": [ - "نجار یا آشپز", - "من نمی دانم", - "گارسون در یک رستوران" - ] + question_number: 26, + text: "کار کردن به همان تعداد ساعت و با حقوق مساوی، بهتر است", + options: ["نجار یا آشپز", "من نمی دانم", "گارسون در یک رستوران"], }, { - "question_number": 27, - "text": "من تعیین شده ام برای انجام", - "options": [ - ")فقط چند عملکرد (تا 5", - "چندین عملکرد", - "تعداد زیادی توابع" - ] + question_number: 27, + text: "من تعیین شده ام برای انجام", + options: [")فقط چند عملکرد (تا 5", "چندین عملکرد", "تعداد زیادی توابع"], }, { - "question_number": 28, - "text": "بیل \"حفاری کردن\" است همانطور که \"چاقو\" است\"", - "options": [ - "لاغر شدن", - "بریدن", - "تیز کردن" - ] + question_number: 28, + text: 'بیل "حفاری کردن" است همانطور که "چاقو" است"', + options: ["لاغر شدن", "بریدن", "تیز کردن"], }, { - "question_number": 29, - "text": "این اتفاق می افتد که من نمی توانم بخوابم زیرا یک ایده مرا آزار می دهد", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 29, + text: "این اتفاق می افتد که من نمی توانم بخوابم زیرا یک ایده مرا آزار می دهد", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], }, { - "question_number": 30, - "text": "در زندگی شخصی به اهدافی که برای خودم در نظر گرفته ام می رسم", - "options": [ - "در اکثر موارد", - "گاهی اوقات", - "هرگز" - ] + question_number: 30, + text: "در زندگی شخصی به اهدافی که برای خودم در نظر گرفته ام می رسم", + options: ["در اکثر موارد", "گاهی اوقات", "هرگز"], }, { - "question_number": 31, - "text": "قانون منسوخ شده باید تغییر کند", - "options": [ + question_number: 31, + text: "قانون منسوخ شده باید تغییر کند", + options: [ "فقط پس از تجزیه و تحلیل کامل", "بین این دو", - "بدون به تأخیر انداختن بیشتر تغییر از طریق بحث های طولانی" - ] + "بدون به تأخیر انداختن بیشتر تغییر از طریق بحث های طولانی", + ], }, { - "question_number": 32, - "text": "وقتی روی پروژه‌ای کار می‌کنم که نیاز به اقدام سریع با افراد دیگر دارد، راحت نیستم (احساس خوبی ندارم)", - "options": [ - "بله", - "بین این دو", - "نه" - ] + question_number: 32, + text: "وقتی روی پروژه‌ای کار می‌کنم که نیاز به اقدام سریع با افراد دیگر دارد، راحت نیستم (احساس خوبی ندارم)", + options: ["بله", "بین این دو", "نه"], }, { - "question_number": 33, - "text": "به نظر من اکثر افرادی که می شناسم مرا یک شریک گفتگوی سرگرم کننده می دانند", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 33, + text: "به نظر من اکثر افرادی که می شناسم مرا یک شریک گفتگوی سرگرم کننده می دانند", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 34, - "text": "اگر ناگهان در یک گروه اجتماعی در مرکز توجه عمومی قرار بگیرم کمی احساس خجالت می کنم", - "options": [ + question_number: 34, + text: "اگر ناگهان در یک گروه اجتماعی در مرکز توجه عمومی قرار بگیرم کمی احساس خجالت می کنم", + options: [ "من آنها را همانطور که هستند می پذیرم", "بین این دو", - "آنها من را منزجر و ناراحت می کنند" - ] + "آنها من را منزجر و ناراحت می کنند", + ], }, { - "question_number": 35, - "text": "اگر ناگهان در یک گروه اجتماعی در مرکز توجه عمومی قرار بگیرم کمی احساس خجالت می کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 35, + text: "اگر ناگهان در یک گروه اجتماعی در مرکز توجه عمومی قرار بگیرم کمی احساس خجالت می کنم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 36, - "text": "من همیشه خوشحالم که مثلاً در یک گردهمایی بزرگ، پذیرایی، توپ یا اجتماع عمومی شرکت می کنم", - "options": [ - "همیشه", - "گاهی اوقات", - "هرگز" - ] + question_number: 36, + text: "من همیشه خوشحالم که مثلاً در یک گردهمایی بزرگ، پذیرایی، توپ یا اجتماع عمومی شرکت می کنم", + options: ["همیشه", "گاهی اوقات", "هرگز"], }, { - "question_number": 37, - "text": "در مدرسه ترجیح دادم یا ترجیح دادم", - "options": [ - "موسیقی", - "من نمی دانم", - "برای آموزش عادات و اخلاق خوب" - ] + question_number: 37, + text: "در مدرسه ترجیح دادم یا ترجیح دادم", + options: ["موسیقی", "من نمی دانم", "برای آموزش عادات و اخلاق خوب"], }, { - "question_number": 38, - "text": "وقتی مسئولیتی در حوزه ای به من سپرده می شود، تقاضا دارم دستورالعمل هایم رعایت شود یا در غیر این صورت استعفا می دهم.", - "options": [ - "بله", - "گاهی اوقات", - "نه" - ] + question_number: 38, + text: "وقتی مسئولیتی در حوزه ای به من سپرده می شود، تقاضا دارم دستورالعمل هایم رعایت شود یا در غیر این صورت استعفا می دهم.", + options: ["بله", "گاهی اوقات", "نه"], }, { - "question_number": 39, - "text": "برای والدین مهمتر است", - "options": [ + question_number: 39, + text: "برای والدین مهمتر است", + options: [ "برای کمک به رشد فرزندانشان", "هر دو", - "تا به آنها یاد بدهیم خودشان را کنترل کنند" - ] + "تا به آنها یاد بدهیم خودشان را کنترل کنند", + ], }, { - "question_number": 40, - "text": "در کار گروهی، ترجیح می دهم", - "options": [ - "خارها", - "بین این دو", - "برای اطمینان از رعایت مقررات" - ] + question_number: 40, + text: "در کار گروهی، ترجیح می دهم", + options: ["خارها", "بین این دو", "برای اطمینان از رعایت مقررات"], }, { - "question_number": 41, - "text": "احساس می کنم نیاز به فعالیت بدنی دارم که نیاز به تلاش خاصی دارد", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 41, + text: "احساس می کنم نیاز به فعالیت بدنی دارم که نیاز به تلاش خاصی دارد", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], }, { - "question_number": 42, - "text": "من ترجیح می دهم با افراد خوش اخلاق و مودب به جای افراد بی سواد برخورد کنم", - "options": [ - "بله", - "احتمالا", - "نه" - ] + question_number: 42, + text: "من ترجیح می دهم با افراد خوش اخلاق و مودب به جای افراد بی سواد برخورد کنم", + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 43, - "text": "وقتی مردم از من انتقاد می کنند احساس افسردگی زیادی می کنم", - "options": [ - "بله", - "بین این دو", - "نه" - ] + question_number: 43, + text: "وقتی مردم از من انتقاد می کنند احساس افسردگی زیادی می کنم", + options: ["بله", "بین این دو", "نه"], }, { - "question_number": 44, - "text": "وقتی رئیس با من تماس می گیرد", - "options": [ + question_number: 44, + text: "وقتی رئیس با من تماس می گیرد", + options: [ "هر دو", "بین هر دو احتمال", - "می ترسم کار اشتباهی انجام داده باشم" - ] + "می ترسم کار اشتباهی انجام داده باشم", + ], }, { - "question_number": 45, - "text": "در متن هایی که می خوانم، مقاصد پنهان را درک می کنم، نه به طور مستقیم بیان شده است", - "options": [ + question_number: 45, + text: "در متن هایی که می خوانم، مقاصد پنهان را درک می کنم، نه به طور مستقیم بیان شده است", + options: [ "افراد عملی با دستاوردهای مادی فوری", "من نمی دانم", - "افرادی با ایده هایی برای بهبود جهان" - ] + "افرادی با ایده هایی برای بهبود جهان", + ], }, { - "question_number": 46, - "text": "در متن هایی که می خوانم، مقاصد پنهان را درک می کنم، نه به طور مستقیم بیان شده است", - "options": [ - "بله", - "بین این دو", - "نه" - ] + question_number: 46, + text: "در متن هایی که می خوانم، مقاصد پنهان را درک می کنم، نه به طور مستقیم بیان شده است", + options: ["بله", "بین این دو", "نه"], }, { - "question_number": 47, - "text": "وقتی نوجوان بودم در فعالیت های ورزشی مدرسه شرکت می کردم", - "options": [ + question_number: 47, + text: "وقتی نوجوان بودم در فعالیت های ورزشی مدرسه شرکت می کردم", + options: [ "تا جایی که ممکن است، زمانی که مجبور شدم", "با بی تفاوتی", - "با اشتیاق" - ] + "با اشتیاق", + ], }, { - "question_number": 48, - "text": "اتاق من به خوبی چیده شده است و به طور کلی من دقیقاً می دانم که وسایلم کجا هستند", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 48, + text: "اتاق من به خوبی چیده شده است و به طور کلی من دقیقاً می دانم که وسایلم کجا هستند", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 49, - "text": "گاهی اوقات وقتی به اتفاقاتی که در طول روز افتاده فکر می کنم دچار تنش و عصبانیت می شوم", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 49, + text: "گاهی اوقات وقتی به اتفاقاتی که در طول روز افتاده فکر می کنم دچار تنش و عصبانیت می شوم", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], }, { - "question_number": 50, - "text": "وقتی با مردم صحبت می‌کنم، فکر می‌کنم که آیا چیزی که می‌گویم واقعاً به آنها علاقه دارد؟", - "options": [ - "تقریبا همیشه", - "گاهی اوقات", - "هرگز" - ] + question_number: 50, + text: "وقتی با مردم صحبت می‌کنم، فکر می‌کنم که آیا چیزی که می‌گویم واقعاً به آنها علاقه دارد؟", + options: ["تقریبا همیشه", "گاهی اوقات", "هرگز"], }, { - "question_number": 51, - "text": "اگر مجبور بودم انتخاب کنم، ترجیح می دادم باشم", - "options": [ - "جنگلبان", - "من نمی دانم", - "معلم دبیرستان" - ] + question_number: 51, + text: "اگر مجبور بودم انتخاب کنم، ترجیح می دادم باشم", + options: ["جنگلبان", "من نمی دانم", "معلم دبیرستان"], }, { - "question_number": 52, - "text": "در مناسبت های خاص جشن و سالگردهای مهم", - "options": [ + question_number: 52, + text: "در مناسبت های خاص جشن و سالگردهای مهم", + options: [ "من دوست دارم هدیه شخصی بدهم", "من نمی دانم", - "به نظر من پرداختن به خرید هدیه کسل کننده است" - ] - }, - { - "question_number": 53, - "text": "خسته\" یعنی \"کار کردن\" همانطور که \"افتخار\" است\"", - "options": [ - "لبخند بزن", - "موفقیت", - "خوشحال" - ] - }, - { - "question_number": 54, - "text": "کدام یک از 3 مورد زیر با دو مورد دیگر مطابقت ندارد", - "options": [ - "شمع", - "ماه", - "لامپ برقی" - ] - }, - { - "question_number": 55, - "text": "دوستان من را رها کرده اند", - "options": [ - "تقریبا هرگز", - "گاهی اوقات", - "اغلب" - ] - }, - { - "question_number": 56, - "text": "از طریق برخی ویژگی های شخصی، من نسبت به اکثر مردم احساس برتری می کنم", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] - }, - { - "question_number": 57, - "text": "وقتی چیزی مرا آزار می دهد، سعی می کنم احساسم را از دیگران پنهان کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + "به نظر من پرداختن به خرید هدیه کسل کننده است", + ], }, { - "question_number": 58, - "text": "من دوست دارم به نمایش بروم یا خوش بگذرانم", - "options": [ + question_number: 53, + text: 'خسته" یعنی "کار کردن" همانطور که "افتخار" است"', + options: ["لبخند بزن", "موفقیت", "خوشحال"], + }, + { + question_number: 54, + text: "کدام یک از 3 مورد زیر با دو مورد دیگر مطابقت ندارد", + options: ["شمع", "ماه", "لامپ برقی"], + }, + { + question_number: 55, + text: "دوستان من را رها کرده اند", + options: ["تقریبا هرگز", "گاهی اوقات", "اغلب"], + }, + { + question_number: 56, + text: "از طریق برخی ویژگی های شخصی، من نسبت به اکثر مردم احساس برتری می کنم", + options: ["بله", "من مطمئن نیستم", "نه"], + }, + { + question_number: 57, + text: "وقتی چیزی مرا آزار می دهد، سعی می کنم احساسم را از دیگران پنهان کنم", + options: ["بله", "کم و بیش", "نه"], + }, + { + question_number: 58, + text: "من دوست دارم به نمایش بروم یا خوش بگذرانم", + options: [ "چند بار در هفته", "حدود یک بار در هفته", - "کمتر از یک بار در هفته" - ] + "کمتر از یک بار در هفته", + ], }, { - "question_number": 59, - "text": "من معتقدم که درجه آزادی بسیار بالا از اخلاق خوب و احترام به قانون ارزشمندتر است", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 59, + text: "من معتقدم که درجه آزادی بسیار بالا از اخلاق خوب و احترام به قانون ارزشمندتر است", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 60, - "text": "در حضور افراد مسئول (با تجربه بیشتر، مسن تر یا در پست های مهم) تمایل به صحبت ندارم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 60, + text: "در حضور افراد مسئول (با تجربه بیشتر، مسن تر یا در پست های مهم) تمایل به صحبت ندارم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 61, - "text": "برای من دشوار است که به گروه بزرگی از مردم خطاب کنم یا در مقابل آنها سخنرانی کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 61, + text: "برای من دشوار است که به گروه بزرگی از مردم خطاب کنم یا در مقابل آنها سخنرانی کنم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 62, - "text": "وقتی در یک مکان ناآشنا هستم، حس جهت گیری خوبی دارم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 62, + text: "وقتی در یک مکان ناآشنا هستم، حس جهت گیری خوبی دارم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 63, - "text": "اگر کسی با من قهر کند", - "options": [ + question_number: 63, + text: "اگر کسی با من قهر کند", + options: [ "سعی می کنم آنها را آرام کنم", "من نمی دانم", - "من را اذیت می کند" - ] + "من را اذیت می کند", + ], }, { - "question_number": 64, - "text": "وقتی مقاله ای را در مجله می خوانم که چیزها را به شکلی تحریف شده ارائه می کند، به جای اینکه بخواهم بگویم چگونه چیزها را می بینم، آن را فراموش می کنم.", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 64, + text: "وقتی مقاله ای را در مجله می خوانم که چیزها را به شکلی تحریف شده ارائه می کند، به جای اینکه بخواهم بگویم چگونه چیزها را می بینم، آن را فراموش می کنم.", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 65, - "text": ".چیزهای بی اهمیتی مثل اسم خیابان ها و مغازه ها و ... یادم نیست", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 65, + text: ".چیزهای بی اهمیتی مثل اسم خیابان ها و مغازه ها و ... یادم نیست", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 66, - "text": "من با اشتها غذا می خورم و همیشه مثل بقیه مردم مرتب و تمیز می خورم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 66, + text: "من با اشتها غذا می خورم و همیشه مثل بقیه مردم مرتب و تمیز می خورم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 67, - "text": "من با اشتها غذا می خورم و همیشه مثل بقیه مردم مرتب و تمیز می خورم", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 67, + text: "من با اشتها غذا می خورم و همیشه مثل بقیه مردم مرتب و تمیز می خورم", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 68, - "text": "روزهایی هست که حالم بد است و دوست ندارم کسی را ببینم", - "options": [ - "خیلی به ندرت", - "گاهی اوقات", - "اغلب اوقات" - ] + question_number: 68, + text: "روزهایی هست که حالم بد است و دوست ندارم کسی را ببینم", + options: ["خیلی به ندرت", "گاهی اوقات", "اغلب اوقات"], }, { - "question_number": 69, - "text": "گاهی به من گفته اند که در صدا و حرکاتم اشتیاق زیادی نشان می دهم", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 69, + text: "گاهی به من گفته اند که در صدا و حرکاتم اشتیاق زیادی نشان می دهم", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], }, { - "question_number": 70, - "text": "در نوجوانی اگر نظر دیگری با پدر و مادرم داشتم", - "options": [ + question_number: 70, + text: "در نوجوانی اگر نظر دیگری با پدر و مادرم داشتم", + options: [ "من نظر خودم را حفظ کردم", "من کم و بیش نظرم را حفظ کردم", - "من به نظر پدر و مادرم تسلیم شدم" - ] + "من به نظر پدر و مادرم تسلیم شدم", + ], }, { - "question_number": 71, - "text": "ترجیح می‌دهم یک دفتر فقط برای خودم داشته باشم بدون اینکه آن را با شخص دیگری به اشتراک بگذارم", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 71, + text: "ترجیح می‌دهم یک دفتر فقط برای خودم داشته باشم بدون اینکه آن را با شخص دیگری به اشتراک بگذارم", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 72, - "text": "ترجیح می دهم از زندگی بی سر و صدا به روش خودم لذت ببرم تا اینکه به خاطر دستاوردهایم تحسین شوم", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 72, + text: "ترجیح می دهم از زندگی بی سر و صدا به روش خودم لذت ببرم تا اینکه به خاطر دستاوردهایم تحسین شوم", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 73, - "text": "من خودم را از بسیاری جهات بالغ می دانم", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 73, + text: "من خودم را از بسیاری جهات بالغ می دانم", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 74, - "text": "روشی که اکثر مردم انتقاد می کنند بیشتر از اینکه به من کمک کند، من را دلسرد می کند", - "options": [ - "اغلب", - "گاهی اوقات", - "هرگز" - ] + question_number: 74, + text: "روشی که اکثر مردم انتقاد می کنند بیشتر از اینکه به من کمک کند، من را دلسرد می کند", + options: ["اغلب", "گاهی اوقات", "هرگز"], }, { - "question_number": 75, - "text": "من همیشه موفق به کنترل کامل بیان احساساتم می شوم", - "options": [ - "همیشه", - "اغلب", - "هرگز" - ] + question_number: 75, + text: "من همیشه موفق به کنترل کامل بیان احساساتم می شوم", + options: ["همیشه", "اغلب", "هرگز"], }, { - "question_number": 76, - "text": "اگر ایده یک اختراع داشتم ترجیح می دادم", - "options": [ + question_number: 76, + text: "اگر ایده یک اختراع داشتم ترجیح می دادم", + options: [ "تا در آزمایشگاه کامل شود", "من نمی دانم", - "برای اجرا به دیگران منتقل شود" - ] + "برای اجرا به دیگران منتقل شود", + ], }, { - "question_number": 77, - "text": "غافلگیری \"عجیب\" است همانطور که \"ترس\" برای\"", - "options": [ - "شجاع", - "گلبرگ ها", - "وحشت زده" - ] + question_number: 77, + text: 'غافلگیری "عجیب" است همانطور که "ترس" برای"', + options: ["شجاع", "گلبرگ ها", "وحشت زده"], }, { - "question_number": 78, - "text": "کدام یک از 3 کسر زیر به دسته 2 کسر دیگر تعلق ندارد", - "options": [ - "3/7", - "3/9", - "3/11" - ] + question_number: 78, + text: "کدام یک از 3 کسر زیر به دسته 2 کسر دیگر تعلق ندارد", + options: ["3/7", "3/9", "3/11"], }, { - "question_number": 79, - "text": "به نظر می رسد برخی افراد مرا نادیده می گیرند یا از من دوری می کنند و من دلیل آن را نمی دانم", - "options": [ - "درست است", - "من نمی دانم", - "نادرست" - ] + question_number: 79, + text: "به نظر می رسد برخی افراد مرا نادیده می گیرند یا از من دوری می کنند و من دلیل آن را نمی دانم", + options: ["درست است", "من نمی دانم", "نادرست"], }, { - "question_number": 80, - "text": "مردم به خاطر نیت خوبم کمتر از آنچه که شایسته آن هستم با من مهربانانه رفتار می کنند", - "options": [ - "اغلب", - "گاهی اوقات", - "هرگز" - ] + question_number: 80, + text: "مردم به خاطر نیت خوبم کمتر از آنچه که شایسته آن هستم با من مهربانانه رفتار می کنند", + options: ["اغلب", "گاهی اوقات", "هرگز"], }, { - "question_number": 81, - "text": "استفاده از کلمات درشت، حتی زمانی که هیچ مرد و زن با هم در گروه وجود ندارد", - "options": [ + question_number: 81, + text: "استفاده از کلمات درشت، حتی زمانی که هیچ مرد و زن با هم در گروه وجود ندارد", + options: [ "من را عمیقاً منزجر می کند", "من را بی تفاوت می گذارد", - "من آن را دوست دارم" - ] - }, - { - "question_number": 82, - "text": "من از بسیاری از مردم دوستان کمتری دارم", - "options": [ - "بله", - "احتمالا", - "نه" - ] - }, - { - "question_number": 83, - "text": "من از بودن در جایی که افراد زیادی برای صحبت کردن با آنها وجود ندارند متنفرم", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] - }, - { - "question_number": 84, - "text": "اگرچه مردم گاهی مرا یک جوکر می دانند، اما باز هم مرا دوست داشتنی می دانند", - "options": [ - "بله", - "احتمالا", - "نه" - ] - }, - { - "question_number": 85, - "text": "من ترس صحنه را در موقعیت های اجتماعی در مناسبت های مختلف تجربه کرده ام", - "options": [ - "خیلی وقت ها", - "به ندرت", - "تقریبا هرگز" - ] - }, - { - "question_number": 86, - "text": "وقتی در گروه کوچکی از مردم هستم، راضی هستم که «در پس‌زمینه» بمانم و به دیگران اجازه بدهم مکالمه را ادامه دهند.", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + "من آن را دوست دارم", + ], + }, + { + question_number: 82, + text: "من از بسیاری از مردم دوستان کمتری دارم", + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 87, - "text": "من ترجیح می دهم بخوانم", - "options": [ + question_number: 83, + text: "من از بودن در جایی که افراد زیادی برای صحبت کردن با آنها وجود ندارند متنفرم", + options: ["بله", "من مطمئن نیستم", "نه"], + }, + { + question_number: 84, + text: "اگرچه مردم گاهی مرا یک جوکر می دانند، اما باز هم مرا دوست داشتنی می دانند", + options: ["بله", "احتمالا", "نه"], + }, + { + question_number: 85, + text: "من ترس صحنه را در موقعیت های اجتماعی در مناسبت های مختلف تجربه کرده ام", + options: ["خیلی وقت ها", "به ندرت", "تقریبا هرگز"], + }, + { + question_number: 86, + text: "وقتی در گروه کوچکی از مردم هستم، راضی هستم که «در پس‌زمینه» بمانم و به دیگران اجازه بدهم مکالمه را ادامه دهند.", + options: ["بله", "کم و بیش", "نه"], + }, + { + question_number: 87, + text: "من ترجیح می دهم بخوانم", + options: [ "گزارش خوبی از درگیری های نظامی یا مبارزات سیاسی", "من نمی دانم", - "یک رمان خوب" - ] + "یک رمان خوب", + ], }, { - "question_number": 88, - "text": "وقتی افراد مقتدر سعی می کنند به من فشار بیاورند، مطابق میل آنها عمل می کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 88, + text: "وقتی افراد مقتدر سعی می کنند به من فشار بیاورند، مطابق میل آنها عمل می کنم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 89, - "text": "مافوق و اعضای خانواده من معمولاً فقط زمانی برای من اظهار نظر می کنند که واقعاً موجه باشد", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 89, + text: "مافوق و اعضای خانواده من معمولاً فقط زمانی برای من اظهار نظر می کنند که واقعاً موجه باشد", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 90, - "text": "من از نگاه برخی افراد در خیابان یا مغازه ها به دیگران خوشم نمی آید", - "options": [ - "درست است", - "بی تفاوت", - "نادرست" - ] + question_number: 90, + text: "من از نگاه برخی افراد در خیابان یا مغازه ها به دیگران خوشم نمی آید", + options: ["درست است", "بی تفاوت", "نادرست"], }, { - "question_number": 91, - "text": "من آن را در طول یک سفر طولانی ترجیح می دهم", - "options": [ + question_number: 91, + text: "من آن را در طول یک سفر طولانی ترجیح می دهم", + options: [ "برای خواندن چیزهای جالب و جالب", "من نمی دانم", - "برای اینکه با یک دوست خوب در مورد این و آن صحبت کنید" - ] + "برای اینکه با یک دوست خوب در مورد این و آن صحبت کنید", + ], }, { - "question_number": 92, - "text": "در مواقعی که اگر درک نشویم می تواند عواقب جدی داشته باشد، حتی به بهای رعایت ادب و آرامش، از شوخی کردن و فهماندن خود دریغ نکنیم.", - "options": [ - "بله", - "بین این دو", - "نه" - ] + question_number: 92, + text: "در مواقعی که اگر درک نشویم می تواند عواقب جدی داشته باشد، حتی به بهای رعایت ادب و آرامش، از شوخی کردن و فهماندن خود دریغ نکنیم.", + options: ["بله", "بین این دو", "نه"], }, { - "question_number": 93, - "text": "اگر در دایره آشنای من افرادی هستند که از من خوششان نمی آید و به من بگویید که مورد پسند آنها نیستم.", - "options": [ - "اصلا اذیتم نمیکنه", - "بین این دو", - "من را اذیت می کند" - ] + question_number: 93, + text: "اگر در دایره آشنای من افرادی هستند که از من خوششان نمی آید و به من بگویید که مورد پسند آنها نیستم.", + options: ["اصلا اذیتم نمیکنه", "بین این دو", "من را اذیت می کند"], }, { - "question_number": 94, - "text": "وقتی از من تعریف و تمجید می شود احساس خجالت می کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 94, + text: "وقتی از من تعریف و تمجید می شود احساس خجالت می کنم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 95, - "text": "ترجیح میدم حقوق بگیرم", - "options": [ - "با حقوق ثابت و مطمئن", - "بین این دو", - "پر جنب و جوش" - ] + question_number: 95, + text: "ترجیح میدم حقوق بگیرم", + options: ["با حقوق ثابت و مطمئن", "بین این دو", "پر جنب و جوش"], }, { - "question_number": 96, - "text": "کار برای اینکه دائماً مطلع باشم، به روز با آنچه اتفاق می افتد، ترجیح می دهم", - "options": [ + question_number: 96, + text: "کار برای اینکه دائماً مطلع باشم، به روز با آنچه اتفاق می افتد، ترجیح می دهم", + options: [ "برای بحث در مورد مسائل با مردم", "بین این دو", - "به خود حقایق تکیه کنند" - ] + "به خود حقایق تکیه کنند", + ], }, { - "question_number": 97, - "text": "من دوست دارم فعالانه در فعالیت های اجتماعی شرکت کنم، در کمیته ها کار کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 97, + text: "من دوست دارم فعالانه در فعالیت های اجتماعی شرکت کنم، در کمیته ها کار کنم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 98, - "text": "برای تکمیل یک کار، من فقط زمانی راضی هستم که کوچکترین جزئیات از نزدیک بررسی شده باشد.", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 98, + text: "برای تکمیل یک کار، من فقط زمانی راضی هستم که کوچکترین جزئیات از نزدیک بررسی شده باشد.", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 99, - "text": "این اتفاق می افتد که چیزهای بسیار کوچک من را خیلی آزار می دهد", - "options": [ - "بله", - "مضطرب", - "نه" - ] + question_number: 99, + text: "این اتفاق می افتد که چیزهای بسیار کوچک من را خیلی آزار می دهد", + options: ["بله", "مضطرب", "نه"], }, { - "question_number": 100, - "text": "من بدون آشفتگی و بدون صحبت در خواب راحت می خوابم", - "options": [ - "همیشه", - "اغلب", - "خیلی به ندرت" - ] + question_number: 100, + text: "من بدون آشفتگی و بدون صحبت در خواب راحت می خوابم", + options: ["همیشه", "اغلب", "خیلی به ندرت"], }, { - "question_number": 101, - "text": "اگر مجبور به انتخاب بودم، در فعالیت حرفه ای خود ترجیح می دادم", - "options": [ + question_number: 101, + text: "اگر مجبور به انتخاب بودم، در فعالیت حرفه ای خود ترجیح می دادم", + options: [ "برای تعامل با مردم", "بین این دو", - "برای کار با اسناد بدون تعامل با مردم" - ] + "برای کار با اسناد بدون تعامل با مردم", + ], }, { - "question_number": 102, - "text": "اندازه\" به \"عرض\" است همانطور که \"بی صداقتی\" به\"", - "options": [ - "زندان", - "افراد عملی با دستاوردهای مادی فوری", - "سرقت" - ] + question_number: 102, + text: 'اندازه" به "عرض" است همانطور که "بی صداقتی" به"', + options: ["زندان", "افراد عملی با دستاوردهای مادی فوری", "سرقت"], }, { - "question_number": 103, - "text": "AB\" به \"DC\" است همانطور که \"SR\" به\"", - "options": [ - "PO", - "OP", - "TU" - ] + question_number: 103, + text: 'AB" به "DC" است همانطور که "SR" به"', + options: ["PO", "OP", "TU"], }, { - "question_number": 104, - "text": "وقتی مردم کارهایی را انجام می دهند یا می گویند که غیر منطقی است", - "options": [ - "من بی تفاوت هستم", - "من نمی دانم", - "من آنها را تحقیر می کنم" - ] + question_number: 104, + text: "وقتی مردم کارهایی را انجام می دهند یا می گویند که غیر منطقی است", + options: ["من بی تفاوت هستم", "من نمی دانم", "من آنها را تحقیر می کنم"], }, { - "question_number": 105, - "text": "وقتی مردم در حال گوش دادن به موسیقی با صدای بلند صحبت می کنند", - "options": [ + question_number: 105, + text: "وقتی مردم در حال گوش دادن به موسیقی با صدای بلند صحبت می کنند", + options: [ "اصلا", "بین این دو", - "آزارم می دهد و میل به گوش دادن به موسیقی را از دست می دهم" - ] + "آزارم می دهد و میل به گوش دادن به موسیقی را از دست می دهم", + ], }, { - "question_number": 106, - "text": "فکر می کنم می توان من را به عنوان یک موجود در نظر گرفت", - "options": [ - "بیشتر یک آدم آرام", - "بین این دو", - "بیشتر یک فرد خشن" - ] + question_number: 106, + text: "فکر می کنم می توان من را به عنوان یک موجود در نظر گرفت", + options: ["بیشتر یک آدم آرام", "بین این دو", "بیشتر یک فرد خشن"], }, { - "question_number": 107, - "text": "من فقط زمانی در جلسات شرکت می کنم که مجبور باشم", - "options": [ - "درست است", - "من نمی دانم", - "نادرست" - ] + question_number: 107, + text: "من فقط زمانی در جلسات شرکت می کنم که مجبور باشم", + options: ["درست است", "من نمی دانم", "نادرست"], }, { - "question_number": 108, - "text": "بهتر است واقع بین باشید و انتظار زیادی نداشته باشید تا اینکه باور کنید همه چیز خود به خود حل می شود", - "options": [ - "درست است", - "من نمی دانم", - "نادرست" - ] + question_number: 108, + text: "بهتر است واقع بین باشید و انتظار زیادی نداشته باشید تا اینکه باور کنید همه چیز خود به خود حل می شود", + options: ["درست است", "من نمی دانم", "نادرست"], }, { - "question_number": 109, - "text": "وقتی به مشکلاتی که در فعالیتم پیش خواهد آمد فکر می کنم", - "options": [ + question_number: 109, + text: "وقتی به مشکلاتی که در فعالیتم پیش خواهد آمد فکر می کنم", + options: [ "من سعی می کنم قبل از وقوع آنها پیش بینی کنم که چگونه پیش خواهم رفت", "من نمی دانم", - "به خودم می گویم که وقتی زمانش برسد می توانم با آنها کنار بیایم" - ] + "به خودم می گویم که وقتی زمانش برسد می توانم با آنها کنار بیایم", + ], }, { - "question_number": 110, - "text": "در مجالس به راحتی به مردم نزدیک می شوم", - "options": [ - "درست است", - "من مطمئن نیستم", - "نادرست" - ] + question_number: 110, + text: "در مجالس به راحتی به مردم نزدیک می شوم", + options: ["درست است", "من مطمئن نیستم", "نادرست"], }, { - "question_number": 111, - "text": "وقتی کمی دیپلماسی یا کار متقاعدکننده ای لازم است تا مردم را به انجام کاری وادار کند، از من دعوت می شود", - "options": [ - "اغلب", - "گاهی اوقات", - "هرگز" - ] + question_number: 111, + text: "وقتی کمی دیپلماسی یا کار متقاعدکننده ای لازم است تا مردم را به انجام کاری وادار کند، از من دعوت می شود", + options: ["اغلب", "گاهی اوقات", "هرگز"], }, { - "question_number": 112, - "text": "به نظر من بودن جالب تر است", - "options": [ - "مشاور راهنمایی شغلی", - "من نمی دانم", - "رئیس اداره سازماندهی کار" - ] - }, - { - "question_number": 113, - "text": "اگر مطمئن باشم که شخصی بی انصاف یا خودخواه است، به او می گویم حتی اگر باعث ناراحتی من شود.", - "options": [ - "بله", - "احتمالا", - "نه" - ] - }, - { - "question_number": 114, - "text": "من به شوخی به خاطر بازی چیزهای پوچ می گویم تا مردم را متحیر کنم و ببینم چه واکنشی نشان می دهند.", - "options": [ - "بله", - "شاید", - "هرگز" - ] - }, - { - "question_number": 115, - "text": "من می خواهم برای یک مجله در بخش سرگرمی (تئاتر، کنسرت، )اپرا بنویسم", - "options": [ - "بله", - "شاید", - "نه" - ] - }, - { - "question_number": 116, - "text": "وقتی مجبور می شوم در طول جلسه بی حرکت بنشینم، هرگز نیازی به خط خطی کردن یا بی قراری احساس نمی کنم", - "options": [ - "درست است", - "شاید", - "نادرست" - ] - }, - { - "question_number": 117, - "text": "اگر کسی چیزی را به من بگوید که من می دانم با واقعیت مطابقت ندارد، من فوراً این نظر را شکل می دهم", - "options": [ - "آنها دروغگو هستند", - "بین این دو", - "آنها اطلاعات ضعیفی دارند" - ] - }, - { - "question_number": 118, - "text": "من احساس تهدید مبهم به مجازات دارم، حتی زمانی که هیچ اشتباهی مرتکب نشده ام", - "options": [ - "اغلب", - "به ندرت", - "هرگز" - ] - }, - { - "question_number": 119, - "text": "این ایده مبالغه آمیز است که یک بیماری هم ماهیت روانی و هم جسمی دارد", - "options": [ - "بله", - "شاید", - "نه" - ] - }, - { - "question_number": 120, - "text": "شکوه (عظمت) و شکوه مراسم اصلی رسمی از آداب و رسومی است که باید حفظ شود", - "options": [ - "بله", - "شاید", - "نه" - ] - }, - { - "question_number": 121, - "text": "اگر مردم فکر می کردند که من خیلی رویایی یا خیلی بدیع هستم، ناراحت می شدم", - "options": [ - "بسیار", - "کمی", - "اصلا" - ] - }, - { - "question_number": 122, - "text": "برای انجام کاری، ترجیح می دهم کار کنم", - "options": [ - "همراه با دیگران", - "من نمی دانم", - "به تنهایی" - ] + question_number: 112, + text: "به نظر من بودن جالب تر است", + options: ["مشاور راهنمایی شغلی", "من نمی دانم", "رئیس اداره سازماندهی کار"], }, { - "question_number": 123, - "text": "من دوره هایی را پشت سر می گذارم که برایم سخت است که از دلسوزی برای خودم خودداری کنم", - "options": [ - "اغلب", - "گاهی اوقات", - "هرگز" - ] + question_number: 113, + text: "اگر مطمئن باشم که شخصی بی انصاف یا خودخواه است، به او می گویم حتی اگر باعث ناراحتی من شود.", + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 124, - "text": "من خیلی زود با مردم عصبانی می شوم", - "options": [ - "اغلب", - "گاهی اوقات", - "هرگز" - ] + question_number: 114, + text: "من به شوخی به خاطر بازی چیزهای پوچ می گویم تا مردم را متحیر کنم و ببینم چه واکنشی نشان می دهند.", + options: ["بله", "شاید", "هرگز"], }, { - "question_number": 125, - "text": "من به راحتی می توانم برخی از عادت ها را بدون اینکه دوباره آنها را ترک کنم، ترک کنم", - "options": [ - "همیشه", - "گاهی اوقات", - "هرگز" - ] + question_number: 115, + text: "من می خواهم برای یک مجله در بخش سرگرمی (تئاتر، کنسرت، )اپرا بنویسم", + options: ["بله", "شاید", "نه"], }, { - "question_number": 126, - "text": "برای دستمزد برابر، ترجیح می دهم باشم", - "options": [ - "وکیل", - "من نمی دانم", - "ناوبر و خلبان" - ] - }, - { - "question_number": 127, - "text": "بهتر است برای \"بدترین\" همانطور که \"آهسته تر\" است\"", - "options": [ - "پر جنب و جوش", - "بهترین", - "سریع ترین" - ] - }, - { - "question_number": 128, - "text": "کدام یک از 3 پاسخ زیر باید بعد از گروه حروف زیر قرار گیرد: XOOOOXXOOOXXX", - "options": [ - "OXXX", - "OOXX", - "XOOO" - ] - }, - { - "question_number": 129, - "text": "این اتفاق می افتد که وقتی زمان انجام کاری که به من پیشنهاد شده و قبلاً از آن خوشحال بودم فرا می رسد، دیگر حوصله کار کردن ندارم.", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] - }, - { - "question_number": 130, - "text": "در بیشتر کارهایی که انجام می‌دهم، بدون ایجاد مزاحمت توسط افرادی که در اطرافم سروصدا می‌کنند، تمرکز می‌کنم.", - "options": [ - "درست است", - "شاید", - "نادرست" - ] - }, - { - "question_number": 131, - "text": "گاهی اوقات می بینم که به غریبه ها چیزهایی می گویم که به نظرم مهم است، حتی اگر آنها چیزی از من نپرسیده باشند", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] - }, - { - "question_number": 132, - "text": "من بسیاری از ساعات آزادم را صرف گفتگو با دوستان در مورد لحظات خوشی که در گذشته با هم داشته ایم می گذرانم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 116, + text: "وقتی مجبور می شوم در طول جلسه بی حرکت بنشینم، هرگز نیازی به خط خطی کردن یا بی قراری احساس نمی کنم", + options: ["درست است", "شاید", "نادرست"], }, { - "question_number": 133, - "text": "من دوست دارم فقط برای سرگرمی در کارهای شجاعانه و حتی بی پروا افراط کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 117, + text: "اگر کسی چیزی را به من بگوید که من می دانم با واقعیت مطابقت ندارد، من فوراً این نظر را شکل می دهم", + options: ["آنها دروغگو هستند", "بین این دو", "آنها اطلاعات ضعیفی دارند"], }, { - "question_number": 134, - "text": "یک اتاق به هم ریخته", - "options": [ - "من اصلا ازش خوشم نمیاد", - "کم و بیش", - "من آن را دوست دارم" - ] + question_number: 118, + text: "من احساس تهدید مبهم به مجازات دارم، حتی زمانی که هیچ اشتباهی مرتکب نشده ام", + options: ["اغلب", "به ندرت", "هرگز"], }, { - "question_number": 135, - "text": "من خودم را فردی بسیار اجتماعی می دانم که افراد زیادی را ملاقات می کنم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 119, + text: "این ایده مبالغه آمیز است که یک بیماری هم ماهیت روانی و هم جسمی دارد", + options: ["بله", "شاید", "نه"], + }, + { + question_number: 120, + text: "شکوه (عظمت) و شکوه مراسم اصلی رسمی از آداب و رسومی است که باید حفظ شود", + options: ["بله", "شاید", "نه"], + }, + { + question_number: 121, + text: "اگر مردم فکر می کردند که من خیلی رویایی یا خیلی بدیع هستم، ناراحت می شدم", + options: ["بسیار", "کمی", "اصلا"], + }, + { + question_number: 122, + text: "برای انجام کاری، ترجیح می دهم کار کنم", + options: ["همراه با دیگران", "من نمی دانم", "به تنهایی"], + }, + { + question_number: 123, + text: "من دوره هایی را پشت سر می گذارم که برایم سخت است که از دلسوزی برای خودم خودداری کنم", + options: ["اغلب", "گاهی اوقات", "هرگز"], + }, + { + question_number: 124, + text: "من خیلی زود با مردم عصبانی می شوم", + options: ["اغلب", "گاهی اوقات", "هرگز"], + }, + { + question_number: 125, + text: "من به راحتی می توانم برخی از عادت ها را بدون اینکه دوباره آنها را ترک کنم، ترک کنم", + options: ["همیشه", "گاهی اوقات", "هرگز"], + }, + { + question_number: 126, + text: "برای دستمزد برابر، ترجیح می دهم باشم", + options: ["وکیل", "من نمی دانم", "ناوبر و خلبان"], + }, + { + question_number: 127, + text: 'بهتر است برای "بدترین" همانطور که "آهسته تر" است"', + options: ["پر جنب و جوش", "بهترین", "سریع ترین"], + }, + { + question_number: 128, + text: "کدام یک از 3 پاسخ زیر باید بعد از گروه حروف زیر قرار گیرد: XOOOOXXOOOXXX", + options: ["OXXX", "OOXX", "XOOO"], + }, + { + question_number: 129, + text: "این اتفاق می افتد که وقتی زمان انجام کاری که به من پیشنهاد شده و قبلاً از آن خوشحال بودم فرا می رسد، دیگر حوصله کار کردن ندارم.", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], + }, + { + question_number: 130, + text: "در بیشتر کارهایی که انجام می‌دهم، بدون ایجاد مزاحمت توسط افرادی که در اطرافم سروصدا می‌کنند، تمرکز می‌کنم.", + options: ["درست است", "شاید", "نادرست"], + }, + { + question_number: 131, + text: "گاهی اوقات می بینم که به غریبه ها چیزهایی می گویم که به نظرم مهم است، حتی اگر آنها چیزی از من نپرسیده باشند", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], + }, + { + question_number: 132, + text: "من بسیاری از ساعات آزادم را صرف گفتگو با دوستان در مورد لحظات خوشی که در گذشته با هم داشته ایم می گذرانم", + options: ["بله", "کم و بیش", "نه"], + }, + { + question_number: 133, + text: "من دوست دارم فقط برای سرگرمی در کارهای شجاعانه و حتی بی پروا افراط کنم", + options: ["بله", "کم و بیش", "نه"], + }, + { + question_number: 134, + text: "یک اتاق به هم ریخته", + options: ["من اصلا ازش خوشم نمیاد", "کم و بیش", "من آن را دوست دارم"], + }, + { + question_number: 135, + text: "من خودم را فردی بسیار اجتماعی می دانم که افراد زیادی را ملاقات می کنم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 136, - "text": "در گفتگوها و بحث ها", - "options": [ + question_number: 136, + text: "در گفتگوها و بحث ها", + options: [ "من آزادانه احساساتم را بیان می کنم", "کم و بیش", - "من احساساتم را برای خودم نگه می دارم" - ] + "من احساساتم را برای خودم نگه می دارم", + ], }, { - "question_number": 137, - "text": "من موسیقی را ترجیح می دهم", - "options": [ - "سبک و شاداب", - "بین این دو", - "عاطفی و احساسی" - ] + question_number: 137, + text: "من موسیقی را ترجیح می دهم", + options: ["سبک و شاداب", "بین این دو", "عاطفی و احساسی"], }, { - "question_number": 138, - "text": "من زیبایی یک شعر را بیشتر از یک سلاح کامل قدر می دانم", - "options": [ - "بله", - "احتمالا", - "نه" - ] + question_number: 138, + text: "من زیبایی یک شعر را بیشتر از یک سلاح کامل قدر می دانم", + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 139, - "text": "اگر یک مشاهده خوب من مورد توجه قرار نگیرد", - "options": [ + question_number: 139, + text: "اگر یک مشاهده خوب من مورد توجه قرار نگیرد", + options: [ "من اصرار ندارم", "من نمی دانم", - "من آن را تکرار می کنم تا به مردم فرصتی بدهم تا متوجه آن شوند" - ] + "من آن را تکرار می کنم تا به مردم فرصتی بدهم تا متوجه آن شوند", + ], }, { - "question_number": 140, - "text": "من مایلم در یک سرویس توانبخشی برای مجرمانی که در حال آزادی موقت هستند کار کنم", - "options": [ - "بله", - "مضطرب", - "نه" - ] + question_number: 140, + text: "من مایلم در یک سرویس توانبخشی برای مجرمانی که در حال آزادی موقت هستند کار کنم", + options: ["بله", "مضطرب", "نه"], }, { - "question_number": 141, - "text": "هنگامی که با افراد غریبه مختلف رابطه دارید، باید محتاط باشید زیرا خطرات آلودگی و سایر خطرات ممکن است ایجاد شود.", - "options": [ - "بله", - "من نمی دانم", - "نه" - ] + question_number: 141, + text: "هنگامی که با افراد غریبه مختلف رابطه دارید، باید محتاط باشید زیرا خطرات آلودگی و سایر خطرات ممکن است ایجاد شود.", + options: ["بله", "من نمی دانم", "نه"], }, { - "question_number": 142, - "text": "من ترجیح می دهم از طریق یک سازمان توریستی در یک برنامه سفر (مسیری) که توسط آن سازمان تعیین شده است، به خارج از کشور سفر کنم، نه اینکه خودم در مورد مکان هایی که بازدید خواهم کرد تصمیم بگیرم.", - "options": [ - "بله", - "احتمالا", - "نه" - ] + question_number: 142, + text: "من ترجیح می دهم از طریق یک سازمان توریستی در یک برنامه سفر (مسیری) که توسط آن سازمان تعیین شده است، به خارج از کشور سفر کنم، نه اینکه خودم در مورد مکان هایی که بازدید خواهم کرد تصمیم بگیرم.", + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 143, - "text": "من را به درستی فردی سرسخت و سخت کوش می دانند، اما چندان موفق نیستم", - "options": [ - "بله", - "احتمالا", - "نه" - ] + question_number: 143, + text: "من را به درستی فردی سرسخت و سخت کوش می دانند، اما چندان موفق نیستم", + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 144, - "text": "اگر پیش بیاید که مردم از محبت من سوء استفاده کنند، ناراحت نمی شوم و زود فراموش نمی کنم", - "options": [ - "بله", - "من مطمئن نیستم", - "نه" - ] + question_number: 144, + text: "اگر پیش بیاید که مردم از محبت من سوء استفاده کنند، ناراحت نمی شوم و زود فراموش نمی کنم", + options: ["بله", "من مطمئن نیستم", "نه"], }, { - "question_number": 145, - "text": "اگر بخواهم شاهد جنجال داغی باشم که در طول یک بحث در یک گروه به وجود می آید", - "options": [ + question_number: 145, + text: "اگر بخواهم شاهد جنجال داغی باشم که در طول یک بحث در یک گروه به وجود می آید", + options: [ "من دوست دارم یک برنده وجود داشته باشد", "بین این دو", - "من دوست دارم به یک عقل سلیم برسم" - ] + "من دوست دارم به یک عقل سلیم برسم", + ], }, { - "question_number": 146, - "text": "دوست دارم کارهایی را که باید انجام دهم به تنهایی سازماندهی کنم، بدون اینکه دیگران حرفم را قطع کنند یا به من توصیه کنند", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 146, + text: "دوست دارم کارهایی را که باید انجام دهم به تنهایی سازماندهی کنم، بدون اینکه دیگران حرفم را قطع کنند یا به من توصیه کنند", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 147, - "text": "در اعمالم تحت تاثیر احساس حسادت قرار می گیرم", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "اصلا" - ] + question_number: 147, + text: "در اعمالم تحت تاثیر احساس حسادت قرار می گیرم", + options: ["گاهی اوقات", "خیلی به ندرت", "اصلا"], }, { - "question_number": 148, - "text": "من کاملا با جمله زیر موافقم: \"حتی اگر او اشتباه می کند، رئیس \".هنوز رئیس است\"", - "options": [ - "بله", - "بین این دو", - "نه" - ] + question_number: 148, + text: 'من کاملا با جمله زیر موافقم: "حتی اگر او اشتباه می کند، رئیس ".هنوز رئیس است"', + options: ["بله", "بین این دو", "نه"], }, { - "question_number": 149, - "text": "وقتی به تمام کارهایی که باید انجام دهم فکر می کنم احساس اضطراب می کنم", - "options": [ - "بله", - "گاهی اوقات", - "نه" - ] + question_number: 149, + text: "وقتی به تمام کارهایی که باید انجام دهم فکر می کنم احساس اضطراب می کنم", + options: ["بله", "گاهی اوقات", "نه"], }, { - "question_number": 150, - "text": "وقتی درگیر یک بازی هستم، توصیه هایی که اطرافیانم به من می دهند، مرا آزار نمی دهد", - "options": [ - "درست است", - "من مطمئن نیستم", - "نادرست" - ] + question_number: 150, + text: "وقتی درگیر یک بازی هستم، توصیه هایی که اطرافیانم به من می دهند، مرا آزار نمی دهد", + options: ["درست است", "من مطمئن نیستم", "نادرست"], }, { - "question_number": 151, - "text": "بودن جالب تر است", - "options": [ - "هنرمند", - "من نمی دانم", - "دبیر یک انجمن" - ] - }, - { - "question_number": 152, - "text": "کدام یک از 3 کلمه زیر با 2 کلمه دیگر در یک دسته قرار نمی گیرد", - "options": [ - "\"مهم نیست\"", - "\"کمی\"", - "\"خیلی\"" - ] - }, - { - "question_number": 153, - "text": "شعله \"گرما\" است همانطور که \"رز\" است\"", - "options": [ - "خارها", - "گلبرگ ها", - "عطر" - ] - }, - { - "question_number": 154, - "text": "خواب های آشفته ای دارم که خوابم را مختل می کند", - "options": [ - "اغلب", - "گاهی اوقات", - "تقریبا هرگز" - ] - }, - { - "question_number": 155, - "text": "حتی اگر شرایط واقعاً برای موفقیت چیزی نامطلوب باشد، من همچنان معتقدم که برای موفقیت باید همه چیز را امتحان کنم", - "options": [ - "همیشه", - "گاهی اوقات", - "هرگز" - ] - }, - { - "question_number": 156, - "text": "من دوست دارم در شرایطی باشم که به خوبی می دانم که گروه باید چه کار کند، طبیعتاً رهبر می شوم", - "options": [ - "درست است", - "کم و بیش", - "نادرست" - ] + question_number: 151, + text: "بودن جالب تر است", + options: ["هنرمند", "من نمی دانم", "دبیر یک انجمن"], }, { - "question_number": 157, - "text": "ترجیح می‌دهم به جای اینکه با یک سبک شیک و اصیل برجسته باشم، ملایم و کلاسیک بپوشم", - "options": [ - "درست است", - "من مطمئن نیستم", - "نادرست" - ] + question_number: 152, + text: "کدام یک از 3 کلمه زیر با 2 کلمه دیگر در یک دسته قرار نمی گیرد", + options: ['"مهم نیست"', '"کمی"', '"خیلی"'], }, { - "question_number": 158, - "text": "یک شب آرام اختصاص داده شده به یک فعالیت مورد علاقه برای من لذت بخش تر از شرکت در یک جمع پر جنب و جوش است", - "options": [ - "درست است", - "من مطمئن نیستم", - "نادرست" - ] + question_number: 153, + text: 'شعله "گرما" است همانطور که "رز" است"', + options: ["خارها", "گلبرگ ها", "عطر"], }, { - "question_number": 159, - "text": "من در برابر پیشنهادهای خیرخواهانه دیگران مقاومت می کنم، حتی زمانی که متوجه می شوم اشتباه می کنم", - "options": [ - "گاهی اوقات", - "تقریبا هرگز", - "هرگز" - ] + question_number: 154, + text: "خواب های آشفته ای دارم که خوابم را مختل می کند", + options: ["اغلب", "گاهی اوقات", "تقریبا هرگز"], }, { - "question_number": 160, - "text": "در تمام تصمیماتی که می‌گیرم، همیشه این وظیفه را می‌دانم که بر اساس قوانین اساسی درست و غلط هدایت شوم", - "options": [ - "درست است", - "کم و بیش", - "نادرست" - ] + question_number: 155, + text: "حتی اگر شرایط واقعاً برای موفقیت چیزی نامطلوب باشد، من همچنان معتقدم که برای موفقیت باید همه چیز را امتحان کنم", + options: ["همیشه", "گاهی اوقات", "هرگز"], }, { - "question_number": 161, - "text": "وقتی گروهی از مردم در حین کار من را تماشا می کنند، تا حدودی احساس ناراحتی می کنم", - "options": [ - "درست است", - "شاید", - "نادرست" - ] + question_number: 156, + text: "من دوست دارم در شرایطی باشم که به خوبی می دانم که گروه باید چه کار کند، طبیعتاً رهبر می شوم", + options: ["درست است", "کم و بیش", "نادرست"], }, { - "question_number": 162, - "text": "نظر شما در مورد جمله زیر چیست: \"با توجه به اینکه همیشه نمی توان عاقلانه کار کرد، گاهی اوقات لازم است بدون \".ناخوشایند\" به اجبار متوسل شویم.", - "options": [ - "موافقم", - "من نمی دانم", - "من مخالفم" - ] + question_number: 157, + text: "ترجیح می‌دهم به جای اینکه با یک سبک شیک و اصیل برجسته باشم، ملایم و کلاسیک بپوشم", + options: ["درست است", "من مطمئن نیستم", "نادرست"], }, { - "question_number": 163, - "text": "در مدرسه ترجیح دادم", - "options": [ - "زبان رومانیایی", - "من نمی دانم", - "ریاضیات" - ] + question_number: 158, + text: "یک شب آرام اختصاص داده شده به یک فعالیت مورد علاقه برای من لذت بخش تر از شرکت در یک جمع پر جنب و جوش است", + options: ["درست است", "من مطمئن نیستم", "نادرست"], }, { - "question_number": 164, - "text": "گاهی برای من پیش آمده که عصبانی می شوم زیرا پشت سرم چیزهای بدی درباره من می گویند که کاملا ساختگی بود.", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 159, + text: "من در برابر پیشنهادهای خیرخواهانه دیگران مقاومت می کنم، حتی زمانی که متوجه می شوم اشتباه می کنم", + options: ["گاهی اوقات", "تقریبا هرگز", "هرگز"], }, { - "question_number": 165, - "text": "گفتگو با مردم عادی که مطابق با قوانین و آداب و رسوم هستند", - "options": [ + question_number: 160, + text: "در تمام تصمیماتی که می‌گیرم، همیشه این وظیفه را می‌دانم که بر اساس قوانین اساسی درست و غلط هدایت شوم", + options: ["درست است", "کم و بیش", "نادرست"], + }, + { + question_number: 161, + text: "وقتی گروهی از مردم در حین کار من را تماشا می کنند، تا حدودی احساس ناراحتی می کنم", + options: ["درست است", "شاید", "نادرست"], + }, + { + question_number: 162, + text: 'نظر شما در مورد جمله زیر چیست: "با توجه به اینکه همیشه نمی توان عاقلانه کار کرد، گاهی اوقات لازم است بدون ".ناخوشایند" به اجبار متوسل شویم.', + options: ["موافقم", "من نمی دانم", "من مخالفم"], + }, + { + question_number: 163, + text: "در مدرسه ترجیح دادم", + options: ["زبان رومانیایی", "من نمی دانم", "ریاضیات"], + }, + { + question_number: 164, + text: "گاهی برای من پیش آمده که عصبانی می شوم زیرا پشت سرم چیزهای بدی درباره من می گویند که کاملا ساختگی بود.", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], + }, + { + question_number: 165, + text: "گفتگو با مردم عادی که مطابق با قوانین و آداب و رسوم هستند", + options: [ "اغلب بسیار جالب و آموزنده هستند", "نسبت به من بی تفاوت هستند", - "حوصله ام سر می رود زیرا سطحی و غیر جالب هستند" - ] + "حوصله ام سر می رود زیرا سطحی و غیر جالب هستند", + ], }, { - "question_number": 166, - "text": "بعضی چیزها آنقدر مرا ناراحت می کند که ترجیح می دهم دیگر در مورد آنها صحبت نکنم", - "options": [ - "درست است", - "بین این دو", - "نادرست" - ] + question_number: 166, + text: "بعضی چیزها آنقدر مرا ناراحت می کند که ترجیح می دهم دیگر در مورد آنها صحبت نکنم", + options: ["درست است", "بین این دو", "نادرست"], }, { - "question_number": 167, - "text": "در تربیت کودک اهمیت بیشتری دارد", - "options": [ + question_number: 167, + text: "در تربیت کودک اهمیت بیشتری دارد", + options: [ "برای ارائه محبت، چیزی که آنها نیاز دارند", "من نمی دانم", - "برای آموزش عادات و اخلاق خوب" - ] + "برای آموزش عادات و اخلاق خوب", + ], }, { - "question_number": 168, - "text": "مردم مرا فردی با صداقت (همه یکپارچه)، متعادل و بی‌تأثیر از موفقیت‌ها و شکست‌های زندگی می‌دانند.", - "options": [ - "درست است", - "شاید", - "نادرست" - ] + question_number: 168, + text: "مردم مرا فردی با صداقت (همه یکپارچه)، متعادل و بی‌تأثیر از موفقیت‌ها و شکست‌های زندگی می‌دانند.", + options: ["درست است", "شاید", "نادرست"], }, { - "question_number": 169, - "text": "من معتقدم جامعه باید این خرد را داشته باشد که عادات خود را تغییر دهد و حتی عادات قدیمی را کنار بگذارد", - "options": [ - "درست است", - "کم و بیش", - "نادرست" - ] + question_number: 169, + text: "من معتقدم جامعه باید این خرد را داشته باشد که عادات خود را تغییر دهد و حتی عادات قدیمی را کنار بگذارد", + options: ["درست است", "کم و بیش", "نادرست"], }, { - "question_number": 170, - "text": "من معتقدم که در دنیای مدرن حل کردن مهمتر است", - "options": [ - "مشکل ارزش های اخلاقی", - "من نمی دانم", - "سریع ترین" - ] + question_number: 170, + text: "من معتقدم که در دنیای مدرن حل کردن مهمتر است", + options: ["مشکل ارزش های اخلاقی", "من نمی دانم", "سریع ترین"], }, { - "question_number": 171, - "text": "بیشتر لذت می برم", - "options": [ - "خواندن یک کتاب خوب", - "من نمی دانم", - "شرکت در بحث گروهی" - ] + question_number: 171, + text: "بیشتر لذت می برم", + options: ["خواندن یک کتاب خوب", "من نمی دانم", "شرکت در بحث گروهی"], }, { - "question_number": 172, - "text": "من ترجیح می‌دهم کاری را که می‌خواهم انجام دهم تا اینکه با قوانین تعیین‌شده مطابقت کنم", - "options": [ - "درست است", - "من مطمئن نیستم", - "نادرست" - ] + question_number: 172, + text: "من ترجیح می‌دهم کاری را که می‌خواهم انجام دهم تا اینکه با قوانین تعیین‌شده مطابقت کنم", + options: ["درست است", "من مطمئن نیستم", "نادرست"], }, { - "question_number": 173, - "text": "قبل از بحث در مورد چیزی، سعی می کنم از صحت آنچه می خواهم بگویم اطمینان حاصل کنم", - "options": [ - "همیشه", - "گاهی اوقات", - "خیلی به ندرت" - ] + question_number: 173, + text: "قبل از بحث در مورد چیزی، سعی می کنم از صحت آنچه می خواهم بگویم اطمینان حاصل کنم", + options: ["همیشه", "گاهی اوقات", "خیلی به ندرت"], }, { - "question_number": 174, - "text": "گاهی اوقات بعضی چیزهای کوچک به طرز غیرقابل تحملی اعصابم را به هم می ریزند، حتی اگر می دانم بی اهمیت هستند.", - "options": [ - "گاهی اوقات", - "خیلی به ندرت", - "هرگز" - ] + question_number: 174, + text: "گاهی اوقات بعضی چیزهای کوچک به طرز غیرقابل تحملی اعصابم را به هم می ریزند، حتی اگر می دانم بی اهمیت هستند.", + options: ["گاهی اوقات", "خیلی به ندرت", "هرگز"], }, { - "question_number": 175, - "text": "به ندرت اتفاق می افتد که تحت تأثیر یک انگیزه لحظه ای چیزهایی بگویم که کاملاً تاسف انگیز است", - "options": [ - "درست است", - "بین این دو", - "نادرست" - ] + question_number: 175, + text: "به ندرت اتفاق می افتد که تحت تأثیر یک انگیزه لحظه ای چیزهایی بگویم که کاملاً تاسف انگیز است", + options: ["درست است", "بین این دو", "نادرست"], }, { - "question_number": 176, - "text": "اگر از من خواسته شود در یک مراسم خیریه شرکت کنم", - "options": [ + question_number: 176, + text: "اگر از من خواسته شود در یک مراسم خیریه شرکت کنم", + options: [ "من قبول می کنم", "من نمی دانم", - "من مودبانه پاسخ می دهم که خیلی سرم شلوغ است" - ] + "من مودبانه پاسخ می دهم که خیلی سرم شلوغ است", + ], }, { - "question_number": 177, - "text": "کدام یک از 3 کلمه زیر به همان دسته دو کلمه دیگر تعلق ندارد", - "options": [ - "\"عریض\"", - "\"سینوسی\"", - "\"مستقیم\"" - ] + question_number: 177, + text: "کدام یک از 3 کلمه زیر به همان دسته دو کلمه دیگر تعلق ندارد", + options: ['"عریض"', '"سینوسی"', '"مستقیم"'], }, { - "question_number": 178, - "text": "به زودی \"هرگز\" همان چیزی است که \"تقریبا\" است\"", - "options": [ - "\"هیچ جا\"", - "\"تقریبا\"", - "\"در دوردست\"" - ] + question_number: 178, + text: 'به زودی "هرگز" همان چیزی است که "تقریبا" است"', + options: ['"هیچ جا"', '"تقریبا"', '"در دوردست"'], }, { - "question_number": 179, - "text": "اگر اشتباهی در جامعه مرتکب شوم، به سرعت آن را فراموش می کنم", - "options": [ - "درست است", - "کم و بیش", - "نادرست" - ] + question_number: 179, + text: "اگر اشتباهی در جامعه مرتکب شوم، به سرعت آن را فراموش می کنم", + options: ["درست است", "کم و بیش", "نادرست"], }, { - "question_number": 180, - "text": "من یک فرد \"خلاق\" به حساب می آیم که تقریباً همیشه چیزی برای ارائه برای مشکلات پیش آمده دارد", - "options": [ - "بله", - "احتمالا", - "نه" - ] + question_number: 180, + text: 'من یک فرد "خلاق" به حساب می آیم که تقریباً همیشه چیزی برای ارائه برای مشکلات پیش آمده دارد', + options: ["بله", "احتمالا", "نه"], }, { - "question_number": 181, - "text": "من باور دارم که هستم", - "options": [ + question_number: 181, + text: "من باور دارم که هستم", + options: [ "خونسردی در مواجهه با شرایط سخت", "من نمی دانم", - "تحمل خواسته های دیگران" - ] + "تحمل خواسته های دیگران", + ], }, { - "question_number": 182, - "text": "من را فردی می دانند که به راحتی مشتاق می شود", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 182, + text: "من را فردی می دانند که به راحتی مشتاق می شود", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 183, - "text": "من کارهایی را دوست دارم که فرصت هایی برای تغییر، وظایف متنوع، سفر، حتی اگر این کار با خطراتی همراه باشد، ارائه می دهد", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 183, + text: "من کارهایی را دوست دارم که فرصت هایی برای تغییر، وظایف متنوع، سفر، حتی اگر این کار با خطراتی همراه باشد، ارائه می دهد", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 184, - "text": "من آدم نسبتاً دقیقی هستم که دوست دارم کارها را به بهترین نحو ممکن انجام دهم", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 184, + text: "من آدم نسبتاً دقیقی هستم که دوست دارم کارها را به بهترین نحو ممکن انجام دهم", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 185, - "text": "من کاری را دوست دارم که در آن باید با وجدان باشید و دقت لازم است", - "options": [ - "بله", - "کم و بیش", - "نه" - ] + question_number: 185, + text: "من کاری را دوست دارم که در آن باید با وجدان باشید و دقت لازم است", + options: ["بله", "کم و بیش", "نه"], }, { - "question_number": 186, - "text": "من از دسته افراد فعالی هستم که هرگز نمی توانند بدون انجام کاری یک جا بنشینند", - "options": [ - "درست است", - "بین این دو", - "نادرست" - ] + question_number: 186, + text: "من از دسته افراد فعالی هستم که هرگز نمی توانند بدون انجام کاری یک جا بنشینند", + options: ["درست است", "بین این دو", "نادرست"], }, { - "question_number": 187, - "text": "مطمئنم هیچ سوالی را از این پرسشنامه حذف نکرده ام و هر بار به درستی پاسخ داده ام.", - "options": [ - "بله", - "بین این دو", - "نه" - ] - } + question_number: 187, + text: "مطمئنم هیچ سوالی را از این پرسشنامه حذف نکرده ام و هر بار به درستی پاسخ داده ام.", + options: ["بله", "بین این دو", "نه"], + }, ]; diff --git a/src/data/countries.ts b/src/data/countries.ts new file mode 100644 index 0000000..c429779 --- /dev/null +++ b/src/data/countries.ts @@ -0,0 +1,401 @@ +export const COUNTRIES_EN = [ + "Afghanistan", + "Albania", + "Algeria", + "Andorra", + "Angola", + "Antigua and Barbuda", + "Argentina", + "Armenia", + "Australia", + "Austria", + "Azerbaijan", + "Bahamas", + "Bahrain", + "Bangladesh", + "Barbados", + "Belarus", + "Belgium", + "Belize", + "Benin", + "Bhutan", + "Bolivia", + "Bosnia and Herzegovina", + "Botswana", + "Brazil", + "Brunei", + "Bulgaria", + "Burkina Faso", + "Burundi", + "Cabo Verde", + "Cambodia", + "Cameroon", + "Canada", + "Central African Republic", + "Chad", + "Chile", + "China", + "Colombia", + "Comoros", + "Congo", + "Costa Rica", + "Croatia", + "Cuba", + "Cyprus", + "Czechia", + "Democratic Republic of the Congo", + "Denmark", + "Djibouti", + "Dominica", + "Dominican Republic", + "Ecuador", + "Egypt", + "El Salvador", + "Equatorial Guinea", + "Eritrea", + "Estonia", + "Eswatini", + "Ethiopia", + "Fiji", + "Finland", + "France", + "Gabon", + "Gambia", + "Georgia", + "Germany", + "Ghana", + "Greece", + "Grenada", + "Guatemala", + "Guinea", + "Guinea-Bissau", + "Guyana", + "Haiti", + "Holy See", + "Honduras", + "Hungary", + "Iceland", + "India", + "Indonesia", + "Iran", + "Iraq", + "Ireland", + "Italy", + "Ivory Coast", + "Jamaica", + "Japan", + "Jordan", + "Kazakhstan", + "Kenya", + "Kiribati", + "Kuwait", + "Kyrgyzstan", + "Laos", + "Latvia", + "Lebanon", + "Lesotho", + "Liberia", + "Libya", + "Liechtenstein", + "Lithuania", + "Luxembourg", + "Madagascar", + "Malawi", + "Malaysia", + "Maldives", + "Mali", + "Malta", + "Marshall Islands", + "Mauritania", + "Mauritius", + "Mexico", + "Micronesia", + "Moldova", + "Monaco", + "Mongolia", + "Montenegro", + "Morocco", + "Mozambique", + "Myanmar", + "Namibia", + "Nauru", + "Nepal", + "Netherlands", + "New Zealand", + "Nicaragua", + "Niger", + "Nigeria", + "North Korea", + "North Macedonia", + "Norway", + "Oman", + "Pakistan", + "Palau", + "Palestine State", + "Panama", + "Papua New Guinea", + "Paraguay", + "Peru", + "Philippines", + "Poland", + "Portugal", + "Qatar", + "Romania", + "Russia", + "Rwanda", + "Saint Kitts and Nevis", + "Saint Lucia", + "Saint Vincent and the Grenadines", + "Samoa", + "San Marino", + "Sao Tome and Principe", + "Saudi Arabia", + "Senegal", + "Serbia", + "Seychelles", + "Sierra Leone", + "Singapore", + "Slovakia", + "Slovenia", + "Solomon Islands", + "Somalia", + "South Africa", + "South Korea", + "South Sudan", + "Spain", + "Sri Lanka", + "Sudan", + "Suriname", + "Sweden", + "Switzerland", + "Syria", + "Tajikistan", + "Tanzania", + "Thailand", + "Timor-Leste", + "Togo", + "Tonga", + "Trinidad and Tobago", + "Tunisia", + "Turkey", + "Turkmenistan", + "Tuvalu", + "Uganda", + "Ukraine", + "United Arab Emirates (UAE)", + "United Kingdom (UK)", + "United States (US)", + "Uruguay", + "Uzbekistan", + "Vanuatu", + "Venezuela", + "Vietnam", + "Yemen", + "Zambia", + "Zimbabwe", +]; + +export const COUNTRIES_FA = [ + "افغانستان", + "آلبانی", + "الجزایر", + "آندورا", + "آنگولا", + "آنتیگوا و باربودا", + "آرژانتین", + "ارمنستان", + "استرالیا", + "اتریش", + "آذربایجان", + "باهاما", + "بحرین", + "بنگلادش", + "باربادوس", + "بلاروس", + "بلژیک", + "بلیز", + "بنین", + "بوتان", + "بولیوی", + "بوسنی و هرزگوین", + "بوتسوانا", + "برزیل", + "برونئی", + "بلغارستان", + "بورکینافاسو", + "بوروندی", + "کیپ ورد", + "کامبوج", + "کامرون", + "کانادا", + "جمهوری آفریقای مرکزی", + "چاد", + "شیلی", + "چین", + "کلمبیا", + "کومور", + "کنگو", + "کاستاریکا", + "کرواسی", + "کوبا", + "قبرس", + "جمهوری چک", + "جمهوری دموکراتیک کنگو", + "دانمارک", + "جیبوتی", + "دومینیکا", + "جمهوری دومینیکن", + "اکوادور", + "مصر", + "السالوادور", + "گینه استوایی", + "اریتره", + "استونی", + "اسواتینی", + "اتیوپی", + "فیجی", + "فنلاند", + "فرانسه", + "گابن", + "Gambia", + "گرجستان", + "آلمان", + "غنا", + "یونان", + "گرنادا", + "گواتمالا", + "گینه", + "گینه بیسائو", + "گویان", + "هایتی", + "واتیکان", + "هندوراس", + "مجارستان", + "ایسلند", + "هند", + "اندونزی", + "ایران", + "عراق", + "ایرلند", + "ایتالیا", + "ساحل عاج", + "جامائیکا", + "ژاپن", + "اردن", + "قزاقستان", + "کنیا", + "کیریباتی", + "کویت", + "قرقیزستان", + "لائوس", + "لتونی", + "لبنان", + "لسوتو", + "لیبریا", + "لیبی", + "لیختن‌اشتاین", + "لیتوانی", + "لوکزامبورگ", + "ماداگاسکار", + "مالاوی", + "مالزی", + "مالدیو", + "مالی", + "مالت", + "جزایر مارشال", + "موریتانی", + "موریس", + "مکزیک", + "میکرونزی", + "مولداوی", + "موناکو", + "مغولستان", + "مونته‌نگرو", + "مراکش", + "موزامبیک", + "میانمار", + "نامیبیا", + "نائورو", + "نپال", + "هلند", + "نیوزیلند", + "نیکاراگوئه", + "نیجر", + "نیجریه", + "کره شمالی", + "مقدونیه شمالی", + "نروژ", + "عمان", + "پاکستان", + "پالائو", + "فلسطین", + "پاناما", + "پاپوآ گینه نو", + "پاراگوئه", + "پرو", + "فیلیپین", + "لهستان", + "پرتغال", + "قطر", + "رومانی", + "روسیه", + "رواندا", + "سنت کیتس و نویس", + "سنت لوسیا", + "سنت وینسنت و گرنادین‌ها", + "ساموآ", + "سان مارینو", + "سائوتومه و پرنسیپ", + "عربستان سعودی", + "سنگال", + "صربستان", + "سیشل", + "سیرالئون", + "سنگاپور", + "اسلواکی", + "اسلوونی", + "جزایر سلیمان", + "سومالی", + "آفریقای جنوبی", + "کره جنوبی", + "سودان جنوبی", + "اسپانیا", + "سری‌لانکا", + "سودان", + "سورینام", + "سوئد", + "سوئیس", + "سوریه", + "تاجیکستان", + "تانزانیا", + "تایلند", + "تیمور شرقی", + "توگو", + "تونگا", + "ترینیداد و توباگو", + "تونس", + "ترکیه", + "ترکمنستان", + "تووالو", + "اوگاندا", + "اوکراین", + "امارات متحده عربی (UAE)", + "بریتانیا (UK)", + "ایالات متحده آمریکا (US)", + "اروگوئه", + "ازبکستان", + "وانواتو", + "ونزوئلا", + "ویتنام", + "یمن", + "زامبیا", + "زیمبابوه", +]; + +export function getCountryList(locale: string): string[] { + const normalized = String(locale || "en").toLowerCase(); + if (normalized === "fa" || normalized === "fa-ir") { + return COUNTRIES_FA; + } + return COUNTRIES_EN; +} diff --git a/src/data/glasser-fallback.ts b/src/data/glasser-fallback.ts index d2304be..1bada8a 100644 --- a/src/data/glasser-fallback.ts +++ b/src/data/glasser-fallback.ts @@ -8,176 +8,176 @@ export const glasserFallbackQuestions: GlasserFallbackQuestion[] = [ { question_number: 1, factor_code: "S", - text: "مسایلی مثل پس انداز، مخارج زندگی، مسکن، آینده شغلی و.. تا چه اندازه ذهن شما را به خود مشغول می دارد؟" + text: "مسایلی مثل پس انداز، مخارج زندگی، مسکن، آینده شغلی و.. تا چه اندازه ذهن شما را به خود مشغول می دارد؟", }, { question_number: 2, factor_code: "S", - text: "تا چه اندازه به سلامت جسمانی، بهداشت و احتمال ابتلا به بیماری فکر میکنید؟" + text: "تا چه اندازه به سلامت جسمانی، بهداشت و احتمال ابتلا به بیماری فکر میکنید؟", }, { question_number: 3, factor_code: "S", - text: "شدت میل جنسی خود را چگونه ارزیابی میکنید؟" + text: "شدت میل جنسی خود را چگونه ارزیابی میکنید؟", }, { question_number: 4, factor_code: "S", - text: "در انجام کارها و اقدامات مخاطره انگیز تا چه اندازه محتاطانه عمل میکنید؟" + text: "در انجام کارها و اقدامات مخاطره انگیز تا چه اندازه محتاطانه عمل میکنید؟", }, { question_number: 5, factor_code: "S", - text: "از روبه رویی با تجارب جدید و شروع راه های ناشناخته تا چه اندازه اجتناب میکنید؟" + text: "از روبه رویی با تجارب جدید و شروع راه های ناشناخته تا چه اندازه اجتناب میکنید؟", }, { question_number: 6, factor_code: "S", - text: "از نظر دوستان و همکاران خود چقدر وقت شناس با نظم و ترتیب و دقیق هستید؟" + text: "از نظر دوستان و همکاران خود چقدر وقت شناس با نظم و ترتیب و دقیق هستید؟", }, { question_number: 7, factor_code: "S", - text: "تا چه اندازه امنیت شغلی و درآمد ثابت برایتان اهمیت دارد؟" + text: "تا چه اندازه امنیت شغلی و درآمد ثابت برایتان اهمیت دارد؟", }, { question_number: 8, factor_code: "L", - text: "احساس می کنید به چه میزان عشق، صمیمیت و مهرورزی نیاز دارید؟" + text: "احساس می کنید به چه میزان عشق، صمیمیت و مهرورزی نیاز دارید؟", }, { question_number: 9, factor_code: "L", - text: "تا چه اندازه رفاه و سعادت انسان های دیگر برایتان مهم است؟" + text: "تا چه اندازه رفاه و سعادت انسان های دیگر برایتان مهم است؟", }, { question_number: 10, factor_code: "L", - text: "تا چه اندازه تمایل دارید تجارب شخصی، احساسات عمیق و اسرار خود را با دیگران در میان بگذارید؟" + text: "تا چه اندازه تمایل دارید تجارب شخصی، احساسات عمیق و اسرار خود را با دیگران در میان بگذارید؟", }, { question_number: 11, factor_code: "L", - text: "در ایجاد صمیمیت و برقراری ارتباط عاطفی با دیگران چقدر پیش قدم می شوید؟" + text: "در ایجاد صمیمیت و برقراری ارتباط عاطفی با دیگران چقدر پیش قدم می شوید؟", }, { question_number: 12, factor_code: "L", - text: "تا چه اندازه از دیدن، وقت گذراندن و گفتگو با دوستان و آشنایان خود لذت می برید؟" + text: "تا چه اندازه از دیدن، وقت گذراندن و گفتگو با دوستان و آشنایان خود لذت می برید؟", }, { question_number: 13, factor_code: "L", - text: "میزان بخشندگی، گذشت و فراموش کردن خطای دیگران را در خود چگونه ارزیابی می کنید؟" + text: "میزان بخشندگی، گذشت و فراموش کردن خطای دیگران را در خود چگونه ارزیابی می کنید؟", }, { question_number: 14, factor_code: "L", - text: "تا چه اندازه به ایجاد و حفظ روابط دوستانه، صمیمی و پایدار با دیگران علاقه مند هستید؟" + text: "تا چه اندازه به ایجاد و حفظ روابط دوستانه، صمیمی و پایدار با دیگران علاقه مند هستید؟", }, { question_number: 15, factor_code: "P", - text: "تا چه اندازه تمایل دارید رهبری گروه‌ها، هدایت پروژه‌ها یا مدیریت امور را بر عهده بگیرید؟" + text: "تا چه اندازه تمایل دارید رهبری گروه‌ها، هدایت پروژه‌ها یا مدیریت امور را بر عهده بگیرید؟", }, { question_number: 16, factor_code: "P", - text: "رسیدن به موفقیت، موقعیت اجتماعی ممتاز و جایگاه برتر تا چه حد برایتان اهمیت دارد؟" + text: "رسیدن به موفقیت، موقعیت اجتماعی ممتاز و جایگاه برتر تا چه حد برایتان اهمیت دارد؟", }, { question_number: 17, factor_code: "P", - text: "در صورت بروز نقد، مخالفت یا اشتباه از سوی دیگران، تا چه حد رفتار تند، قاطع یا اصلاحی نشان می‌دهید؟" + text: "در صورت بروز نقد، مخالفت یا اشتباه از سوی دیگران، تا چه حد رفتار تند، قاطع یا اصلاحی نشان می‌دهید؟", }, { question_number: 18, factor_code: "P", - text: "تا چه اندازه تمایل دارید کارها دقیقاً طبق نظرات، استانداردها و روش‌های شما انجام شوند؟" + text: "تا چه اندازه تمایل دارید کارها دقیقاً طبق نظرات، استانداردها و روش‌های شما انجام شوند؟", }, { question_number: 19, factor_code: "P", - text: "در بحث‌ها و گفتگوها تا چه حد اصرار دارید حرف و نظر خود را به عنوان نظر درست به اثبات برسانید؟" + text: "در بحث‌ها و گفتگوها تا چه حد اصرار دارید حرف و نظر خود را به عنوان نظر درست به اثبات برسانید؟", }, { question_number: 20, factor_code: "P", - text: "وقتی احساس می‌کنید حق با شماست، تا چه اندازه حاضر به رقابت یا پافشاری بر روی خواسته‌هایتان هستید؟" + text: "وقتی احساس می‌کنید حق با شماست، تا چه اندازه حاضر به رقابت یا پافشاری بر روی خواسته‌هایتان هستید؟", }, { question_number: 21, factor_code: "P", - text: "دیدگاه شما نسبت به یادگیری، کسب دانش و بالا بردن اطلاعات تخصصی چیست؟" + text: "دیدگاه شما نسبت به یادگیری، کسب دانش و بالا بردن اطلاعات تخصصی چیست؟", }, { question_number: 22, factor_code: "Fr", - text: "تا چه اندازه تمایل دارید بدون دخالت، نظارت یا دستور دیگران اهداف شخصی خود را دنبال کنید؟" + text: "تا چه اندازه تمایل دارید بدون دخالت، نظارت یا دستور دیگران اهداف شخصی خود را دنبال کنید؟", }, { question_number: 23, factor_code: "Fr", - text: "در برابر احساس محدودیت، اجبار یا رعایت قوانین دست و پا گیر تا چه حد واکنش نشان می‌دهید؟" + text: "در برابر احساس محدودیت، اجبار یا رعایت قوانین دست و پا گیر تا چه حد واکنش نشان می‌دهید؟", }, { question_number: 24, factor_code: "Fr", - text: "میزان تمایل شما به داشتن حریم خصوصی، زمان تنهایی و استقلال در تصمیم‌گیری‌ها چقدر است؟" + text: "میزان تمایل شما به داشتن حریم خصوصی، زمان تنهایی و استقلال در تصمیم‌گیری‌ها چقدر است؟", }, { question_number: 25, factor_code: "Fr", - text: "تا چه اندازه رهایی از قید و بندها و برنامه‌های فشرده را ترجیح می‌دهید؟" + text: "تا چه اندازه رهایی از قید و بندها و برنامه‌های فشرده را ترجیح می‌دهید؟", }, { question_number: 26, factor_code: "Fr", - text: "در مواجهه با فشار روانی یا استرس، تا چه حد نیاز دارید فضا و وقت مستقل داشته باشید؟" + text: "در مواجهه با فشار روانی یا استرس، تا چه حد نیاز دارید فضا و وقت مستقل داشته باشید؟", }, { question_number: 27, factor_code: "Fr", - text: "تا چه اندازه تمایل دارید مسیر زندگی، سبک پوشش یا رفتارهای خود را بر اساس معیارهای فردی انتخاب کنید؟" + text: "تا چه اندازه تمایل دارید مسیر زندگی، سبک پوشش یا رفتارهای خود را بر اساس معیارهای فردی انتخاب کنید؟", }, { question_number: 28, factor_code: "Fr", - text: "چقدر برای آزادی اندیشه و ابراز دیدگاه‌های غیرمعمول اهمیت قائل هستید؟" + text: "چقدر برای آزادی اندیشه و ابراز دیدگاه‌های غیرمعمول اهمیت قائل هستید؟", }, { question_number: 29, factor_code: "Fu", - text: "تا چه اندازه اهل شوخ‌طبعی، خنده، لطیفه‌گویی و ایجاد فضای شاد هستید؟" + text: "تا چه اندازه اهل شوخ‌طبعی، خنده، لطیفه‌گویی و ایجاد فضای شاد هستید؟", }, { question_number: 30, factor_code: "Fu", - text: "چقدر زمان و هزینه برای سرگرمی، تفریحات بی‌دغدغه و فعالیت‌های مفرح اختصاص می‌دهید؟" + text: "چقدر زمان و هزینه برای سرگرمی، تفریحات بی‌دغدغه و فعالیت‌های مفرح اختصاص می‌دهید؟", }, { question_number: 31, factor_code: "Fu", - text: "تا چه اندازه از کارهای خلاقانه، هنری، بازی و سرگرمی لذت می‌برید؟" + text: "تا چه اندازه از کارهای خلاقانه، هنری، بازی و سرگرمی لذت می‌برید؟", }, { question_number: 32, factor_code: "Fu", - text: "چقدر قادر هستید لحظات سخت و جدیت زندگی را با نگاهی سبک، طنزآمیز و مثبت سپری کنید؟" + text: "چقدر قادر هستید لحظات سخت و جدیت زندگی را با نگاهی سبک، طنزآمیز و مثبت سپری کنید؟", }, { question_number: 33, factor_code: "Fu", - text: "تمایل شما به شرکت در دورهمی‌ها، برنامه‌های تفریحی و سفر با دوستان چقدر است؟" + text: "تمایل شما به شرکت در دورهمی‌ها، برنامه‌های تفریحی و سفر با دوستان چقدر است؟", }, { question_number: 34, factor_code: "Fu", - text: "چقدر برای داشتن سرگرمی‌ها (هابی) و فعالیت‌های غیرکاری وقت می‌گذارید؟" + text: "چقدر برای داشتن سرگرمی‌ها (هابی) و فعالیت‌های غیرکاری وقت می‌گذارید؟", }, { question_number: 35, factor_code: "Fu", - text: "از یادگیری چیزهای جدید همراه با بازی، هیجان و نشاط چقدر استقبال می‌کنید؟" - } + text: "از یادگیری چیزهای جدید همراه با بازی، هیجان و نشاط چقدر استقبال می‌کنید؟", + }, ]; diff --git a/src/data/languages.ts b/src/data/languages.ts new file mode 100644 index 0000000..995a198 --- /dev/null +++ b/src/data/languages.ts @@ -0,0 +1,157 @@ +export const LANGUAGES_EN = [ + "Afrikaans", + "Albanian", + "Amharic", + "Arabic", + "Armenian", + "Azerbaijani", + "Bengali", + "Bosnian", + "Bulgarian", + "Burmese", + "Catalan", + "Chinese", + "Croatian", + "Czech", + "Danish", + "Dutch", + "English", + "Estonian", + "Finnish", + "French", + "Georgian", + "German", + "Greek", + "Gujarati", + "Hausa", + "Hebrew", + "Hindi", + "Hungarian", + "Icelandic", + "Indonesian", + "Irish", + "Italian", + "Japanese", + "Kashmiri", + "Kazakh", + "Khmer", + "Korean", + "Kyrgyz", + "Latvian", + "Lithuanian", + "Macedonian", + "Malay", + "Maltese", + "Mongolian", + "Nepali", + "Norwegian", + "Pashto", + "Persian (Farsi)", + "Polish", + "Portuguese", + "Punjabi", + "Romanian", + "Russian", + "Serbian", + "Sinhala", + "Slovak", + "Slovenian", + "Somali", + "Spanish", + "Swahili", + "Swedish", + "Tajik", + "Tamil", + "Telugu", + "Thai", + "Turkish", + "Turkmen", + "Ukrainian", + "Urdu", + "Urdu Roman (Latin)", + "Uzbek", + "Vietnamese", + "Other", +]; + +export const LANGUAGES_FA = [ + "آذربایجانی", + "آفریکانس", + "آلمانی", + "آلبانیایی", + "امهری", + "اردو", + "اردو (لاتین)", + "ارمنی", + "ازبکی", + "اسپانیایی", + "استونیایی", + "اسلواکی", + "اسلوونیایی", + "انگلیسی", + "اندونزیایی", + "اوکراینی", + "ایتالیایی", + "ایرلندی", + "ایسلندی", + "بنگالی", + "بوسنیایی", + "بلغاری", + "پشتو", + "پنجابی", + "پرتغالی", + "تاجیکی", + "تامیلی", + "تایلندی", + "تلوگو", + "ترکی", + "ترکمنی", + "چکی", + "چینی", + "دانمارکی", + "روسی", + "رومانیایی", + "ژاپنی", + "سواحیلی", + "سوئدی", + "سینهالی", + "صربی", + "سومالیایی", + "عربی", + "عبری", + "فارسی", + "فرانسوی", + "فنلاندی", + "قزاقی", + "قرقیزی", + "کاتالان", + "کره‌ای", + "کرواتی", + "کشمیری", + "گجراتی", + "گرجی", + "لتونیایی", + "لیتوانیایی", + "لهستانی", + "مالایی", + "مالتی", + "مجاری", + "مقدونیه‌ای", + "مغولی", + "میانماری (برمه‌ای)", + "نپالی", + "نروژی", + "هلندی", + "ویتنامی", + "هندی", + "هوسا", + "سایر", +]; + +export function getLanguageList(locale: string): string[] { + const normalized = String(locale || "en").toLowerCase(); + if (normalized === "fa" || normalized === "fa-ir") { + return LANGUAGES_FA; + } + return LANGUAGES_EN; +} diff --git a/src/data/nationalities.ts b/src/data/nationalities.ts new file mode 100644 index 0000000..3eeb5f4 --- /dev/null +++ b/src/data/nationalities.ts @@ -0,0 +1,283 @@ +export const NATIONALITIES_EN = [ + "Afghan", + "Albanian", + "Algerian", + "American (US)", + "Andorran", + "Angolan", + "Antiguan", + "Argentinian", + "Armenian", + "Australian", + "Austrian", + "Azerbaijani", + "Bahamian", + "Bahraini", + "Bangladeshi", + "Barbadian", + "Belarusian", + "Belgian", + "Belizean", + "Beninese", + "Bhutanese", + "Bolivian", + "Bosnian", + "Botswanan", + "Brazilian", + "British (UK)", + "Bruneian", + "Bulgarian", + "Burkinabè", + "Burmese", + "Burundian", + "Cabo Verdean", + "Cambodian", + "Cameroonian", + "Canadian", + "Central African", + "Chadian", + "Chilean", + "Chinese", + "Colombian", + "Comorian", + "Congolese", + "Costa Rican", + "Croatian", + "Cuban", + "Cypriot", + "Czech", + "Danish", + "Djiboutian", + "Dominican", + "Dutch", + "Ecuadorian", + "Egyptian", + "Emirati (UAE)", + "Equatorial Guinean", + "Eritrean", + "Estonian", + "Ethiopian", + "Fijian", + "Filipino", + "Finnish", + "French", + "Gabonese", + "Gambian", + "Georgian", + "German", + "Ghanaian", + "Greek", + "Grenadian", + "Guatemalan", + "Guinean", + "Guyanese", + "Haitian", + "Honduran", + "Hungarian", + "Icelandic", + "Indian", + "Indonesian", + "Iranian", + "Iraqi", + "Irish", + "Italian", + "Ivorian", + "Jamaican", + "Japanese", + "Jordanian", + "Kazakhstani", + "Kenyan", + "Kuwaiti", + "Kyrgyzstani", + "Laotian", + "Latvian", + "Lebanese", + "Liberian", + "Libyan", + "Liechtensteiner", + "Lithuanian", + "Luxembourger", + "Macedonian", + "Malagasy", + "Malawian", + "Malaysian", + "Maldivian", + "Malian", + "Maltese", + "Mauritanian", + "Mauritian", + "Mexican", + "Micronesian", + "Moldovan", + "Monégasque", + "Mongolian", + "Montenegrin", + "Moroccan", + "Mozambican", + "Namibian", + "Nauruan", + "Nepalese", + "New Zealander", + "Nicaraguan", + "Nigerien", + "Nigerian", + "North Korean", + "Norwegian", + "Omani", + "Pakistani", + "Palestinian", + "Panamanian", + "Papua New Guinean", + "Paraguayan", + "Peruvian", + "Polish", + "Portuguese", + "Qatari", + "Romanian", + "Russian", + "Rwandan", + "Saudi", + "Senegalese", + "Serbian", + "Seychellois", + "Sierra Leonean", + "Singaporean", + "Slovak", + "Slovenian", + "Somali", + "South African", + "South Korean", + "Spanish", + "Sri Lankan", + "Sudanese", + "Surinamese", + "Swazi", + "Swedish", + "Swiss", + "Syrian", + "Tajikistani", + "Tanzanian", + "Thai", + "Togolese", + "Tongan", + "Tunisian", + "Turkish", + "Turkmen", + "Ugandan", + "Ukrainian", + "Uruguayan", + "Uzbekistani", + "Venezuelan", + "Vietnamese", + "Yemeni", + "Zambian", + "Zimbabwean", + "Other", +]; + +export const NATIONALITIES_FA = [ + "آذربایجانی", + "آرژانتینی", + "آلمانی", + "آلبانیایی", + "آمریکایی (US)", + "آندورایی", + "آنگولایی", + "اتریشی", + "اتیوپیایی", + "ارمنی", + "اردنی", + "اروگوئه‌ای", + "ازبکستانی", + "اسپانیایی", + "استرالیایی", + "استونیایی", + "اسلواکی", + "اسلوونیایی", + "افغانستانی", + "الجزایری", + "اماراتی (UAE)", + "اندونزیایی", + "انگلیسی", + "ایتالیایی", + "ایرانی", + "ایرلندی", + "بحرینی", + "برزیلی", + "بریتانیایی (UK)", + "بلغارستانی", + "بنگلادشی", + "بلژیکی", + "بلاروسی", + "بوسنیایی", + "پاکستانی", + "پرتغالی", + "پروایی", + "تاجیکستانی", + "تایلندی", + "ترکیه‌ای", + "تونسی", + "چکی", + "چینی", + "دانمارکی", + "روسی", + "رومانیایی", + "ژاپنی", + "سری‌لانکایی", + "سعودی", + "سنگاپوری", + "سوری", + "سومالیایی", + "سوئدی", + "سوئیسی", + "شیلیایی", + "عراقی", + "عربستانی", + "عمانی", + "فرانسوی", + "فلسطینی", + "فیلیپینی", + "فنلاندی", + "قزاقستانی", + "قطری", + "قرقیزستانی", + "کره جنوبی", + "کره شمالی", + "کلمبیایی", + "کامرونی", + "کانادایی", + "کنگویی", + "کوبایی", + "کویتی", + "کنیایی", + "گرجستانی", + "لبنانی", + "لهستانی", + "لیبیایی", + "لیتوانیایی", + "مالزیایی", + "مالدیوی", + "مراکشی", + "مصر", + "مکزیکی", + "مولداویایی", + "مغولی", + "نامیبیاایی", + "نپالی", + "نروژی", + "نیوزیلندی", + "نیجریه‌ای", + "هلندی", + "ونزوئلایی", + "ویتنامی", + "یمنی", + "سایر", +]; + +export function getNationalityList(locale: string): string[] { + const normalized = String(locale || "en").toLowerCase(); + if (normalized === "fa" || normalized === "fa-ir") { + return NATIONALITIES_FA; + } + return NATIONALITIES_EN; +} diff --git a/src/data/question-data.ts b/src/data/question-data.ts index 9a4a78f..a2efd4c 100644 --- a/src/data/question-data.ts +++ b/src/data/question-data.ts @@ -1,7 +1,7 @@ -import type { MarriageGender } from "@/hooks/marriage/types"; -import { defaultLocale, type Locale } from "@/translations/config"; import enQuestions from "@/data/questions/en.json"; import faQuestions from "@/data/questions/fa.json"; +import type { MarriageGender } from "@/hooks/marriage/types"; +import { defaultLocale, type Locale } from "@/translations/config"; export const bookingTerms = [ "You will be contacted by your consultant.", @@ -108,7 +108,11 @@ function mapQuestionListItem(item: RawQuestionListItem): QuestionListItem { } export function getQuestionListItems(locale: Locale = defaultLocale) { - const items = questionsByLocale[locale] ?? questionsByLocale[defaultLocale] ?? questionsByLocale.en ?? []; + const items = + questionsByLocale[locale] ?? + questionsByLocale[defaultLocale] ?? + questionsByLocale.en ?? + []; return items.map(mapQuestionListItem); } diff --git a/src/data/questions/en.json b/src/data/questions/en.json index 86c6d6d..1155820 100644 --- a/src/data/questions/en.json +++ b/src/data/questions/en.json @@ -9,32 +9,15 @@ "description": "Collects personal details to start the marriage application flow.", "questions": [ { - "title": "First Name", + "title": "Full Name", "type": "text", "required": true, "extras": { - "placeHolder": "e.g. Sara", - "range": [ - 0, - 0 - ], - "options": [] - }, - "private": true - }, - { - "title": "Last Name", - "type": "text", - "required": true, - "extras": { - "placeHolder": "e.g. Ahmadi", - "range": [ - 0, - 0 - ], + "placeHolder": "Sarah Smith", + "range": [0, 0], "options": [] }, - "private": true + "private": false }, { "title": "Date of Birth", @@ -42,10 +25,7 @@ "required": true, "extras": { "placeHolder": "YYYY-MM-DD", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } }, @@ -55,36 +35,17 @@ "required": false, "extras": { "placeHolder": "", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } }, { - "title": "Birth City", - "type": "text", + "title": "Birthplace", + "type": "birthplace", "required": true, "extras": { - "placeHolder": "e.g. Tehran", - "range": [ - 0, - 0 - ], - "options": [] - } - }, - { - "title": "Country of Birth", - "type": "dropdown", - "required": true, - "extras": { - "placeHolder": "Select country", - "range": [ - 0, - 0 - ], + "placeHolder": "City, region, or neighborhood", + "range": [0, 0], "options": [ "Iran", "United States", @@ -104,8 +65,7 @@ "Norway", "Australia", "Other" - ], - "noSearch": true + ] } }, { @@ -114,10 +74,7 @@ "required": true, "extras": { "placeHolder": "Select country", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Iran", "United States", @@ -146,42 +103,19 @@ "type": "text", "required": true, "extras": { - "placeHolder": "e.g. Persian", - "range": [ - 0, - 0 - ], + "placeHolder": "British", + "range": [0, 0], "options": [] } }, - { - "title": "Skin Color", - "type": "radio", - "required": true, - "extras": { - "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], - "options": [ - "Fair / White", - "Light Tan / Wheatish", - "Dark Tan / Brown", - "Dark / Black" - ] - } - }, + { "title": "Mother Tongue", "type": "dropdown", "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Persian", "English", @@ -204,10 +138,7 @@ "required": false, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Persian", "English", @@ -240,11 +171,8 @@ "type": "phone", "required": true, "extras": { - "placeHolder": "e.g. +98 912 123 4567", - "range": [ - 0, - 0 - ], + "placeHolder": "+44 7911 123456", + "range": [0, 0], "options": [] }, "private": true @@ -254,25 +182,20 @@ "type": "text", "required": true, "extras": { - "placeHolder": "e.g. user@example.com", - "range": [ - 0, - 0 - ], + "placeHolder": "user@example.com", + "range": [0, 0], "options": [] }, "private": true }, { - "title": "Current Country of Residence", - "type": "dropdown", + "title": "Current Residence", + "type": "birthplace", "required": true, + "tooltip": "A precise address is not required. Just the general area of where you live is sufficient, such as the city, region, neighborhood, or nearest major city.", "extras": { - "placeHolder": "Select country", - "range": [ - 0, - 0 - ], + "placeHolder": "City, region, or neighborhood", + "range": [0, 0], "options": [ "Iran", "United States", @@ -292,46 +215,17 @@ "Norway", "Australia", "Other" - ], - "noSearch": true - } - }, - { - "title": "Current City / State of Residence", - "type": "text", - "required": true, - "extras": { - "placeHolder": "e.g. Tehran", - "range": [ - 0, - 0 - ], - "options": [] - } - }, - { - "title": "Approximate Location of Current Residence", - "type": "text", - "required": true, - "extras": { - "placeHolder": "e.g. West Tehran", - "range": [ - 0, - 0 - ], - "options": [] + ] } }, + { "title": "Residence Status", "type": "dropdown", "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Citizen / National", "Permanent Residence", @@ -350,10 +244,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Fully flexible; moving to another city or country is not a problem.", "Willing to move to another city, but only within my current country.", @@ -368,17 +259,12 @@ "type": "text", "required": false, "requiredWhen": { - "genders": [ - "female" - ], + "genders": ["female"], "maxAge": 26 }, "extras": { - "placeHolder": "e.g. Sara Ahmadi", - "range": [ - 0, - 0 - ], + "placeHolder": "Sarah Smith", + "range": [0, 0], "options": [] }, "private": true @@ -388,17 +274,12 @@ "type": "dropdown", "required": false, "requiredWhen": { - "genders": [ - "female" - ], + "genders": ["female"], "maxAge": 26 }, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Father", "Mother", @@ -419,17 +300,12 @@ "type": "phone", "required": false, "requiredWhen": { - "genders": [ - "female" - ], + "genders": ["female"], "maxAge": 26 }, "extras": { - "placeHolder": "e.g. +98 912 123 4567", - "range": [ - 0, - 0 - ], + "placeHolder": "+44 7911 123456", + "range": [0, 0], "options": [] }, "private": true @@ -450,11 +326,8 @@ "type": "number", "required": true, "extras": { - "placeHolder": "e.g. 175", - "range": [ - 50, - 300 - ], + "placeHolder": "175", + "range": [50, 300], "options": [] }, "private": true @@ -464,25 +337,34 @@ "type": "number", "required": true, "extras": { - "placeHolder": "e.g. 70", - "range": [ - 20, - 600 - ], + "placeHolder": "70", + "range": [20, 600], "options": [] }, "private": true }, + { + "title": "Skin Color", + "type": "radio", + "required": true, + "extras": { + "placeHolder": "Select one option", + "range": [0, 0], + "options": [ + "Fair / White", + "Light Tan / Wheatish", + "Dark Tan / Brown", + "Dark / Black" + ] + } + }, { "title": "Physical Health Status", "type": "radio", "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "I am in perfect health.", "I have a specific or chronic illness.", @@ -497,10 +379,7 @@ "tooltip": "Provide more details if you have any health conditions or limitations.", "extras": { "placeHolder": "Enter details here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } }, @@ -510,10 +389,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "I have no specific problems.", "I have a history of counseling and treatment.", @@ -526,11 +402,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "e.g. Insulin, etc.", - "range": [ - 0, - 0 - ], + "placeHolder": "Insulin, etc.", + "range": [0, 0], "options": [] }, "private": true @@ -552,10 +425,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Below High School", "High School Diploma", @@ -575,11 +445,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "e.g. Computer Science", - "range": [ - 0, - 0 - ], + "placeHolder": "Computer Science", + "range": [0, 0], "options": [] } }, @@ -589,10 +456,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Full-time Employed", "Part-time Employed", @@ -613,11 +477,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "e.g. Software Engineer", - "range": [ - 0, - 0 - ], + "placeHolder": "Software Engineer", + "range": [0, 0], "options": [] } }, @@ -626,11 +487,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "e.g. Tehran, Remote", - "range": [ - 0, - 0 - ], + "placeHolder": "London, Remote", + "range": [0, 0], "options": [] } }, @@ -639,11 +497,8 @@ "type": "number", "required": true, "extras": { - "placeHolder": "e.g. 2500 USD, 1800 EUR", - "range": [ - 0, - 0 - ], + "placeHolder": "3500 GBP, 4000 USD", + "range": [0, 0], "options": [] }, "private": true @@ -654,10 +509,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Stable and reliable income", "Income is variable", @@ -675,10 +527,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Fully able to support expenses", "Able to support the main portion of expenses", @@ -696,10 +545,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Homeowner", "Renting independently", @@ -718,10 +564,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Have a personal home for living together", "Can buy a home", @@ -737,10 +580,7 @@ "required": false, "extras": { "placeHolder": "Enter your explanation here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] }, "private": true @@ -761,11 +601,8 @@ "type": "number", "required": true, "extras": { - "placeHolder": "e.g. 2", - "range": [ - 0, - 20 - ], + "placeHolder": "2", + "range": [0, 20], "options": [] } }, @@ -775,10 +612,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Both parents are alive", "Father has passed away", @@ -793,10 +627,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Living together", "Separated / Divorced", @@ -813,10 +644,7 @@ "description": "Please select the option that best describes the general atmosphere and lifestyle of your family.", "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Religious and strictly observant", "Religious (committed to duties)", @@ -831,16 +659,8 @@ "required": false, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], - "options": [ - "Weak", - "Average", - "Good", - "Prosperous" - ] + "range": [0, 0], + "options": ["Weak", "Average", "Good", "Prosperous"] } }, { @@ -849,10 +669,7 @@ "required": false, "extras": { "placeHolder": "Enter details here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } } @@ -873,10 +690,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Single; never married", "Failed engagement / Annulled marriage; without living together", @@ -901,11 +715,8 @@ } }, "extras": { - "placeHolder": "e.g., 3 years", - "range": [ - 0, - 0 - ], + "placeHolder": "3 years", + "range": [0, 0], "options": [] }, "private": true @@ -925,10 +736,7 @@ }, "extras": { "placeHolder": "Enter details here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] }, "private": true @@ -939,10 +747,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "No children", "Have children living with me", @@ -958,18 +763,12 @@ "logic": { "dependsOn": { "title": "Current Marital Status", - "values": [ - "Divorced; after living together", - "Widowed" - ] + "values": ["Divorced; after living together", "Widowed"] } }, "extras": { - "placeHolder": "e.g., 2", - "range": [ - 0, - 10 - ], + "placeHolder": "2", + "range": [0, 10], "options": [] } }, @@ -979,10 +778,7 @@ "required": false, "extras": { "placeHolder": "Enter details here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } } @@ -1002,11 +798,8 @@ "type": "text", "required": true, "extras": { - "placeHolder": "e.g., Ayatollah Sistani", - "range": [ - 0, - 0 - ], + "placeHolder": "Ayatollah Sistani", + "range": [0, 0], "options": [] } }, @@ -1016,10 +809,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Always committed, preferably at the earliest time", "Always committed, but not necessarily at the earliest time", @@ -1035,10 +825,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Fully committed", "Do not fast for religious or medical reasons", @@ -1054,10 +841,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Full Islamic covering (Maximum Hijab) - Abaya, Jilbab, Chador, or Niqab with full observance.", "Full Hijab with loose modest clothing - Wide and long outfits with full hair covering.", @@ -1073,16 +857,11 @@ "type": "radio", "required": false, "audience": { - "genders": [ - "female" - ] + "genders": ["female"] }, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Do not wear makeup at all", "Only very light makeup", @@ -1096,10 +875,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Religion and politics are inseparable; my spouse must share this outlook.", "Religion and politics are inseparable, but active engagement is not a requirement for my spouse.", @@ -1117,10 +893,7 @@ "required": false, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Supporter of the current government; serious opposition from my spouse is a red line.", "Supporter of the current government, but a difference in view is not a red line.", @@ -1138,10 +911,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Very formal and limited (Only as necessary) - Avoid any unnecessary conversation or jokes.", "Respectful and conventional (No intimacy) - Polite interactions with clear personal boundaries.", @@ -1156,10 +926,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Do not smoke at all", "Occasional / Recreational", @@ -1175,10 +942,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Do not smoke hookah at all", "Occasional / Recreational", @@ -1194,10 +958,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Do not use at all", "Occasional / Recreational", @@ -1213,10 +974,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Do not consume at all", "Alcohol is a serious red line for me", @@ -1232,10 +990,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Never used", "Used in the past, but not anymore", @@ -1251,10 +1006,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Do not listen to any music", "Only listen to Nasheeds, Acapella, religious, or instrument-free music", @@ -1269,10 +1021,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "No ceremony or very simple", "Strictly religious and gender-segregated", @@ -1290,10 +1039,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 1, - 10 - ], + "range": [1, 10], "options": [ "Calm and Introverted", "Social and Extroverted", @@ -1321,10 +1067,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 1, - 15 - ], + "range": [1, 15], "options": [ "Quran Recitation and Religious Studies", "Mosque and Religious Gatherings", @@ -1353,10 +1096,7 @@ "required": false, "extras": { "placeHolder": "Enter details here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } } @@ -1397,11 +1137,8 @@ "required": true, "description": "from [number] to [number] years", "extras": { - "placeHolder": "e.g. 25-30", - "range": [ - 0, - 0 - ], + "placeHolder": "25-30", + "range": [0, 0], "options": [] }, "private": true @@ -1412,10 +1149,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Under 160", @@ -1434,10 +1168,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Slim", @@ -1456,10 +1187,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Fair / White", @@ -1477,11 +1205,8 @@ "required": false, "description": "Optional text field", "extras": { - "placeHolder": "e.g. Persian, Turkish, etc.", - "range": [ - 0, - 0 - ], + "placeHolder": "English, French, etc.", + "range": [0, 0], "options": [] }, "private": true @@ -1492,10 +1217,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Minimum High School", @@ -1515,10 +1237,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Employed", @@ -1538,10 +1257,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Never married only; history is a red line", "Never married preferred, but open to special cases", @@ -1557,10 +1273,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Will not accept", "Accept in special conditions", @@ -1575,16 +1288,11 @@ "type": "dropdown", "required": true, "audience": { - "genders": [ - "male" - ] + "genders": ["male"] }, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Full Islamic covering mandatory", "Sharia Hijab mandatory, type doesn't matter", @@ -1601,16 +1309,11 @@ "type": "dropdown", "required": true, "audience": { - "genders": [ - "female" - ] + "genders": ["female"] }, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Formal, dignified, and religious", "Simple, neat, and modest", @@ -1628,10 +1331,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Must intend to continue", @@ -1649,10 +1349,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Must be employed", @@ -1671,10 +1368,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Doesn't matter.", "Parents not divorced", @@ -1693,10 +1387,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Close and active", "Respectful but independent", @@ -1712,10 +1403,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Very religious and committed", "Moderate religious", @@ -1731,10 +1419,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Must align with mine", "Differences okay with mutual respect", @@ -1750,10 +1435,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Very formal and limited", "Normal and respectful", @@ -1768,10 +1450,7 @@ "required": true, "extras": { "placeHolder": "Select options", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Smoking is a red line", "Hookah is a red line", @@ -1791,10 +1470,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Should not listen", "Only religious/instrument-free okay", @@ -1810,10 +1486,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Simple or no ceremony", "Strictly religious and segregated", @@ -1831,10 +1504,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Red line", "Consider in special cases", @@ -1850,10 +1520,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "No problem", "Depends on stability", @@ -1869,10 +1536,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Country doesn't matter", "Stay in my current country", @@ -1891,10 +1555,7 @@ "required": true, "extras": { "placeHolder": "Select one option", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "Only independent life", "Temporary with family okay", @@ -1911,10 +1572,7 @@ "description": "Large text field", "extras": { "placeHolder": "Enter details here...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] }, "private": true @@ -1938,15 +1596,8 @@ "description": "Recent and clear face photo", "extras": { "placeHolder": "Upload photo", - "range": [ - 0, - 0 - ], - "options": [ - ".jpg", - ".jpeg", - ".png" - ] + "range": [0, 0], + "options": [".jpg", ".jpeg", ".png"] } }, { @@ -1957,16 +1608,8 @@ "description": "Passport, National ID, or Driver's License", "extras": { "placeHolder": "Upload document", - "range": [ - 0, - 0 - ], - "options": [ - ".pdf", - ".jpg", - ".jpeg", - ".png" - ] + "range": [0, 0], + "options": [".pdf", ".jpg", ".jpeg", ".png"] } }, { @@ -1975,10 +1618,7 @@ "required": true, "extras": { "placeHolder": "I confirm", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "I confirm that my name, age, photo, and identity details match the uploaded documents." ] @@ -1987,4 +1627,4 @@ } ] } -] \ No newline at end of file +] diff --git a/src/data/questions/fa.json b/src/data/questions/fa.json index 6bf0b43..8208951 100644 --- a/src/data/questions/fa.json +++ b/src/data/questions/fa.json @@ -9,32 +9,15 @@ "description": "Collects personal details to start the marriage application flow.", "questions": [ { - "title": "نام", + "title": "نام و نام خانوادگی", "type": "text", "required": true, "extras": { - "placeHolder": "e.g. Sara Ahmadi", - "range": [ - 0, - 0 - ], - "options": [] - }, - "private": true - }, - { - "title": "نام خانوادگی", - "type": "text", - "required": true, - "extras": { - "placeHolder": "e.g. Ahmadi", - "range": [ - 0, - 0 - ], + "placeHolder": "سارا اسمیت", + "range": [0, 0], "options": [] }, - "private": true + "private": false }, { "title": "تاریخ تولد", @@ -42,10 +25,7 @@ "required": true, "extras": { "placeHolder": "YYYY-MM-DD", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } }, @@ -55,36 +35,17 @@ "required": false, "extras": { "placeHolder": "", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } }, { - "title": "شهر محل تولد", - "type": "text", + "title": "محل تولد", + "type": "birthplace", "required": true, "extras": { - "placeHolder": "e.g. Tehran", - "range": [ - 0, - 0 - ], - "options": [] - } - }, - { - "title": "کشور محل تولد", - "type": "dropdown", - "required": true, - "extras": { - "placeHolder": "انتخاب کشور", - "range": [ - 0, - 0 - ], + "placeHolder": "شهر، منطقه یا محله", + "range": [0, 0], "options": [ "ایران", "ایالات متحده", @@ -104,8 +65,7 @@ "نروژ", "استرالیا", "سایر" - ], - "noSearch": true + ] } }, { @@ -114,10 +74,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کشور", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "ایران", "ایالات متحده", @@ -146,42 +103,19 @@ "type": "text", "required": true, "extras": { - "placeHolder": "مثلا فارس", - "range": [ - 0, - 0 - ], + "placeHolder": "انگلستان", + "range": [0, 0], "options": [] } }, - { - "title": "رنگ پوست", - "type": "radio", - "required": true, - "extras": { - "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], - "options": [ - "سفید / روشن", - "گندم‌گون / سبزه روشن", - "سبزه تیره / قهوه‌ای", - "تیره / سیاه‌پوست" - ] - } - }, + { "title": "زبان مادری", "type": "dropdown", "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "فارسی", "انگلیسی", @@ -204,10 +138,7 @@ "required": false, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "فارسی", "انگلیسی", @@ -240,11 +171,8 @@ "type": "phone", "required": true, "extras": { - "placeHolder": "مثلاً +98 912 123 4567", - "range": [ - 0, - 0 - ], + "placeHolder": "+44 7911 123456", + "range": [0, 0], "options": [] }, "private": true @@ -254,25 +182,20 @@ "type": "text", "required": true, "extras": { - "placeHolder": "مثلاً user@example.com", - "range": [ - 0, - 0 - ], + "placeHolder": "user@example.com", + "range": [0, 0], "options": [] }, "private": true }, { - "title": "کشور محل سکونت فعلی", - "type": "dropdown", + "title": "محل سکونت فعلی", + "type": "birthplace", "required": true, + "tooltip": "نیازی به آدرس دقیق نیست. فقط محدوده کلی محل زندگی کافی است؛ مثلاً نام شهر، منطقه، ناحیه یا نزدیکترین شهر بزرگ.", "extras": { - "placeHolder": "انتخاب کشور", - "range": [ - 0, - 0 - ], + "placeHolder": "شهر، منطقه یا محله", + "range": [0, 0], "options": [ "ایران", "ایالات متحده", @@ -292,46 +215,17 @@ "نروژ", "استرالیا", "سایر" - ], - "noSearch": true - } - }, - { - "title": "شهر / ایالت محل سکونت فعلی", - "type": "text", - "required": true, - "extras": { - "placeHolder": "مثلاً تهران", - "range": [ - 0, - 0 - ], - "options": [] - } - }, - { - "title": "لوکیشن حدودی محل زندگی فعلی", - "type": "text", - "required": true, - "extras": { - "placeHolder": "مثلاً غرب تهران", - "range": [ - 0, - 0 - ], - "options": [] + ] } }, + { "title": "وضعیت اقامت در کشور فعلی", "type": "dropdown", "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "شهروند / دارای تابعیت", "اقامت دائم", @@ -350,10 +244,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "کاملاً منعطف هستم؛ جابجایی به شهر یا کشور دیگر برایم مشکلی ندارد.", "حاضرم به شهر دیگری نقل مکان کنم، اما فقط در کشور فعلی خودم حاضر به زندگی هستم.", @@ -368,17 +259,12 @@ "type": "text", "required": false, "requiredWhen": { - "genders": [ - "female" - ], + "genders": ["female"], "maxAge": 26 }, "extras": { - "placeHolder": "مثلاً سارا احمدی", - "range": [ - 0, - 0 - ], + "placeHolder": "سارا اسمیت", + "range": [0, 0], "options": [] }, "private": true @@ -388,17 +274,12 @@ "type": "dropdown", "required": false, "requiredWhen": { - "genders": [ - "female" - ], + "genders": ["female"], "maxAge": 26 }, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "پدر", "مادر", @@ -419,17 +300,12 @@ "type": "phone", "required": false, "requiredWhen": { - "genders": [ - "female" - ], + "genders": ["female"], "maxAge": 26 }, "extras": { - "placeHolder": "مثلاً +98 912 123 4567", - "range": [ - 0, - 0 - ], + "placeHolder": "+44 7911 123456", + "range": [0, 0], "options": [] }, "private": true @@ -450,11 +326,8 @@ "type": "number", "required": true, "extras": { - "placeHolder": "مثلاً ۱۷۵", - "range": [ - 50, - 300 - ], + "placeHolder": "۱۷۵", + "range": [50, 300], "options": [] }, "private": true @@ -464,25 +337,34 @@ "type": "number", "required": true, "extras": { - "placeHolder": "مثلاً ۷۰", - "range": [ - 20, - 600 - ], + "placeHolder": "۷۰", + "range": [20, 600], "options": [] }, "private": true }, + { + "title": "رنگ پوست", + "type": "radio", + "required": true, + "extras": { + "placeHolder": "یک گزینه را انتخاب کنید", + "range": [0, 0], + "options": [ + "سفید / روشن", + "گندم‌گون / سبزه روشن", + "سبزه تیره / قهوه‌ای", + "تیره / سیاه‌پوست" + ] + } + }, { "title": "وضعیت سلامت جسمانی", "type": "radio", "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "در سلامت کامل هستم.", "بیماری خاص یا مزمن دارم.", @@ -497,10 +379,7 @@ "tooltip": "وضعیت بیماریهای مزمن، محدودیتهای جسمانی یا داروهای مصرفی خود را به دقت شرح داده و در صورت سلامت، عبارت «دارای سلامت کامل جسمانی» را در این کادر ثبت کنید.", "extras": { "placeHolder": "توضیحات را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } }, @@ -510,10 +389,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مشکل خاصی ندارم.", "سابقه مشاوره و درمان داشته‌ام.", @@ -526,11 +402,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "مثلاً انسولین و غیره", - "range": [ - 0, - 0 - ], + "placeHolder": "انسولین و غیره", + "range": [0, 0], "options": [] }, "private": true @@ -552,10 +425,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "زیر دیپلم", "دیپلم / High School", @@ -575,11 +445,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "مثلاً مهندسی کامپیوتر", - "range": [ - 0, - 0 - ], + "placeHolder": "مهندسی کامپیوتر", + "range": [0, 0], "options": [] } }, @@ -589,10 +456,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "شاغل تمام‌وقت", "شاغل پاره‌وقت", @@ -613,11 +477,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "مثلاً مهندس نرم‌افزار", - "range": [ - 0, - 0 - ], + "placeHolder": "مهندس نرم‌افزار", + "range": [0, 0], "options": [] } }, @@ -626,11 +487,8 @@ "type": "text", "required": false, "extras": { - "placeHolder": "مثلاً تهران، دورکاری", - "range": [ - 0, - 0 - ], + "placeHolder": "لندن، دورکاری", + "range": [0, 0], "options": [] } }, @@ -639,11 +497,8 @@ "type": "number", "required": true, "extras": { - "placeHolder": "مثلاً 2500 USD، 1800 EUR", - "range": [ - 0, - 0 - ], + "placeHolder": "۳۵۰۰ پوند، ۴۰۰۰ دلار", + "range": [0, 0], "options": [] }, "private": true @@ -654,10 +509,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "درآمد پایدار و قابل اتکا دارم.", "درآمد دارم، اما متغیر است.", @@ -675,10 +527,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "توانایی تأمین کامل هزینه‌های زندگی مشترک را دارم.", "توانایی تأمین بخش اصلی هزینه‌ها را دارم.", @@ -696,10 +545,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مالک خانه شخصی هستم.", "مستأجر هستم و مستقل زندگی می‌کنم.", @@ -718,10 +564,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "خانه شخصی دارم و امکان زندگی مشترک در آن وجود دارد.", "امکان خرید خانه دارم.", @@ -737,10 +580,7 @@ "required": false, "extras": { "placeHolder": "توضیحات خود را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] }, "private": true @@ -761,11 +601,8 @@ "type": "number", "required": true, "extras": { - "placeHolder": "مثلاً ۲", - "range": [ - 0, - 20 - ], + "placeHolder": "۲", + "range": [0, 20], "options": [] } }, @@ -775,10 +612,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "هر دو در قید حیات هستند.", "پدر فوت شده است.", @@ -793,10 +627,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "با هم زندگی می‌کنند.", "از هم جدا شده‌اند / طلاق گرفته‌اند.", @@ -813,10 +644,7 @@ "description": "Please select the option that best describes the general atmosphere and lifestyle of your family.", "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مذهبی و کاملاً مقید", "مذهبی (مقید به واجبات)", @@ -831,16 +659,8 @@ "required": false, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], - "options": [ - "ضعیف", - "متوسط", - "خوب", - "مرفه" - ] + "range": [0, 0], + "options": ["ضعیف", "متوسط", "خوب", "مرفه"] } }, { @@ -849,10 +669,7 @@ "required": false, "extras": { "placeHolder": "توضیحات خود را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } } @@ -873,10 +690,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مجرد؛ بدون هیچ‌گونه سابقه عقد یا ازدواج", "عقد ناموفق / فسخ نامزدی؛ بدون شروع زندگی مشترک", @@ -901,11 +715,8 @@ } }, "extras": { - "placeHolder": "مثلاً ۳ سال", - "range": [ - 0, - 0 - ], + "placeHolder": "۳ سال", + "range": [0, 0], "options": [] }, "private": true @@ -925,10 +736,7 @@ }, "extras": { "placeHolder": "توضیحات را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] }, "private": true @@ -939,10 +747,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "فرزندی ندارم.", "فرزند دارم و با من زندگی می‌کند.", @@ -958,18 +763,12 @@ "logic": { "dependsOn": { "title": "وضعیت تأهل فعلی", - "values": [ - "جدا شده؛ طلاق پس از زندگی مشترک", - "همسر فوت شده" - ] + "values": ["جدا شده؛ طلاق پس از زندگی مشترک", "همسر فوت شده"] } }, "extras": { - "placeHolder": "مثلاً ۲", - "range": [ - 0, - 10 - ], + "placeHolder": "۲", + "range": [0, 10], "options": [] } }, @@ -979,10 +778,7 @@ "required": false, "extras": { "placeHolder": "توضیحات را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } } @@ -1002,11 +798,8 @@ "type": "text", "required": true, "extras": { - "placeHolder": "مثلاً آیت‌الله سیستانی", - "range": [ - 0, - 0 - ], + "placeHolder": "آیت‌الله سیستانی", + "range": [0, 0], "options": [] } }, @@ -1016,10 +809,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "همیشه مقید هستم، ترجیحاً اول وقت", "همیشه مقید هستم، اما نه لزوماً اول وقت", @@ -1035,10 +825,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "کاملاً مقید هستم", "به دلیل عذر شرعی یا پزشکی روزه نمی‌گیرم", @@ -1054,10 +841,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "پوشش کامل اسلامی (حداکثری) - چادر، عبا یا پوشش‌های مشابه با رعایت کامل حدود شرعی.", "حجاب کامل با لباس‌های پوشیده و آزاد - مانتوهای بلند و گشاد با پوشش کامل موی سر.", @@ -1073,16 +857,11 @@ "type": "radio", "required": false, "audience": { - "genders": [ - "female" - ] + "genders": ["female"] }, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "اصلاً آرایش نمی‌کنم", "فقط آرایش بسیار ملایم", @@ -1096,10 +875,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "دین و سیاست از هم جدایی‌ناپذیرند و حتماً همسرم باید همین دیدگاه را داشته باشد.", "دین و سیاست از هم جدایی‌ناپذیرند، اما فعالیت سیاسی همسرم الزامی نیست.", @@ -1117,10 +893,7 @@ "required": false, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "موافق و حامی نظام فعلی؛ مخالفت جدی همسرم خط قرمز است.", "موافق و حامی نظام فعلی، اما تفاوت دیدگاه همسرم خط قرمز نیست.", @@ -1138,10 +911,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "بسیار رسمی و محدود (فقط در حد ضرورت) - اجتناب از هرگونه گفتگوی غیرضروری یا شوخی.", "محترمانه و متعارف (بدون صمیمیت) - تعاملات مؤدبانه با حفظ مرزهای مشخص شخصی.", @@ -1156,10 +926,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "اصلاً مصرف نمی‌کنم", "گاهی / تفریحی مصرف می‌کنم", @@ -1175,10 +942,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "اصلاً مصرف نمی‌کنم", "گاهی / تفریحی مصرف می‌کنم", @@ -1194,10 +958,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "اصلاً مصرف نمی‌کنم", "گاهی / تفریحی مصرف می‌کنم", @@ -1213,10 +974,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "اصلاً مصرف نمی‌کنم", "مصرف الکل برای من خط قرمز جدی است", @@ -1232,10 +990,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "هرگز مصرف نکرده‌ام", "در گذشته مصرف داشته‌ام اما اکنون ترک کرده‌ام", @@ -1251,10 +1006,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "اصلاً به هیچ موسیقی گوش نمی‌دهم", "فقط به تواشیح، موسیقی‌های مذهبی یا بدون ساز گوش می‌دهم", @@ -1269,10 +1021,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "بدون مراسم یا بسیار ساده", "کاملاً مذهبی و تفکیک‌شده (زنانه و مردانه جدا)", @@ -1290,10 +1039,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 1, - 10 - ], + "range": [1, 10], "options": [ "آرام و درونگرا", "اجتماعی و برونگرا", @@ -1321,10 +1067,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 1, - 15 - ], + "range": [1, 15], "options": [ "تلاوت قرآن و مطالعه دینی", "حضور در مسجد و هیئت", @@ -1353,10 +1096,7 @@ "required": false, "extras": { "placeHolder": "توضیحات را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] } } @@ -1397,11 +1137,8 @@ "required": true, "description": "از [عدد] تا [عدد] سال", "extras": { - "placeHolder": "مثلاً ۲۵-۳۰", - "range": [ - 0, - 0 - ], + "placeHolder": "۲۵-۳۰", + "range": [0, 0], "options": [] }, "private": true @@ -1412,10 +1149,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "کمتر از ۱۶۰", @@ -1434,10 +1168,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "لاغراندام", @@ -1456,10 +1187,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "سفید / روشن", @@ -1477,11 +1205,8 @@ "required": false, "description": "فیلد متنی اختیاری", "extras": { - "placeHolder": "مثلاً فارس، ترک، عرب و ...", - "range": [ - 0, - 0 - ], + "placeHolder": "انگلیسی، فرانسوی و...", + "range": [0, 0], "options": [] }, "private": true @@ -1492,10 +1217,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "حداقل دیپلم", @@ -1515,10 +1237,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "شاغل باشد.", @@ -1538,10 +1257,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "فقط مجرد؛ سابقه عقد یا ازدواج قبلی برایم خط قرمز است.", "مجرد ترجیح دارد، اما شرایط خاص را بررسی می‌کنم.", @@ -1557,10 +1273,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "به هیچ وجه نمی‌پذیرم.", "در شرایط خاص می‌پذیرم.", @@ -1575,16 +1288,11 @@ "type": "dropdown", "required": true, "audience": { - "genders": [ - "male" - ] + "genders": ["male"] }, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "پوشش کامل اسلامی مانند چادر، عبایا یا جلباب الزامی است.", "حجاب شرعی الزامی است، اما نوع آن مهم نیست.", @@ -1601,16 +1309,11 @@ "type": "dropdown", "required": true, "audience": { - "genders": [ - "female" - ] + "genders": ["female"] }, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "پوشش رسمی، سنگین و مذهبی داشته باشد.", "ساده، مرتب و محجوب باشد.", @@ -1628,10 +1331,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "حتماً قصد ادامه تحصیل داشته باشد.", @@ -1649,10 +1349,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مهم نیست.", "حتماً شاغل باشد.", @@ -1671,10 +1368,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "این معیارها برایم مهم نیست.", "والدین همسرم طلاق نگرفته باشند.", @@ -1693,10 +1387,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "ارتباط نزدیک و پررنگ با خانواده‌ها را دوست دارم.", "ارتباط محترمانه اما با حفظ استقلال زندگی مشترک را ترجیح می‌دهم.", @@ -1712,10 +1403,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "بسیار مذهبی و مقید", "مذهبی معتدل", @@ -1731,10 +1419,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "حتماً همسو با دیدگاه من باشد.", "تفاوت دیدگاه سیاسی مهم نیست، به شرط احترام متقابل.", @@ -1750,10 +1435,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "بسیار رسمی و محدود باشد.", "معمولی و محترمانه باشد.", @@ -1768,10 +1450,7 @@ "required": true, "extras": { "placeHolder": "انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "سیگار برایم خط قرمز است.", "قلیان برایم خط قرمز است.", @@ -1791,10 +1470,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "نباید به موسیقی گوش بدهد.", "فقط موسیقی مذهبی / بدون ساز / نشید قابل قبول است.", @@ -1810,10 +1486,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "مراسم ساده یا بدون مراسم را ترجیح دهد.", "فقط مراسم کاملاً شرعی و تفکیک‌شده قابل قبول است.", @@ -1831,10 +1504,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "برایم خط قرمز است.", "در شرایط خاص و با توضیح کامل بررسی می‌کنم.", @@ -1850,10 +1520,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "برایم مشکلی ندارد.", "بستگی به شرایط فعلی و میزان ثبات دارد.", @@ -1869,10 +1536,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "کشور محل زندگی طرف مقابل برایم مهم نیست.", "ترجیح می‌دهم در کشور فعلی خودم بمانم.", @@ -1891,10 +1555,7 @@ "required": true, "extras": { "placeHolder": "یک گزینه را انتخاب کنید", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "فقط زندگی مستقل را می‌پذیرم.", "زندگی موقت با خانواده در ابتدای ازدواج قابل قبول است.", @@ -1911,10 +1572,7 @@ "description": "فیلد متنی بزرگ", "extras": { "placeHolder": "توضیحات تکمیلی را اینجا وارد کنید...", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [] }, "private": true @@ -1938,15 +1596,8 @@ "description": "عکس جدید و واضح", "extras": { "placeHolder": "بارگذاری تصویر", - "range": [ - 0, - 0 - ], - "options": [ - ".jpg", - ".jpeg", - ".png" - ] + "range": [0, 0], + "options": [".jpg", ".jpeg", ".png"] } }, { @@ -1957,16 +1608,8 @@ "description": "پاسپورت، کارت ملی یا گواهینامه", "extras": { "placeHolder": "بارگذاری مدرک", - "range": [ - 0, - 0 - ], - "options": [ - ".pdf", - ".jpg", - ".jpeg", - ".png" - ] + "range": [0, 0], + "options": [".pdf", ".jpg", ".jpeg", ".png"] } }, { @@ -1975,10 +1618,7 @@ "required": true, "extras": { "placeHolder": "تأیید می‌کنم", - "range": [ - 0, - 0 - ], + "range": [0, 0], "options": [ "تأیید می‌کنم که نام، سن، تصویر و اطلاعات هویتی من با مدارک بارگذاری‌شده مطابقت دارد." ] @@ -1987,4 +1627,4 @@ } ] } -] \ No newline at end of file +] diff --git a/src/hooks/marriage/query-keys.ts b/src/hooks/marriage/query-keys.ts index 3588d19..0fe2453 100644 --- a/src/hooks/marriage/query-keys.ts +++ b/src/hooks/marriage/query-keys.ts @@ -14,11 +14,21 @@ export const marriageQueryKeys = { [...marriageQueryKeys.sections(), slug, "data"] as const, sections: () => [...marriageQueryKeys.all, "sections"] as const, cattellQuestions: (lang?: string) => - [...marriageQueryKeys.all, "cattell", "questions", lang ?? "default"] as const, + [ + ...marriageQueryKeys.all, + "cattell", + "questions", + lang ?? "default", + ] as const, cattellResult: (lang?: string) => [...marriageQueryKeys.all, "cattell", "result", lang ?? "default"] as const, glasserQuestions: (lang?: string) => - [...marriageQueryKeys.all, "glasser", "questions", lang ?? "default"] as const, + [ + ...marriageQueryKeys.all, + "glasser", + "questions", + lang ?? "default", + ] as const, glasserResult: (lang?: string) => [...marriageQueryKeys.all, "glasser", "result", lang ?? "default"] as const, }; diff --git a/src/hooks/marriage/types.ts b/src/hooks/marriage/types.ts index 038e6dc..6819f91 100644 --- a/src/hooks/marriage/types.ts +++ b/src/hooks/marriage/types.ts @@ -74,7 +74,14 @@ export type MarriageActiveCase = { contact_shared_at?: string | null; minutes_since_contact_shared?: number | null; can_report_no_contact?: boolean; - my_action?: "pending" | "waiting" | "rejected" | "other_rejected" | "payment_required" | "completed" | string; + my_action?: + | "pending" + | "waiting" + | "rejected" + | "other_rejected" + | "payment_required" + | "completed" + | string; other_action?: string; }; @@ -242,4 +249,3 @@ export type GlasserSubmitResponse = { export type GlasserResultResponse = { results: Record; }; - diff --git a/src/hooks/marriage/use-section-data.ts b/src/hooks/marriage/use-section-data.ts index 9d16e1f..3e0966f 100644 --- a/src/hooks/marriage/use-section-data.ts +++ b/src/hooks/marriage/use-section-data.ts @@ -1,6 +1,7 @@ "use client"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { toBackendSlug } from "@/data/section-slug-map"; import { http } from "@/lib/http"; import type { MutationOptions, QueryOptions } from "./options"; import { pathParam } from "./path-param"; @@ -10,8 +11,6 @@ import type { UpdateMarriageSectionDataPayload, } from "./types"; -import { toBackendSlug } from "@/data/section-slug-map"; - export async function getMarriageSectionData(slug: string) { const backendSlug = toBackendSlug(slug); const { data } = await http.get( diff --git a/src/hooks/use-close-service-on-back.ts b/src/hooks/use-close-service-on-back.ts index 34a0dd5..2128b65 100644 --- a/src/hooks/use-close-service-on-back.ts +++ b/src/hooks/use-close-service-on-back.ts @@ -23,7 +23,11 @@ export function useCloseServiceOnBack(enabled: boolean = true) { const handlePopState = () => { if ((window as any).HabibApp?.postMessage) { // Keep the state pinned in webview and notify Flutter to close the webview - window.history.pushState({ closeOnBack: true }, "", window.location.href); + window.history.pushState( + { closeOnBack: true }, + "", + window.location.href, + ); (window as any).HabibApp.postMessage( JSON.stringify({ action: "close_service" }), ); diff --git a/src/hooks/useFlutterBridge.ts b/src/hooks/useFlutterBridge.ts index cce3a73..85cb0cb 100644 --- a/src/hooks/useFlutterBridge.ts +++ b/src/hooks/useFlutterBridge.ts @@ -3,16 +3,16 @@ * دریافت و ارسال ایونت‌ها */ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from "react"; // تایپ‌های ایونت‌های دریافتی از Flutter export type FlutterEventType = - | 'LAYOUT_CHANGED' - | 'KEYBOARD_CHANGED' - | 'SAFE_AREA_CHANGED' - | 'ORIENTATION_CHANGED' - | 'SCREEN_SIZE_CHANGED' - | 'INITIAL_CONFIG'; + | "LAYOUT_CHANGED" + | "KEYBOARD_CHANGED" + | "SAFE_AREA_CHANGED" + | "ORIENTATION_CHANGED" + | "SCREEN_SIZE_CHANGED" + | "INITIAL_CONFIG"; export interface FlutterEvent { type: FlutterEventType; @@ -22,11 +22,11 @@ export interface FlutterEvent { // تایپ‌های ایونت‌های ارسالی به Flutter export type WebEventType = - | 'WEB_READY' - | 'REQUEST_LOCATION' - | 'REQUEST_CONSULTANT' - | 'PAGE_LOADED' - | 'ERROR_OCCURRED'; + | "WEB_READY" + | "REQUEST_LOCATION" + | "REQUEST_CONSULTANT" + | "PAGE_LOADED" + | "ERROR_OCCURRED"; export interface WebEvent { type: WebEventType; @@ -69,34 +69,37 @@ const WEB_EVENT_TO_ACTION: Record = { }; export function useFlutterBridge( - options: UseFlutterBridgeOptions = {} + options: UseFlutterBridgeOptions = {}, ): UseFlutterBridgeReturn { const { onEvent, enableLogging = true } = options; - + const [events, setEvents] = useState([]); const [lastEvent, setLastEvent] = useState(null); const [isReady, setIsReady] = useState(false); const [logs, setLogs] = useState([]); - + const logsRef = useRef([]); const hasSentReadyRef = useRef(false); // تابع کمکی برای اضافه کردن لاگ - const addLog = (message: string, type: 'info' | 'success' | 'error' = 'info') => { - const timestamp = new Date().toLocaleTimeString('fa-IR'); + const addLog = ( + message: string, + type: "info" | "success" | "error" = "info", + ) => { + const timestamp = new Date().toLocaleTimeString("fa-IR"); const logMessage = `[${timestamp}] [${type.toUpperCase()}] ${message}`; - + if (enableLogging) { console.log(logMessage); } - + logsRef.current = [...logsRef.current, logMessage].slice(-50); // نگه داشتن 50 لاگ آخر setLogs(logsRef.current); }; // تابع ارسال ایونت به Flutter const sendToFlutter = (type: WebEventType, payload?: any) => { - if (typeof window === 'undefined') return; + if (typeof window === "undefined") return; const action = WEB_EVENT_TO_ACTION[type]; let delivered = false; @@ -109,14 +112,17 @@ export function useFlutterBridge( payload !== undefined ? { action, data: payload } : { action }; window.HabibApp.postMessage(JSON.stringify(message)); delivered = true; - addLog(`📤 ارسال به Flutter (HabibApp): ${type} → ${action}`, 'success'); + addLog( + `📤 ارسال به Flutter (HabibApp): ${type} → ${action}`, + "success", + ); } // مسیرهای fallback فقط برای محیط توسعه/iframe (در WebView واقعی Flutter وجود ندارند) const event: WebEvent = { type, payload, timestamp: Date.now() }; if (window.parent && window.parent !== window) { - window.parent.postMessage(event, '*'); + window.parent.postMessage(event, "*"); delivered = true; } @@ -126,28 +132,29 @@ export function useFlutterBridge( } if ((window as any).webkit?.messageHandlers?.FlutterChannel) { - (window as any).webkit.messageHandlers.FlutterChannel.postMessage(event); + (window as any).webkit.messageHandlers.FlutterChannel.postMessage( + event, + ); delivered = true; } if (!delivered) { - addLog(`⚠️ محیط Flutter یافت نشد - در حالت توسعه`, 'info'); + addLog(`⚠️ محیط Flutter یافت نشد - در حالت توسعه`, "info"); } } catch (error) { - addLog(`❌ خطا در ارسال به Flutter: ${error}`, 'error'); - console.error('Error sending to Flutter:', error); + addLog(`❌ خطا در ارسال به Flutter: ${error}`, "error"); + console.error("Error sending to Flutter:", error); } }; // Listen کردن به ایونت‌های Flutter useEffect(() => { - addLog('🚀 شروع listening به ایونت‌های Flutter', 'info'); + addLog("🚀 شروع listening به ایونت‌های Flutter", "info"); const handleFlutterEvent = (event: MessageEvent) => { try { - const data = typeof event.data === 'string' - ? JSON.parse(event.data) - : event.data; + const data = + typeof event.data === "string" ? JSON.parse(event.data) : event.data; // چک کردن اینکه ایونت از Flutter است if (data && data.type) { @@ -157,15 +164,15 @@ export function useFlutterBridge( timestamp: data.timestamp || Date.now(), }; - addLog(`📥 دریافت از Flutter: ${data.type}`, 'success'); - + addLog(`📥 دریافت از Flutter: ${data.type}`, "success"); + setEvents((prev) => [...prev, flutterEvent].slice(-20)); // نگه داشتن 20 ایونت آخر setLastEvent(flutterEvent); // Handle INITIAL_CONFIG - if (data.type === 'INITIAL_CONFIG') { + if (data.type === "INITIAL_CONFIG") { setIsReady(true); - addLog('✅ WebView آماده شد', 'success'); + addLog("✅ WebView آماده شد", "success"); } // Callback @@ -174,13 +181,13 @@ export function useFlutterBridge( } } } catch (error) { - addLog(`❌ خطا در parse ایونت Flutter: ${error}`, 'error'); - console.error('Error parsing Flutter event:', error); + addLog(`❌ خطا در parse ایونت Flutter: ${error}`, "error"); + console.error("Error parsing Flutter event:", error); } }; // Listen به message event - window.addEventListener('message', handleFlutterEvent); + window.addEventListener("message", handleFlutterEvent); // Listen به custom events const handleCustomEvent = (event: Event) => { @@ -192,15 +199,24 @@ export function useFlutterBridge( } }; - window.addEventListener('flutterConfig', handleCustomEvent as EventListener); - window.addEventListener('flutterEvent', handleCustomEvent as EventListener); + window.addEventListener( + "flutterConfig", + handleCustomEvent as EventListener, + ); + window.addEventListener("flutterEvent", handleCustomEvent as EventListener); // Cleanup return () => { - window.removeEventListener('message', handleFlutterEvent); - window.removeEventListener('flutterConfig', handleCustomEvent as EventListener); - window.removeEventListener('flutterEvent', handleCustomEvent as EventListener); - addLog('🛑 متوقف کردن listening', 'info'); + window.removeEventListener("message", handleFlutterEvent); + window.removeEventListener( + "flutterConfig", + handleCustomEvent as EventListener, + ); + window.removeEventListener( + "flutterEvent", + handleCustomEvent as EventListener, + ); + addLog("🛑 متوقف کردن listening", "info"); }; }, [onEvent, enableLogging]); @@ -209,7 +225,7 @@ export function useFlutterBridge( // تزریق می‌شود؛ وجودش یعنی پل برقرار است. منتظر INITIAL_CONFIG نمی‌مانیم، // چون Flutter چنین ایونتی نمی‌فرستد. useEffect(() => { - if (typeof window === 'undefined') return; + if (typeof window === "undefined") return; let interval: ReturnType | undefined; let timeout: ReturnType | undefined; @@ -221,12 +237,12 @@ export function useFlutterBridge( if (!hasSentReadyRef.current) { hasSentReadyRef.current = true; - sendToFlutter('WEB_READY', { + sendToFlutter("WEB_READY", { url: window.location.href, userAgent: navigator.userAgent, timestamp: Date.now(), }); - addLog('✅ WEB_READY به‌صورت خودکار ارسال شد', 'success'); + addLog("✅ WEB_READY به‌صورت خودکار ارسال شد", "success"); } return true; @@ -252,18 +268,18 @@ export function useFlutterBridge( // گوش‌دادن به پاسخ‌های واقعی Flutter از مسیر window.onFlutterResponse. // رسیدن هر پاسخ یعنی ارتباط دوطرفه برقرار است. useEffect(() => { - if (typeof window === 'undefined') return; + if (typeof window === "undefined") return; const unsubscribe = window.addFlutterResponseListener?.((response) => { setIsReady(true); const flutterEvent: FlutterEvent = { - type: 'INITIAL_CONFIG', + type: "INITIAL_CONFIG", payload: response, timestamp: response?.data?.timestamp || Date.now(), }; - addLog(`📥 پاسخ از Flutter: ${response?.action}`, 'success'); + addLog(`📥 پاسخ از Flutter: ${response?.action}`, "success"); setEvents((prev) => [...prev, flutterEvent].slice(-20)); setLastEvent(flutterEvent); onEvent?.(flutterEvent); diff --git a/src/lib/auth-bridge.ts b/src/lib/auth-bridge.ts index 92a298d..8064ce9 100644 --- a/src/lib/auth-bridge.ts +++ b/src/lib/auth-bridge.ts @@ -74,11 +74,13 @@ class AuthBridge { return false; } - this.flutterResponseUnsubscribe = win.addFlutterResponseListener((event) => { - if (event.action === "login") { - this.handleLoginResponse(event.success); - } - }); + this.flutterResponseUnsubscribe = win.addFlutterResponseListener( + (event) => { + if (event.action === "login") { + this.handleLoginResponse(event.success); + } + }, + ); return true; }; @@ -147,7 +149,10 @@ class AuthBridge { } private resolvePending(token: string | null) { - const resolvers = this.pendingResolvers.splice(0, this.pendingResolvers.length); + const resolvers = this.pendingResolvers.splice( + 0, + this.pendingResolvers.length, + ); for (const resolve of resolvers) { resolve(token); } diff --git a/src/lib/http.ts b/src/lib/http.ts index 2d4d483..945adf7 100644 --- a/src/lib/http.ts +++ b/src/lib/http.ts @@ -56,7 +56,9 @@ export function getApiRequestUrl(path: string) { } export const http = axios.create({ - baseURL: shouldUseProxy() ? "/api/proxy" : process.env.NEXT_PUBLIC_API_BASE_URL, + baseURL: shouldUseProxy() + ? "/api/proxy" + : process.env.NEXT_PUBLIC_API_BASE_URL, headers: { Accept: "application/json", "Content-Type": "application/json", @@ -98,5 +100,5 @@ http.interceptors.request.use((config) => { http.interceptors.response.use( (response) => response, - (error) => Promise.reject(error) + (error) => Promise.reject(error), ); diff --git a/src/lib/performance.ts b/src/lib/performance.ts index 4c8523c..590c5e2 100644 --- a/src/lib/performance.ts +++ b/src/lib/performance.ts @@ -1,9 +1,11 @@ export function measurePerformance() { - if (typeof window === 'undefined') return; + if (typeof window === "undefined") return; + + window.addEventListener("load", () => { + const perfData = performance.getEntriesByType( + "navigation", + )[0] as PerformanceNavigationTiming; - window.addEventListener('load', () => { - const perfData = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming; - const metrics = { dns: perfData.domainLookupEnd - perfData.domainLookupStart, tcp: perfData.connectEnd - perfData.connectStart, @@ -14,14 +16,16 @@ export function measurePerformance() { loadComplete: perfData.loadEventEnd - perfData.fetchStart, }; - console.log('⏱️ Performance Metrics:', metrics); - + console.log("⏱️ Performance Metrics:", metrics); + // ارسال به analytics (اختیاری) if ((window as any).HabibApp) { - (window as any).HabibApp.postMessage(JSON.stringify({ - action: 'performance_metrics', - data: metrics, - })); + (window as any).HabibApp.postMessage( + JSON.stringify({ + action: "performance_metrics", + data: metrics, + }), + ); } }); } diff --git a/src/lib/view-paddings.ts b/src/lib/view-paddings.ts index 12aac9a..1dc6b7d 100644 --- a/src/lib/view-paddings.ts +++ b/src/lib/view-paddings.ts @@ -34,12 +34,14 @@ interface InitialConfig { locale: LocaleInfo | null; } -type EdgeSource = { - top?: number; - bottom?: number; - left?: number; - right?: number; -} | null +type EdgeSource = + | { + top?: number; + bottom?: number; + left?: number; + right?: number; + } + | null | undefined; function num(value: unknown): number { @@ -130,9 +132,7 @@ class ViewPaddingsBridge { window.addEventListener("message", (event) => { const data = - typeof event.data === "string" - ? safeParse(event.data) - : event.data; + typeof event.data === "string" ? safeParse(event.data) : event.data; handle(data); }); } @@ -313,5 +313,11 @@ class ViewPaddingsBridge { } } -export type { ViewPaddings, InitialConfig, LayoutInfo, PlatformInfo, LocaleInfo }; +export type { + ViewPaddings, + InitialConfig, + LayoutInfo, + PlatformInfo, + LocaleInfo, +}; export const viewPaddingsBridge = new ViewPaddingsBridge(); diff --git a/src/plugins/jsx-locator-loader.cjs b/src/plugins/jsx-locator-loader.cjs index a72aae5..8fe5820 100644 --- a/src/plugins/jsx-locator-loader.cjs +++ b/src/plugins/jsx-locator-loader.cjs @@ -35,7 +35,9 @@ module.exports = function (source, inputSourceMap) { return; } } catch (err) { - console.error(`[jsx-locator-loader] Skipped ${filename} due to parse notice: ${err.message}`); + console.error( + `[jsx-locator-loader] Skipped ${filename} due to parse notice: ${err.message}`, + ); } return source; diff --git a/src/translations/dictionaries.ts b/src/translations/dictionaries.ts index 7c82bdc..5ded7dd 100644 --- a/src/translations/dictionaries.ts +++ b/src/translations/dictionaries.ts @@ -55,5 +55,8 @@ export const dictionaries = { export type Dictionary = typeof dictionaries.en; export function getDictionary(locale: Locale): Dictionary { - return (dictionaries as unknown as Record)[locale] ?? dictionaries.en; + return ( + (dictionaries as unknown as Record)[locale] ?? + dictionaries.en + ); } diff --git a/src/translations/locales/ar.json b/src/translations/locales/ar.json index 0557e22..a29fed7 100644 --- a/src/translations/locales/ar.json +++ b/src/translations/locales/ar.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "معلومات سرية (مرئية لمستشاري حبيب مريج فقط)", + "privateFieldNotice": "معلومات سرية (للمستشارين فقط)", "startMatchFailed": "فشل إرسال طلب التوافق. يرجى التحقق من الاتصال والمحاولة مرة أخرى.", "moveToEnd": "الانتقال إلى النهاية" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/az.json b/src/translations/locales/az.json index ed025ac..421fdda 100644 --- a/src/translations/locales/az.json +++ b/src/translations/locales/az.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/bn.json b/src/translations/locales/bn.json index ed025ac..421fdda 100644 --- a/src/translations/locales/bn.json +++ b/src/translations/locales/bn.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/da.json b/src/translations/locales/da.json index ed025ac..421fdda 100644 --- a/src/translations/locales/da.json +++ b/src/translations/locales/da.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/de.json b/src/translations/locales/de.json index ed025ac..421fdda 100644 --- a/src/translations/locales/de.json +++ b/src/translations/locales/de.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/en.json b/src/translations/locales/en.json index 2cad233..b5fdd69 100644 --- a/src/translations/locales/en.json +++ b/src/translations/locales/en.json @@ -34,7 +34,7 @@ "playAlt": "play" }, "questions": { - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "profileRegistration": "Profile registration", "closeQuestionsList": "Close questions list", "requiredSteps": "Required Steps", @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/es.json b/src/translations/locales/es.json index ed025ac..421fdda 100644 --- a/src/translations/locales/es.json +++ b/src/translations/locales/es.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/fa.json b/src/translations/locales/fa.json index ea75bc4..aef563e 100644 --- a/src/translations/locales/fa.json +++ b/src/translations/locales/fa.json @@ -34,7 +34,7 @@ "playAlt": "پخش" }, "questions": { - "privateFieldNotice": "اطلاعات محرمانه (فقط برای کارشناسان حبیب مریج و سیستم مچینگ)", + "privateFieldNotice": "اطلاعات محرمانه (فقط کارشناسان)", "profileRegistration": "ثبت اطلاعات پروفایل", "closeQuestionsList": "بستن فهرست سوالات", "requiredSteps": "مراحل ضروری", @@ -151,4 +151,4 @@ "matchProfile": "مشاهده پروفایل گزینه", "profileLocked": "پروفایل قفل است" } -} \ No newline at end of file +} diff --git a/src/translations/locales/fr.json b/src/translations/locales/fr.json index ed025ac..421fdda 100644 --- a/src/translations/locales/fr.json +++ b/src/translations/locales/fr.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/gu.json b/src/translations/locales/gu.json index ed025ac..421fdda 100644 --- a/src/translations/locales/gu.json +++ b/src/translations/locales/gu.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/ha.json b/src/translations/locales/ha.json index ed025ac..421fdda 100644 --- a/src/translations/locales/ha.json +++ b/src/translations/locales/ha.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/he.json b/src/translations/locales/he.json index ed025ac..421fdda 100644 --- a/src/translations/locales/he.json +++ b/src/translations/locales/he.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/hi.json b/src/translations/locales/hi.json index ed025ac..421fdda 100644 --- a/src/translations/locales/hi.json +++ b/src/translations/locales/hi.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/id.json b/src/translations/locales/id.json index ed025ac..421fdda 100644 --- a/src/translations/locales/id.json +++ b/src/translations/locales/id.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/ks.json b/src/translations/locales/ks.json index ed025ac..421fdda 100644 --- a/src/translations/locales/ks.json +++ b/src/translations/locales/ks.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/pt.json b/src/translations/locales/pt.json index ed025ac..421fdda 100644 --- a/src/translations/locales/pt.json +++ b/src/translations/locales/pt.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/ru.json b/src/translations/locales/ru.json index ed025ac..421fdda 100644 --- a/src/translations/locales/ru.json +++ b/src/translations/locales/ru.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/sw.json b/src/translations/locales/sw.json index ef8ec1f..6115ce6 100644 --- a/src/translations/locales/sw.json +++ b/src/translations/locales/sw.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/tg.json b/src/translations/locales/tg.json index ef8ec1f..6115ce6 100644 --- a/src/translations/locales/tg.json +++ b/src/translations/locales/tg.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/tr.json b/src/translations/locales/tr.json index 6c175fd..974d524 100644 --- a/src/translations/locales/tr.json +++ b/src/translations/locales/tr.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Gizli Alan (Yalnızca Habib Marriage danışmanları tarafından görülebilir)", + "privateFieldNotice": "Gizli (Yalnızca Danışmanlar)", "startMatchFailed": "Eşleşme isteği gönderilemedi. Lütfen bağlantınızı kontrol edip tekrar deneyin.", "moveToEnd": "Sona Taşı" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/ul.json b/src/translations/locales/ul.json index ef8ec1f..6115ce6 100644 --- a/src/translations/locales/ul.json +++ b/src/translations/locales/ul.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/ur.json b/src/translations/locales/ur.json index 7a835fe..32f9748 100644 --- a/src/translations/locales/ur.json +++ b/src/translations/locales/ur.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "نجی فیلڈ (صرف حبیب میرج کے مشیروں کو نظر آتی ہے)", + "privateFieldNotice": "نجی (صرف مشیران)", "startMatchFailed": "میچ کی درخواست بھیجنے میں ناکامی۔ برائے مہربانی اپنا کنکشن چیک کریں اور دوبارہ کوشش کریں۔", "moveToEnd": "آخر میں منتقل کریں" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/uz.json b/src/translations/locales/uz.json index ef8ec1f..6115ce6 100644 --- a/src/translations/locales/uz.json +++ b/src/translations/locales/uz.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/locales/zh.json b/src/translations/locales/zh.json index ef8ec1f..6115ce6 100644 --- a/src/translations/locales/zh.json +++ b/src/translations/locales/zh.json @@ -63,7 +63,7 @@ "By identifying your strongest needs, you can better communicate your expectations and build healthier relationships." ] }, - "privateFieldNotice": "Private Field (Visible to Habib Marriage advisors only)", + "privateFieldNotice": "Private (Advisors Only)", "startMatchFailed": "Sending the match request failed. Please check your connection and try again.", "moveToEnd": "Move to the End" }, @@ -151,4 +151,4 @@ "matchProfile": "Match Profile", "profileLocked": "Profile is locked" } -} \ No newline at end of file +} diff --git a/src/translations/provider.tsx b/src/translations/provider.tsx index af70671..361ab91 100644 --- a/src/translations/provider.tsx +++ b/src/translations/provider.tsx @@ -7,7 +7,11 @@ import { useEffect, useMemo, } from "react"; -import { defaultLocale, type Locale, localeDirections } from "@/translations/config"; +import { + defaultLocale, + type Locale, + localeDirections, +} from "@/translations/config"; import { type Dictionary, getDictionary } from "@/translations/dictionaries"; type I18nContextValue = { diff --git a/src/view-paddings.ts b/src/view-paddings.ts index 193cfb1..0e54091 100644 --- a/src/view-paddings.ts +++ b/src/view-paddings.ts @@ -1,7 +1,7 @@ +export { FixedBottom } from "./components/utils/fixed-bottom"; export { useFlutterConfig, useViewPaddings } from "./hooks/use-view-paddings"; export { type InitialConfig, type ViewPaddings, viewPaddingsBridge, } from "./lib/view-paddings"; -export { FixedBottom } from "./components/utils/fixed-bottom";