django-cfg 1.1.81__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +20 -448
- django_cfg/apps/accounts/README.md +3 -3
- django_cfg/apps/accounts/admin/__init__.py +0 -2
- django_cfg/apps/accounts/admin/activity.py +2 -9
- django_cfg/apps/accounts/admin/filters.py +0 -42
- django_cfg/apps/accounts/admin/inlines.py +8 -8
- django_cfg/apps/accounts/admin/otp.py +5 -5
- django_cfg/apps/accounts/admin/registration_source.py +1 -8
- django_cfg/apps/accounts/admin/user.py +12 -20
- django_cfg/apps/accounts/managers/user_manager.py +2 -129
- django_cfg/apps/accounts/migrations/0006_remove_twilioresponse_otp_secret_and_more.py +46 -0
- django_cfg/apps/accounts/models.py +3 -123
- django_cfg/apps/accounts/serializers/otp.py +40 -44
- django_cfg/apps/accounts/serializers/profile.py +0 -2
- django_cfg/apps/accounts/services/otp_service.py +98 -186
- django_cfg/apps/accounts/signals.py +25 -15
- django_cfg/apps/accounts/utils/auth_email_service.py +84 -0
- django_cfg/apps/accounts/views/otp.py +35 -36
- django_cfg/apps/agents/README.md +129 -0
- django_cfg/apps/agents/__init__.py +68 -0
- django_cfg/apps/agents/admin/__init__.py +17 -0
- django_cfg/apps/agents/admin/execution_admin.py +460 -0
- django_cfg/apps/agents/admin/registry_admin.py +360 -0
- django_cfg/apps/agents/admin/toolsets_admin.py +482 -0
- django_cfg/apps/agents/apps.py +29 -0
- django_cfg/apps/agents/core/__init__.py +20 -0
- django_cfg/apps/agents/core/agent.py +281 -0
- django_cfg/apps/agents/core/dependencies.py +154 -0
- django_cfg/apps/agents/core/exceptions.py +66 -0
- django_cfg/apps/agents/core/models.py +106 -0
- django_cfg/apps/agents/core/orchestrator.py +391 -0
- django_cfg/apps/agents/examples/__init__.py +3 -0
- django_cfg/apps/agents/examples/simple_example.py +161 -0
- django_cfg/apps/agents/integration/__init__.py +14 -0
- django_cfg/apps/agents/integration/middleware.py +80 -0
- django_cfg/apps/agents/integration/registry.py +345 -0
- django_cfg/apps/agents/integration/signals.py +50 -0
- django_cfg/apps/agents/management/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/create_agent.py +365 -0
- django_cfg/apps/agents/management/commands/orchestrator_status.py +191 -0
- django_cfg/apps/agents/managers/__init__.py +23 -0
- django_cfg/apps/agents/managers/execution.py +236 -0
- django_cfg/apps/agents/managers/registry.py +254 -0
- django_cfg/apps/agents/managers/toolsets.py +496 -0
- django_cfg/apps/agents/migrations/0001_initial.py +286 -0
- django_cfg/apps/agents/migrations/__init__.py +5 -0
- django_cfg/apps/agents/models/__init__.py +15 -0
- django_cfg/apps/agents/models/execution.py +215 -0
- django_cfg/apps/agents/models/registry.py +220 -0
- django_cfg/apps/agents/models/toolsets.py +305 -0
- django_cfg/apps/agents/patterns/__init__.py +24 -0
- django_cfg/apps/agents/patterns/content_agents.py +234 -0
- django_cfg/apps/agents/toolsets/__init__.py +15 -0
- django_cfg/apps/agents/toolsets/cache_toolset.py +285 -0
- django_cfg/apps/agents/toolsets/django_toolset.py +220 -0
- django_cfg/apps/agents/toolsets/file_toolset.py +324 -0
- django_cfg/apps/agents/toolsets/orm_toolset.py +319 -0
- django_cfg/apps/agents/urls.py +46 -0
- django_cfg/apps/knowbase/README.md +150 -0
- django_cfg/apps/knowbase/__init__.py +27 -0
- django_cfg/apps/knowbase/admin/__init__.py +23 -0
- django_cfg/apps/knowbase/admin/archive_admin.py +857 -0
- django_cfg/apps/knowbase/admin/chat_admin.py +386 -0
- django_cfg/apps/knowbase/admin/document_admin.py +650 -0
- django_cfg/apps/knowbase/admin/external_data_admin.py +685 -0
- django_cfg/apps/knowbase/apps.py +81 -0
- django_cfg/apps/knowbase/config/README.md +176 -0
- django_cfg/apps/knowbase/config/__init__.py +51 -0
- django_cfg/apps/knowbase/config/constance_fields.py +186 -0
- django_cfg/apps/knowbase/config/constance_settings.py +200 -0
- django_cfg/apps/knowbase/config/settings.py +444 -0
- django_cfg/apps/knowbase/examples/__init__.py +3 -0
- django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
- django_cfg/apps/knowbase/management/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/knowbase_stats.py +158 -0
- django_cfg/apps/knowbase/management/commands/setup_knowbase.py +59 -0
- django_cfg/apps/knowbase/managers/__init__.py +22 -0
- django_cfg/apps/knowbase/managers/archive.py +426 -0
- django_cfg/apps/knowbase/managers/base.py +32 -0
- django_cfg/apps/knowbase/managers/chat.py +141 -0
- django_cfg/apps/knowbase/managers/document.py +203 -0
- django_cfg/apps/knowbase/managers/external_data.py +471 -0
- django_cfg/apps/knowbase/migrations/0001_initial.py +427 -0
- django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +434 -0
- django_cfg/apps/knowbase/migrations/__init__.py +5 -0
- django_cfg/apps/knowbase/mixins/__init__.py +15 -0
- django_cfg/apps/knowbase/mixins/config.py +108 -0
- django_cfg/apps/knowbase/mixins/creator.py +81 -0
- django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +813 -0
- django_cfg/apps/knowbase/mixins/service.py +362 -0
- django_cfg/apps/knowbase/models/__init__.py +41 -0
- django_cfg/apps/knowbase/models/archive.py +599 -0
- django_cfg/apps/knowbase/models/base.py +58 -0
- django_cfg/apps/knowbase/models/chat.py +157 -0
- django_cfg/apps/knowbase/models/document.py +267 -0
- django_cfg/apps/knowbase/models/external_data.py +376 -0
- django_cfg/apps/knowbase/serializers/__init__.py +68 -0
- django_cfg/apps/knowbase/serializers/archive_serializers.py +386 -0
- django_cfg/apps/knowbase/serializers/chat_serializers.py +137 -0
- django_cfg/apps/knowbase/serializers/document_serializers.py +94 -0
- django_cfg/apps/knowbase/serializers/external_data_serializers.py +256 -0
- django_cfg/apps/knowbase/serializers/public_serializers.py +74 -0
- django_cfg/apps/knowbase/services/__init__.py +40 -0
- django_cfg/apps/knowbase/services/archive/__init__.py +42 -0
- django_cfg/apps/knowbase/services/archive/archive_service.py +541 -0
- django_cfg/apps/knowbase/services/archive/chunking_service.py +791 -0
- django_cfg/apps/knowbase/services/archive/exceptions.py +52 -0
- django_cfg/apps/knowbase/services/archive/extraction_service.py +508 -0
- django_cfg/apps/knowbase/services/archive/vectorization_service.py +362 -0
- django_cfg/apps/knowbase/services/base.py +53 -0
- django_cfg/apps/knowbase/services/chat_service.py +239 -0
- django_cfg/apps/knowbase/services/document_service.py +144 -0
- django_cfg/apps/knowbase/services/embedding/__init__.py +43 -0
- django_cfg/apps/knowbase/services/embedding/async_processor.py +244 -0
- django_cfg/apps/knowbase/services/embedding/batch_processor.py +250 -0
- django_cfg/apps/knowbase/services/embedding/batch_result.py +61 -0
- django_cfg/apps/knowbase/services/embedding/models.py +229 -0
- django_cfg/apps/knowbase/services/embedding/processors.py +148 -0
- django_cfg/apps/knowbase/services/embedding/utils.py +176 -0
- django_cfg/apps/knowbase/services/prompt_builder.py +191 -0
- django_cfg/apps/knowbase/services/search_service.py +293 -0
- django_cfg/apps/knowbase/signals/__init__.py +21 -0
- django_cfg/apps/knowbase/signals/archive_signals.py +211 -0
- django_cfg/apps/knowbase/signals/chat_signals.py +37 -0
- django_cfg/apps/knowbase/signals/document_signals.py +143 -0
- django_cfg/apps/knowbase/signals/external_data_signals.py +157 -0
- django_cfg/apps/knowbase/tasks/__init__.py +39 -0
- django_cfg/apps/knowbase/tasks/archive_tasks.py +316 -0
- django_cfg/apps/knowbase/tasks/document_processing.py +341 -0
- django_cfg/apps/knowbase/tasks/external_data_tasks.py +341 -0
- django_cfg/apps/knowbase/tasks/maintenance.py +195 -0
- django_cfg/apps/knowbase/urls.py +43 -0
- django_cfg/apps/knowbase/utils/__init__.py +12 -0
- django_cfg/apps/knowbase/utils/chunk_settings.py +261 -0
- django_cfg/apps/knowbase/utils/text_processing.py +375 -0
- django_cfg/apps/knowbase/utils/validation.py +99 -0
- django_cfg/apps/knowbase/views/__init__.py +28 -0
- django_cfg/apps/knowbase/views/archive_views.py +469 -0
- django_cfg/apps/knowbase/views/base.py +49 -0
- django_cfg/apps/knowbase/views/chat_views.py +181 -0
- django_cfg/apps/knowbase/views/document_views.py +183 -0
- django_cfg/apps/knowbase/views/public_views.py +129 -0
- django_cfg/apps/leads/admin.py +70 -0
- django_cfg/apps/newsletter/admin.py +234 -0
- django_cfg/apps/newsletter/admin_filters.py +124 -0
- django_cfg/apps/support/admin.py +196 -0
- django_cfg/apps/support/admin_filters.py +71 -0
- django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
- django_cfg/apps/urls.py +5 -4
- django_cfg/cli/README.md +1 -1
- django_cfg/cli/commands/create_project.py +2 -2
- django_cfg/cli/commands/info.py +1 -1
- django_cfg/config.py +44 -0
- django_cfg/core/config.py +29 -82
- django_cfg/core/environment.py +1 -1
- django_cfg/core/generation.py +19 -107
- django_cfg/{integration.py → core/integration.py} +18 -16
- django_cfg/core/validation.py +1 -1
- django_cfg/management/__init__.py +1 -1
- django_cfg/management/commands/__init__.py +1 -1
- django_cfg/management/commands/auto_generate.py +482 -0
- django_cfg/management/commands/migrator.py +19 -101
- django_cfg/management/commands/test_email.py +1 -1
- django_cfg/middleware/README.md +0 -158
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/api.py +145 -0
- django_cfg/models/base.py +287 -0
- django_cfg/models/cache.py +4 -4
- django_cfg/models/constance.py +25 -88
- django_cfg/models/database.py +9 -9
- django_cfg/models/drf.py +3 -36
- django_cfg/models/email.py +163 -0
- django_cfg/models/environment.py +276 -0
- django_cfg/models/limits.py +1 -1
- django_cfg/models/logging.py +366 -0
- django_cfg/models/revolution.py +41 -2
- django_cfg/models/security.py +125 -0
- django_cfg/models/services.py +1 -1
- django_cfg/modules/__init__.py +2 -56
- django_cfg/modules/base.py +78 -52
- django_cfg/modules/django_currency/service.py +2 -2
- django_cfg/modules/django_email.py +2 -2
- django_cfg/modules/django_health.py +267 -0
- django_cfg/modules/django_llm/llm/client.py +79 -17
- django_cfg/modules/django_llm/translator/translator.py +2 -2
- django_cfg/modules/django_logger.py +2 -2
- django_cfg/modules/django_ngrok.py +2 -2
- django_cfg/modules/django_tasks.py +68 -3
- django_cfg/modules/django_telegram.py +3 -3
- django_cfg/modules/django_twilio/sendgrid_service.py +2 -2
- django_cfg/modules/django_twilio/service.py +2 -2
- django_cfg/modules/django_twilio/simple_service.py +2 -2
- django_cfg/modules/django_twilio/templates/guide.md +266 -0
- django_cfg/modules/django_twilio/twilio_service.py +2 -2
- django_cfg/modules/django_unfold/__init__.py +69 -0
- django_cfg/modules/{unfold → django_unfold}/callbacks.py +23 -22
- django_cfg/modules/django_unfold/dashboard.py +278 -0
- django_cfg/modules/django_unfold/icons/README.md +145 -0
- django_cfg/modules/django_unfold/icons/__init__.py +12 -0
- django_cfg/modules/django_unfold/icons/constants.py +2851 -0
- django_cfg/modules/django_unfold/icons/generate_icons.py +486 -0
- django_cfg/modules/django_unfold/models/__init__.py +42 -0
- django_cfg/modules/django_unfold/models/config.py +601 -0
- django_cfg/modules/django_unfold/models/dashboard.py +206 -0
- django_cfg/modules/django_unfold/models/dropdown.py +40 -0
- django_cfg/modules/django_unfold/models/navigation.py +73 -0
- django_cfg/modules/django_unfold/models/tabs.py +25 -0
- django_cfg/modules/{unfold → django_unfold}/system_monitor.py +2 -2
- django_cfg/modules/django_unfold/utils.py +140 -0
- django_cfg/registry/__init__.py +23 -0
- django_cfg/registry/core.py +61 -0
- django_cfg/registry/exceptions.py +11 -0
- django_cfg/registry/modules.py +12 -0
- django_cfg/registry/services.py +26 -0
- django_cfg/registry/third_party.py +52 -0
- django_cfg/routing/__init__.py +19 -0
- django_cfg/routing/callbacks.py +198 -0
- django_cfg/routing/routers.py +48 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +8 -9
- django_cfg/templatetags/__init__.py +0 -0
- django_cfg/templatetags/django_cfg.py +33 -0
- django_cfg/urls.py +33 -0
- django_cfg/utils/path_resolution.py +1 -1
- django_cfg/utils/smart_defaults.py +7 -61
- django_cfg/utils/toolkit.py +663 -0
- {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
- django_cfg-1.2.0.dist-info/RECORD +441 -0
- django_cfg/apps/tasks/@docs/README.md +0 -195
- django_cfg/archive/django_sample.zip +0 -0
- django_cfg/models/unfold.py +0 -271
- django_cfg/modules/unfold/__init__.py +0 -29
- django_cfg/modules/unfold/dashboard.py +0 -318
- django_cfg/pyproject.toml +0 -370
- django_cfg/routers.py +0 -83
- django_cfg-1.1.81.dist-info/RECORD +0 -278
- /django_cfg/{exceptions.py → core/exceptions.py} +0 -0
- /django_cfg/modules/{unfold → django_unfold}/models.py +0 -0
- /django_cfg/modules/{unfold → django_unfold}/tailwind.py +0 -0
- /django_cfg/{version_check.py → utils/version_check.py} +0 -0
- {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
# 🚀 Django CFG Twilio Integration - Complete Setup Guide
|
2
|
+
|
3
|
+
## 📋 Overview
|
4
|
+
|
5
|
+
Django CFG Twilio provides seamless integration for:
|
6
|
+
- 📱 **WhatsApp OTP** via Twilio Verify API
|
7
|
+
- 📱 **SMS OTP** via Twilio Verify API
|
8
|
+
- 📧 **Email OTP** via SendGrid
|
9
|
+
- 🔧 **Testing Suite** with management commands
|
10
|
+
- 📧 **HTML Email Templates** with customization
|
11
|
+
|
12
|
+
## 🛠️ Quick Setup (5 minutes)
|
13
|
+
|
14
|
+
### 1. Install Dependencies
|
15
|
+
```bash
|
16
|
+
pip install django-cfg[twilio]
|
17
|
+
# or
|
18
|
+
poetry add django-cfg[twilio]
|
19
|
+
```
|
20
|
+
|
21
|
+
### 2. Configure Twilio Services
|
22
|
+
|
23
|
+
#### A. Create Twilio Verify Service
|
24
|
+
1. Go to [Twilio Console > Verify > Services](https://console.twilio.com/us1/develop/verify/services)
|
25
|
+
2. Click **Create new Service**
|
26
|
+
3. Name: `YourApp OTP Service`
|
27
|
+
4. **Enable channels**: WhatsApp ✅, SMS ✅
|
28
|
+
5. Copy the **Service SID** (starts with `VA...`)
|
29
|
+
|
30
|
+
#### B. Get SendGrid API Key (Optional)
|
31
|
+
1. Go to [SendGrid Console > API Keys](https://app.sendgrid.com/settings/api_keys)
|
32
|
+
2. Create new API key with **Mail Send** permissions
|
33
|
+
3. Copy the API key (starts with `SG.`)
|
34
|
+
|
35
|
+
### 3. Update Configuration Files
|
36
|
+
|
37
|
+
#### `config.dev.yaml`
|
38
|
+
```yaml
|
39
|
+
twilio:
|
40
|
+
account_sid: "AC_YOUR_ACCOUNT_SID"
|
41
|
+
auth_token: "YOUR_AUTH_TOKEN"
|
42
|
+
whatsapp_from: "+14155238886" # Twilio sandbox
|
43
|
+
sms_from: "+YOUR_SMS_NUMBER"
|
44
|
+
sendgrid_api_key: "SG.YOUR_SENDGRID_API_KEY"
|
45
|
+
verify_service_sid: "VA_YOUR_VERIFY_SERVICE_SID"
|
46
|
+
```
|
47
|
+
|
48
|
+
#### `config.py`
|
49
|
+
```python
|
50
|
+
from django_cfg.modules.django_twilio.models import SendGridConfig, TwilioVerifyConfig, TwilioChannelType
|
51
|
+
|
52
|
+
class YourProjectConfig(DjangoConfig):
|
53
|
+
# Admin emails for testing
|
54
|
+
admin_emails: List[str] = ["admin@yourdomain.com"]
|
55
|
+
|
56
|
+
# Twilio configuration
|
57
|
+
twilio: Optional[TwilioConfig] = TwilioConfig(
|
58
|
+
account_sid=env.twilio.account_sid,
|
59
|
+
auth_token=SecretStr(env.twilio.auth_token),
|
60
|
+
|
61
|
+
# Verify API for OTP
|
62
|
+
verify=TwilioVerifyConfig(
|
63
|
+
service_sid=env.twilio.verify_service_sid,
|
64
|
+
service_name=env.app.name,
|
65
|
+
default_channel=TwilioChannelType.WHATSAPP,
|
66
|
+
fallback_channels=[TwilioChannelType.SMS],
|
67
|
+
code_length=6,
|
68
|
+
ttl_seconds=600, # 10 minutes
|
69
|
+
max_attempts=5,
|
70
|
+
) if env.twilio.verify_service_sid else None,
|
71
|
+
|
72
|
+
# SendGrid for email
|
73
|
+
sendgrid=SendGridConfig(
|
74
|
+
api_key=SecretStr(env.twilio.sendgrid_api_key),
|
75
|
+
from_email="noreply@yourdomain.com",
|
76
|
+
from_name=env.app.name,
|
77
|
+
default_subject=f"Your {env.app.name} verification code",
|
78
|
+
) if env.twilio.sendgrid_api_key else None,
|
79
|
+
) if env.twilio.account_sid and env.twilio.auth_token else None
|
80
|
+
```
|
81
|
+
|
82
|
+
## 🧪 Testing Everything
|
83
|
+
|
84
|
+
### Quick Test Command
|
85
|
+
```bash
|
86
|
+
# Test all services
|
87
|
+
python manage.py test_twilio --mode=all
|
88
|
+
|
89
|
+
# Test OTP only
|
90
|
+
python manage.py test_twilio --mode=test-otp --phone="+1234567890"
|
91
|
+
|
92
|
+
# Interactive mode
|
93
|
+
python manage.py test_twilio --interactive
|
94
|
+
|
95
|
+
# Check configuration
|
96
|
+
python manage.py test_twilio --mode=setup
|
97
|
+
```
|
98
|
+
|
99
|
+
### Expected Output
|
100
|
+
```
|
101
|
+
🚀 Django CFG Twilio Test Suite
|
102
|
+
==================================================
|
103
|
+
📧 Using admin email from config: admin@yourdomain.com
|
104
|
+
|
105
|
+
🔧 Configuration Check
|
106
|
+
------------------------------
|
107
|
+
✅ Admin emails configured
|
108
|
+
✅ Twilio configuration found
|
109
|
+
✅ Verify API configured
|
110
|
+
✅ SendGrid configured
|
111
|
+
✅ Email configuration found
|
112
|
+
|
113
|
+
🔐 Testing OTP Functionality
|
114
|
+
------------------------------
|
115
|
+
📱 Testing WhatsApp OTP to +1234567890...
|
116
|
+
✅ OTP sent via WhatsApp to ***7890
|
117
|
+
|
118
|
+
📧 Testing Email OTP to admin@yourdomain.com...
|
119
|
+
✅ Email OTP sent (code: 123456)
|
120
|
+
|
121
|
+
🎉 All tests completed!
|
122
|
+
```
|
123
|
+
|
124
|
+
## 🔌 API Usage
|
125
|
+
|
126
|
+
### Basic OTP Request
|
127
|
+
```python
|
128
|
+
from django_cfg.modules.django_twilio import send_whatsapp_otp, verify_otp
|
129
|
+
|
130
|
+
# Send WhatsApp OTP
|
131
|
+
success, message = send_whatsapp_otp("+1234567890")
|
132
|
+
|
133
|
+
# Verify OTP
|
134
|
+
is_valid, message = verify_otp("+1234567890", "123456")
|
135
|
+
```
|
136
|
+
|
137
|
+
### Email OTP
|
138
|
+
```python
|
139
|
+
from django_cfg.modules.django_twilio import send_otp_email
|
140
|
+
|
141
|
+
# Send email OTP
|
142
|
+
success, message, otp_code = send_otp_email("user@example.com")
|
143
|
+
```
|
144
|
+
|
145
|
+
### REST API Endpoints
|
146
|
+
```bash
|
147
|
+
# Request OTP
|
148
|
+
curl -X POST http://localhost:8000/api/accounts/otp/request/ \
|
149
|
+
-H "Content-Type: application/json" \
|
150
|
+
-d '{"identifier": "+1234567890", "channel": "phone"}'
|
151
|
+
|
152
|
+
# Verify OTP
|
153
|
+
curl -X POST http://localhost:8000/api/accounts/otp/verify/ \
|
154
|
+
-H "Content-Type: application/json" \
|
155
|
+
-d '{"identifier": "+1234567890", "otp": "123456", "channel": "phone"}'
|
156
|
+
```
|
157
|
+
|
158
|
+
## 📧 Email Templates
|
159
|
+
|
160
|
+
### Template Structure
|
161
|
+
```
|
162
|
+
django_cfg/modules/django_twilio/templates/
|
163
|
+
├── email_otp_template.html # Main HTML template
|
164
|
+
├── email_otp_test_data.json # Test data
|
165
|
+
└── email_otp_rendered.html # Generated preview
|
166
|
+
```
|
167
|
+
|
168
|
+
### Template Variables
|
169
|
+
- `{{app_name}}` - Your app name
|
170
|
+
- `{{user_name}}` - User's name
|
171
|
+
- `{{otp_code}}` - 6-digit OTP code
|
172
|
+
- `{{otp_link}}` - Verification link
|
173
|
+
- `{{expires_minutes}}` - Expiry time
|
174
|
+
|
175
|
+
### Generate Templates
|
176
|
+
```bash
|
177
|
+
python manage.py test_twilio --mode=generate-templates
|
178
|
+
```
|
179
|
+
|
180
|
+
## 🚨 Troubleshooting
|
181
|
+
|
182
|
+
### Common Issues
|
183
|
+
|
184
|
+
#### 1. WhatsApp Not Working
|
185
|
+
```
|
186
|
+
❌ Error: Unable to create record: Delivery channel disabled: WHATSAPP
|
187
|
+
```
|
188
|
+
**Solution**: Enable WhatsApp channel in [Twilio Console > Verify > Services](https://console.twilio.com/us1/develop/verify/services)
|
189
|
+
|
190
|
+
#### 2. SMS to International Numbers
|
191
|
+
```
|
192
|
+
❌ Error: Message cannot be sent with current 'To' and 'From' parameters
|
193
|
+
```
|
194
|
+
**Solution**: Use Verify API (automatic) or upgrade Twilio account for international SMS
|
195
|
+
|
196
|
+
#### 3. SendGrid Not Working
|
197
|
+
```
|
198
|
+
❌ Error: SendGrid configuration not found
|
199
|
+
```
|
200
|
+
**Solution**: Add `sendgrid_api_key` to your YAML config and enable in `config.py`
|
201
|
+
|
202
|
+
#### 4. Email Not Sending
|
203
|
+
```
|
204
|
+
❌ Error: Email backend not configured
|
205
|
+
```
|
206
|
+
**Solution**: Check email configuration in `config.py` and ensure SMTP settings are correct
|
207
|
+
|
208
|
+
### Debug Mode
|
209
|
+
```python
|
210
|
+
# Enable detailed logging
|
211
|
+
twilio: TwilioConfig = TwilioConfig(
|
212
|
+
debug_logging=True, # Shows all API requests/responses
|
213
|
+
test_mode=True, # Uses test credentials
|
214
|
+
)
|
215
|
+
```
|
216
|
+
|
217
|
+
## 📱 Production Checklist
|
218
|
+
|
219
|
+
### Before Going Live:
|
220
|
+
|
221
|
+
#### Twilio Setup
|
222
|
+
- [ ] **Account verified** and upgraded from trial
|
223
|
+
- [ ] **Phone numbers verified** for SMS
|
224
|
+
- [ ] **WhatsApp Business approved** (if using production WhatsApp)
|
225
|
+
- [ ] **Verify Service** created and channels enabled
|
226
|
+
- [ ] **Webhook URLs** configured (optional)
|
227
|
+
|
228
|
+
#### SendGrid Setup
|
229
|
+
- [ ] **Domain authentication** completed
|
230
|
+
- [ ] **Sender identity** verified
|
231
|
+
- [ ] **API key** with proper permissions
|
232
|
+
- [ ] **Email templates** tested and approved
|
233
|
+
|
234
|
+
#### Security
|
235
|
+
- [ ] **Environment variables** for sensitive data
|
236
|
+
- [ ] **Rate limiting** configured
|
237
|
+
- [ ] **Admin emails** updated for production
|
238
|
+
- [ ] **Error monitoring** setup (Sentry, etc.)
|
239
|
+
|
240
|
+
#### Testing
|
241
|
+
- [ ] **All OTP channels** tested with real numbers
|
242
|
+
- [ ] **Email delivery** tested with real addresses
|
243
|
+
- [ ] **Error handling** tested with invalid inputs
|
244
|
+
- [ ] **Load testing** completed for expected volume
|
245
|
+
|
246
|
+
## 🔗 Useful Links
|
247
|
+
|
248
|
+
- [Twilio Console](https://console.twilio.com/)
|
249
|
+
- [Twilio Verify API Docs](https://www.twilio.com/docs/verify/api)
|
250
|
+
- [SendGrid Console](https://app.sendgrid.com/)
|
251
|
+
- [Django CFG Documentation](https://github.com/your-repo/django-cfg)
|
252
|
+
|
253
|
+
## 💡 Pro Tips
|
254
|
+
|
255
|
+
1. **Use Verify API** for professional OTP instead of custom solutions
|
256
|
+
2. **Enable both WhatsApp and SMS** for better delivery rates
|
257
|
+
3. **Test with real numbers** in different countries
|
258
|
+
4. **Monitor delivery rates** in Twilio Console
|
259
|
+
5. **Use admin_emails** for easy testing configuration
|
260
|
+
6. **Keep templates simple** for better email client compatibility
|
261
|
+
|
262
|
+
---
|
263
|
+
|
264
|
+
🎉 **You're all set!** Your Django CFG Twilio integration is ready for production use.
|
265
|
+
|
266
|
+
For support, check the troubleshooting section or create an issue on GitHub.
|
@@ -17,7 +17,7 @@ from twilio.rest import Client
|
|
17
17
|
from twilio.base.exceptions import TwilioException
|
18
18
|
from asgiref.sync import sync_to_async
|
19
19
|
|
20
|
-
from django_cfg.modules.base import
|
20
|
+
from django_cfg.modules.base import BaseCfgModule
|
21
21
|
from django_cfg.modules.django_twilio.models import TwilioConfig, TwilioVerifyConfig
|
22
22
|
from django_cfg.modules.django_twilio.exceptions import (
|
23
23
|
TwilioConfigurationError,
|
@@ -27,7 +27,7 @@ from django_cfg.modules.django_twilio.exceptions import (
|
|
27
27
|
logger = logging.getLogger(__name__)
|
28
28
|
|
29
29
|
|
30
|
-
class TwilioService(
|
30
|
+
class TwilioService(BaseCfgModule):
|
31
31
|
"""
|
32
32
|
Unified Twilio service for WhatsApp, SMS, and OTP.
|
33
33
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
"""
|
2
|
+
Django CFG Unfold Module
|
3
|
+
|
4
|
+
Provides complete Unfold admin interface integration with dashboard,
|
5
|
+
navigation, theming, and callback support.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .dashboard import DashboardManager, get_dashboard_manager
|
9
|
+
from .callbacks import UnfoldCallbacks
|
10
|
+
from .system_monitor import SystemMonitor
|
11
|
+
from .tailwind import get_unfold_colors, get_css_variables
|
12
|
+
from .models import *
|
13
|
+
|
14
|
+
# Lazy initialization functions to avoid circular imports
|
15
|
+
def get_system_monitor() -> SystemMonitor:
|
16
|
+
"""Get the global system monitor instance."""
|
17
|
+
global _system_monitor
|
18
|
+
if '_system_monitor' not in globals():
|
19
|
+
globals()['_system_monitor'] = SystemMonitor()
|
20
|
+
return globals()['_system_monitor']
|
21
|
+
|
22
|
+
def get_unfold_callbacks() -> UnfoldCallbacks:
|
23
|
+
"""Get the global unfold callbacks instance."""
|
24
|
+
global _unfold_callbacks
|
25
|
+
if '_unfold_callbacks' not in globals():
|
26
|
+
globals()['_unfold_callbacks'] = UnfoldCallbacks()
|
27
|
+
return globals()['_unfold_callbacks']
|
28
|
+
|
29
|
+
# Export main components
|
30
|
+
__all__ = [
|
31
|
+
'DashboardManager',
|
32
|
+
'get_dashboard_manager',
|
33
|
+
'UnfoldCallbacks',
|
34
|
+
'get_unfold_callbacks',
|
35
|
+
'SystemMonitor',
|
36
|
+
'get_system_monitor',
|
37
|
+
'get_unfold_colors',
|
38
|
+
'get_css_variables',
|
39
|
+
# Models
|
40
|
+
'UnfoldConfig',
|
41
|
+
'UnfoldTheme',
|
42
|
+
'UnfoldColors',
|
43
|
+
'UnfoldSidebar',
|
44
|
+
'UnfoldThemeConfig',
|
45
|
+
'UnfoldDashboardConfig',
|
46
|
+
'NavigationItem',
|
47
|
+
'NavigationSection',
|
48
|
+
'NavigationItemType',
|
49
|
+
'SiteDropdownItem',
|
50
|
+
'StatCard',
|
51
|
+
'SystemHealthItem',
|
52
|
+
'QuickAction',
|
53
|
+
'DashboardWidget',
|
54
|
+
'DashboardData',
|
55
|
+
'ChartDataset',
|
56
|
+
'ChartData',
|
57
|
+
'TabConfiguration',
|
58
|
+
'TabItem',
|
59
|
+
]
|
60
|
+
|
61
|
+
# Version info
|
62
|
+
__version__ = '1.0.0'
|
63
|
+
__author__ = 'Django CFG Team'
|
64
|
+
__email__ = 'team@djangocfg.com'
|
65
|
+
|
66
|
+
# Module metadata
|
67
|
+
__title__ = 'Django CFG Unfold'
|
68
|
+
__description__ = 'Complete Unfold admin interface integration'
|
69
|
+
__url__ = 'https://github.com/djangocfg/django-cfg'
|
@@ -21,8 +21,9 @@ from django.db import connection
|
|
21
21
|
from django.core.cache import cache
|
22
22
|
from django.apps import apps
|
23
23
|
|
24
|
-
from ..base import
|
25
|
-
from .models import DashboardData, StatCard, SystemHealthItem, QuickAction
|
24
|
+
from ..base import BaseCfgModule
|
25
|
+
from .models.dashboard import DashboardData, StatCard, SystemHealthItem, QuickAction
|
26
|
+
from .icons import Icons
|
26
27
|
|
27
28
|
logger = logging.getLogger(__name__)
|
28
29
|
|
@@ -119,7 +120,7 @@ def get_user_admin_urls():
|
|
119
120
|
}
|
120
121
|
|
121
122
|
|
122
|
-
class UnfoldCallbacks(
|
123
|
+
class UnfoldCallbacks(BaseCfgModule):
|
123
124
|
"""
|
124
125
|
Base Unfold dashboard callbacks with full system monitoring.
|
125
126
|
|
@@ -148,7 +149,7 @@ class UnfoldCallbacks(BaseModule):
|
|
148
149
|
StatCard(
|
149
150
|
title="Total Users",
|
150
151
|
value=f"{total_users:,}",
|
151
|
-
icon=
|
152
|
+
icon=Icons.PEOPLE,
|
152
153
|
change=f"+{new_users_7d}" if new_users_7d > 0 else None,
|
153
154
|
change_type="positive" if new_users_7d > 0 else "neutral",
|
154
155
|
description="Registered users",
|
@@ -156,7 +157,7 @@ class UnfoldCallbacks(BaseModule):
|
|
156
157
|
StatCard(
|
157
158
|
title="Active Users",
|
158
159
|
value=f"{active_users:,}",
|
159
|
-
icon=
|
160
|
+
icon=Icons.PERSON,
|
160
161
|
change=(
|
161
162
|
f"{(active_users/total_users*100):.1f}%"
|
162
163
|
if total_users > 0
|
@@ -170,14 +171,14 @@ class UnfoldCallbacks(BaseModule):
|
|
170
171
|
StatCard(
|
171
172
|
title="New This Week",
|
172
173
|
value=f"{new_users_7d:,}",
|
173
|
-
icon=
|
174
|
+
icon=Icons.PERSON_ADD,
|
174
175
|
change_type="positive" if new_users_7d > 0 else "neutral",
|
175
176
|
description="Last 7 days",
|
176
177
|
),
|
177
178
|
StatCard(
|
178
179
|
title="Staff Members",
|
179
180
|
value=f"{staff_users:,}",
|
180
|
-
icon=
|
181
|
+
icon=Icons.ADMIN_PANEL_SETTINGS,
|
181
182
|
change=(
|
182
183
|
f"{(staff_users/total_users*100):.1f}%" if total_users > 0 else "0%"
|
183
184
|
),
|
@@ -191,7 +192,7 @@ class UnfoldCallbacks(BaseModule):
|
|
191
192
|
StatCard(
|
192
193
|
title="Users",
|
193
194
|
value="N/A",
|
194
|
-
icon=
|
195
|
+
icon=Icons.PEOPLE,
|
195
196
|
description="Data unavailable",
|
196
197
|
)
|
197
198
|
]
|
@@ -316,7 +317,7 @@ class UnfoldCallbacks(BaseModule):
|
|
316
317
|
QuickAction(
|
317
318
|
title="Add User",
|
318
319
|
description="Create new user account",
|
319
|
-
icon=
|
320
|
+
icon=Icons.PERSON_ADD,
|
320
321
|
link=user_admin_urls["add"],
|
321
322
|
color="primary",
|
322
323
|
category="admin",
|
@@ -324,16 +325,16 @@ class UnfoldCallbacks(BaseModule):
|
|
324
325
|
QuickAction(
|
325
326
|
title="Support Tickets",
|
326
327
|
description="Manage support tickets",
|
327
|
-
icon=
|
328
|
+
icon=Icons.SUPPORT_AGENT,
|
328
329
|
link="admin:django_cfg_support_ticket_changelist",
|
329
|
-
color="
|
330
|
+
color="primary",
|
330
331
|
category="support",
|
331
332
|
),
|
332
333
|
QuickAction(
|
333
334
|
title="Health Check",
|
334
335
|
description="System health status",
|
335
|
-
icon=
|
336
|
-
link="
|
336
|
+
icon=Icons.HEALTH_AND_SAFETY,
|
337
|
+
link="/cfg/health/",
|
337
338
|
color="success",
|
338
339
|
category="system",
|
339
340
|
),
|
@@ -382,7 +383,7 @@ class UnfoldCallbacks(BaseModule):
|
|
382
383
|
StatCard(
|
383
384
|
title="Total Tickets",
|
384
385
|
value=f"{total_tickets:,}",
|
385
|
-
icon=
|
386
|
+
icon=Icons.SUPPORT_AGENT,
|
386
387
|
change=f"+{new_tickets_7d}" if new_tickets_7d > 0 else None,
|
387
388
|
change_type="positive" if new_tickets_7d > 0 else "neutral",
|
388
389
|
description="All support tickets",
|
@@ -390,7 +391,7 @@ class UnfoldCallbacks(BaseModule):
|
|
390
391
|
StatCard(
|
391
392
|
title="Open Tickets",
|
392
393
|
value=f"{open_tickets:,}",
|
393
|
-
icon=
|
394
|
+
icon=Icons.PENDING,
|
394
395
|
change=(
|
395
396
|
f"{(open_tickets/total_tickets*100):.1f}%"
|
396
397
|
if total_tickets > 0
|
@@ -406,7 +407,7 @@ class UnfoldCallbacks(BaseModule):
|
|
406
407
|
StatCard(
|
407
408
|
title="Resolved",
|
408
409
|
value=f"{resolved_tickets:,}",
|
409
|
-
icon=
|
410
|
+
icon=Icons.CHECK_CIRCLE,
|
410
411
|
change=(
|
411
412
|
f"{(resolved_tickets/total_tickets*100):.1f}%"
|
412
413
|
if total_tickets > 0
|
@@ -418,7 +419,7 @@ class UnfoldCallbacks(BaseModule):
|
|
418
419
|
StatCard(
|
419
420
|
title="New This Week",
|
420
421
|
value=f"{new_tickets_7d:,}",
|
421
|
-
icon=
|
422
|
+
icon=Icons.NEW_RELEASES,
|
422
423
|
change_type="positive" if new_tickets_7d > 0 else "neutral",
|
423
424
|
description="Last 7 days",
|
424
425
|
),
|
@@ -429,7 +430,7 @@ class UnfoldCallbacks(BaseModule):
|
|
429
430
|
StatCard(
|
430
431
|
title="Support",
|
431
432
|
value="N/A",
|
432
|
-
icon=
|
433
|
+
icon=Icons.SUPPORT_AGENT,
|
433
434
|
description="Data unavailable",
|
434
435
|
)
|
435
436
|
]
|
@@ -707,14 +708,14 @@ class UnfoldCallbacks(BaseModule):
|
|
707
708
|
environment=getattr(settings, "ENVIRONMENT", "development"),
|
708
709
|
)
|
709
710
|
|
710
|
-
# Convert to template context (
|
711
|
-
cards_data = [card.
|
711
|
+
# Convert to template context (using to_dict for Unfold compatibility)
|
712
|
+
cards_data = [card.to_dict() for card in dashboard_data.stat_cards]
|
712
713
|
|
713
714
|
context.update({
|
714
715
|
# Statistics cards
|
715
716
|
"cards": cards_data,
|
716
|
-
"user_stats": [card.
|
717
|
-
"support_stats": [card.
|
717
|
+
"user_stats": [card.to_dict() for card in user_stats],
|
718
|
+
"support_stats": [card.to_dict() for card in support_stats],
|
718
719
|
# System health (convert to dict for template)
|
719
720
|
"system_health": {
|
720
721
|
item.component + "_status": item.status
|