django-cfg 1.3.13__py3-none-any.whl → 1.4.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.
Files changed (438) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/user_admin.py +39 -16
  3. django_cfg/apps/accounts/serializers/profile.py +1 -1
  4. django_cfg/apps/accounts/services/otp_service.py +18 -11
  5. django_cfg/apps/accounts/signals.py +15 -24
  6. django_cfg/apps/accounts/utils/notifications.py +217 -358
  7. django_cfg/apps/accounts/views/otp.py +2 -2
  8. django_cfg/apps/accounts/views/webhook.py +1 -1
  9. django_cfg/apps/agents/core/django_agent.py +1 -1
  10. django_cfg/apps/api/commands/views.py +66 -83
  11. django_cfg/apps/api/health/drf_views.py +269 -0
  12. django_cfg/apps/api/health/serializers.py +45 -0
  13. django_cfg/apps/api/health/urls.py +6 -1
  14. django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
  15. django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
  16. django_cfg/apps/knowbase/admin/document_admin.py +136 -270
  17. django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
  18. django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
  19. django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
  20. django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
  21. django_cfg/apps/knowbase/config/constance_fields.py +1 -1
  22. django_cfg/apps/knowbase/config/settings.py +2 -2
  23. django_cfg/apps/knowbase/mixins/__init__.py +19 -2
  24. django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
  25. django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
  26. django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
  27. django_cfg/apps/knowbase/mixins/creator.py +10 -10
  28. django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
  29. django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
  30. django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
  31. django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
  32. django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
  33. django_cfg/apps/knowbase/mixins/service.py +2 -2
  34. django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
  35. django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
  36. django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
  37. django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
  38. django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
  39. django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
  40. django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
  41. django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
  42. django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
  43. django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
  44. django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
  45. django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
  46. django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
  47. django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
  48. django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
  49. django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
  50. django_cfg/apps/knowbase/services/embedding/models.py +18 -14
  51. django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
  52. django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
  53. django_cfg/apps/leads/tests.py +1 -1
  54. django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
  55. django_cfg/apps/payments/admin/balance_admin.py +1 -1
  56. django_cfg/apps/payments/admin/currencies_admin.py +1 -1
  57. django_cfg/apps/payments/admin/payments_admin.py +1 -1
  58. django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
  59. django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
  60. django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
  61. django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
  62. django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
  63. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
  64. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
  65. django_cfg/apps/payments/admin_interface/views/base.py +29 -2
  66. django_cfg/apps/payments/apps.py +1 -1
  67. django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
  68. django_cfg/apps/payments/config/helpers.py +3 -2
  69. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
  70. django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
  71. django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
  72. django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
  73. django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
  74. django_cfg/apps/payments/management/commands/test_providers.py +1 -1
  75. django_cfg/apps/payments/middleware/api_access.py +1 -1
  76. django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
  77. django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
  78. django_cfg/apps/payments/models/balance.py +2 -2
  79. django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
  80. django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
  81. django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
  82. django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
  83. django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
  84. django_cfg/apps/payments/models/payments.py +2 -2
  85. django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
  86. django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
  87. django_cfg/apps/payments/services/core/base.py +1 -1
  88. django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
  89. django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
  90. django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
  91. django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
  92. django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
  93. django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
  94. django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
  95. django_cfg/apps/payments/services/core/payment_service.py +124 -612
  96. django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
  97. django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
  98. django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
  99. django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
  100. django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
  101. django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
  102. django_cfg/apps/payments/services/providers/base.py +1 -1
  103. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
  104. django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
  105. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
  106. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
  107. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
  108. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
  109. django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
  110. django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
  111. django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
  112. django_cfg/apps/payments/services/providers/registry.py +1 -1
  113. django_cfg/apps/payments/services/providers/sync_service.py +1 -1
  114. django_cfg/apps/payments/signals/__init__.py +1 -1
  115. django_cfg/apps/payments/signals/api_key_signals.py +1 -1
  116. django_cfg/apps/payments/signals/balance_signals.py +1 -1
  117. django_cfg/apps/payments/signals/payment_signals.py +1 -1
  118. django_cfg/apps/payments/signals/subscription_signals.py +1 -1
  119. django_cfg/apps/payments/views/api/api_keys.py +1 -1
  120. django_cfg/apps/payments/views/api/balances.py +1 -1
  121. django_cfg/apps/payments/views/api/base.py +1 -1
  122. django_cfg/apps/payments/views/api/currencies.py +1 -1
  123. django_cfg/apps/payments/views/api/payments.py +1 -1
  124. django_cfg/apps/payments/views/api/subscriptions.py +1 -1
  125. django_cfg/apps/payments/views/api/webhooks.py +1 -1
  126. django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
  127. django_cfg/apps/payments/views/serializers/balances.py +1 -1
  128. django_cfg/apps/payments/views/serializers/currencies.py +1 -1
  129. django_cfg/apps/payments/views/serializers/payments.py +1 -1
  130. django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
  131. django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
  132. django_cfg/apps/support/admin/support_admin.py +21 -13
  133. django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
  134. django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
  135. django_cfg/apps/support/utils/support_email_service.py +1 -1
  136. django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
  137. django_cfg/apps/tasks/utils/simulator.py +1 -1
  138. django_cfg/apps/tasks/views/dashboard.py +33 -3
  139. django_cfg/apps/urls.py +5 -1
  140. django_cfg/cli/README.md +57 -471
  141. django_cfg/cli/commands/create_project.py +140 -529
  142. django_cfg/cli/main.py +13 -10
  143. django_cfg/core/__init__.py +63 -6
  144. django_cfg/core/base/__init__.py +5 -0
  145. django_cfg/core/base/config_model.py +652 -0
  146. django_cfg/core/builders/__init__.py +11 -0
  147. django_cfg/core/builders/apps_builder.py +258 -0
  148. django_cfg/core/builders/middleware_builder.py +115 -0
  149. django_cfg/core/builders/security_builder.py +96 -0
  150. django_cfg/core/config.py +20 -892
  151. django_cfg/core/constants.py +69 -0
  152. django_cfg/core/environment/__init__.py +9 -0
  153. django_cfg/core/exceptions.py +45 -298
  154. django_cfg/core/generation/__init__.py +51 -0
  155. django_cfg/core/generation/core_generators/__init__.py +0 -0
  156. django_cfg/core/generation/core_generators/settings.py +90 -0
  157. django_cfg/core/generation/core_generators/static.py +82 -0
  158. django_cfg/core/generation/core_generators/templates.py +141 -0
  159. django_cfg/core/generation/data_generators/__init__.py +15 -0
  160. django_cfg/core/generation/data_generators/cache.py +132 -0
  161. django_cfg/core/generation/data_generators/database.py +117 -0
  162. django_cfg/core/generation/generation.py +92 -0
  163. django_cfg/core/generation/integration_generators/__init__.py +21 -0
  164. django_cfg/core/generation/integration_generators/api.py +237 -0
  165. django_cfg/core/generation/integration_generators/sessions.py +65 -0
  166. django_cfg/core/generation/integration_generators/tailwind.py +54 -0
  167. django_cfg/core/generation/integration_generators/tasks.py +92 -0
  168. django_cfg/core/generation/integration_generators/third_party.py +144 -0
  169. django_cfg/core/generation/orchestrator.py +285 -0
  170. django_cfg/core/generation/protocols.py +30 -0
  171. django_cfg/core/generation/security_generators/__init__.py +0 -0
  172. django_cfg/core/generation/utility_generators/__init__.py +24 -0
  173. django_cfg/core/generation/utility_generators/email.py +58 -0
  174. django_cfg/core/generation/utility_generators/i18n.py +66 -0
  175. django_cfg/core/generation/utility_generators/limits.py +58 -0
  176. django_cfg/core/generation/utility_generators/logging.py +66 -0
  177. django_cfg/core/generation/utility_generators/security.py +101 -0
  178. django_cfg/core/generation/utils/__init__.py +0 -0
  179. django_cfg/core/generation/utils/helpers.py +32 -0
  180. django_cfg/core/integration/__init__.py +18 -25
  181. django_cfg/core/integration/display/startup.py +146 -133
  182. django_cfg/core/integration/url_integration.py +13 -2
  183. django_cfg/core/services/__init__.py +5 -0
  184. django_cfg/core/services/config_service.py +121 -0
  185. django_cfg/core/state/__init__.py +9 -0
  186. django_cfg/core/state/registry.py +84 -0
  187. django_cfg/core/types/__init__.py +15 -0
  188. django_cfg/core/types/aliases.py +15 -0
  189. django_cfg/core/types/enums.py +49 -0
  190. django_cfg/dashboard/DEBUG_README.md +105 -0
  191. django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
  192. django_cfg/dashboard/__init__.py +24 -0
  193. django_cfg/dashboard/components.py +308 -0
  194. django_cfg/dashboard/debug.py +176 -0
  195. django_cfg/dashboard/management/__init__.py +0 -0
  196. django_cfg/dashboard/management/commands/__init__.py +0 -0
  197. django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
  198. django_cfg/dashboard/sections/__init__.py +1 -0
  199. django_cfg/dashboard/sections/base.py +128 -0
  200. django_cfg/dashboard/sections/commands.py +32 -0
  201. django_cfg/dashboard/sections/overview.py +394 -0
  202. django_cfg/dashboard/sections/stats.py +48 -0
  203. django_cfg/dashboard/sections/system.py +73 -0
  204. django_cfg/management/commands/check_settings.py +6 -2
  205. django_cfg/management/commands/clear_constance.py +6 -1
  206. django_cfg/management/commands/create_token.py +5 -4
  207. django_cfg/management/commands/generate.py +5 -0
  208. django_cfg/management/commands/list_urls.py +7 -2
  209. django_cfg/management/commands/migrate_all.py +6 -2
  210. django_cfg/management/commands/migrator.py +6 -1
  211. django_cfg/management/commands/rundramatiq.py +6 -1
  212. django_cfg/management/commands/rundramatiq_simulator.py +11 -4
  213. django_cfg/management/commands/runserver_ngrok.py +9 -7
  214. django_cfg/management/commands/script.py +25 -21
  215. django_cfg/management/commands/show_config.py +6 -1
  216. django_cfg/management/commands/show_urls.py +8 -3
  217. django_cfg/management/commands/superuser.py +5 -4
  218. django_cfg/management/commands/task_clear.py +8 -3
  219. django_cfg/management/commands/task_status.py +8 -3
  220. django_cfg/management/commands/test_email.py +6 -1
  221. django_cfg/management/commands/test_telegram.py +6 -1
  222. django_cfg/management/commands/test_twilio.py +6 -1
  223. django_cfg/management/commands/tree.py +7 -4
  224. django_cfg/models/__init__.py +88 -3
  225. django_cfg/models/api/__init__.py +27 -0
  226. django_cfg/models/{api.py → api/config.py} +1 -1
  227. django_cfg/models/api/drf/__init__.py +21 -0
  228. django_cfg/models/api/drf/config.py +101 -0
  229. django_cfg/models/api/drf/redoc.py +31 -0
  230. django_cfg/models/api/drf/spectacular.py +129 -0
  231. django_cfg/models/api/drf/swagger.py +59 -0
  232. django_cfg/models/{api_keys.py → api/keys.py} +16 -6
  233. django_cfg/models/{limits.py → api/limits.py} +0 -1
  234. django_cfg/models/base/__init__.py +14 -0
  235. django_cfg/models/django/__init__.py +16 -0
  236. django_cfg/models/{constance.py → django/constance.py} +1 -1
  237. django_cfg/models/{environment.py → django/environment.py} +1 -1
  238. django_cfg/models/infrastructure/__init__.py +17 -0
  239. django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
  240. django_cfg/models/infrastructure/database/__init__.py +22 -0
  241. django_cfg/models/infrastructure/database/config.py +265 -0
  242. django_cfg/models/infrastructure/database/converters.py +91 -0
  243. django_cfg/models/infrastructure/database/parsers.py +96 -0
  244. django_cfg/models/infrastructure/database/routing.py +85 -0
  245. django_cfg/models/infrastructure/database/validators.py +170 -0
  246. django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
  247. django_cfg/models/{security.py → infrastructure/security.py} +2 -2
  248. django_cfg/models/ngrok/__init__.py +11 -0
  249. django_cfg/models/ngrok/auth.py +37 -0
  250. django_cfg/models/ngrok/config.py +77 -0
  251. django_cfg/models/ngrok/tunnel.py +35 -0
  252. django_cfg/models/payments/__init__.py +20 -0
  253. django_cfg/models/payments/api_keys.py +57 -0
  254. django_cfg/models/{payments.py → payments/config.py} +56 -154
  255. django_cfg/models/payments/providers/__init__.py +15 -0
  256. django_cfg/models/payments/providers/base.py +25 -0
  257. django_cfg/models/payments/providers/nowpayments.py +48 -0
  258. django_cfg/models/services/__init__.py +18 -0
  259. django_cfg/models/services/base.py +65 -0
  260. django_cfg/models/{email.py → services/email.py} +1 -1
  261. django_cfg/models/services/telegram.py +172 -0
  262. django_cfg/models/tasks/__init__.py +51 -0
  263. django_cfg/models/tasks/backends.py +250 -0
  264. django_cfg/models/tasks/config.py +314 -0
  265. django_cfg/models/tasks/utils.py +174 -0
  266. django_cfg/modules/base.py +18 -3
  267. django_cfg/modules/django_admin/decorators/actions.py +1 -1
  268. django_cfg/modules/django_admin/decorators/display.py +1 -1
  269. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
  270. django_cfg/modules/django_cfg_rpc_client/README.md +346 -0
  271. django_cfg/modules/django_cfg_rpc_client/__init__.py +51 -0
  272. django_cfg/modules/django_cfg_rpc_client/client.py +540 -0
  273. django_cfg/modules/django_cfg_rpc_client/config.py +207 -0
  274. django_cfg/modules/django_cfg_rpc_client/dashboard/README.md +517 -0
  275. django_cfg/modules/django_cfg_rpc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
  276. django_cfg/modules/django_cfg_rpc_client/dashboard/__init__.py +11 -0
  277. django_cfg/modules/django_cfg_rpc_client/dashboard/apps.py +22 -0
  278. django_cfg/modules/django_cfg_rpc_client/dashboard/monitor.py +435 -0
  279. django_cfg/modules/django_cfg_rpc_client/dashboard/static/django_cfg_rpc_dashboard/js/dashboard.js +373 -0
  280. django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/base.html +76 -0
  281. django_cfg/modules/django_cfg_rpc_client/dashboard/templates/django_cfg_rpc_dashboard/dashboard.html +200 -0
  282. django_cfg/modules/django_cfg_rpc_client/dashboard/urls.py +22 -0
  283. django_cfg/modules/django_cfg_rpc_client/dashboard/urls_admin.py +9 -0
  284. django_cfg/modules/django_cfg_rpc_client/dashboard/views.py +251 -0
  285. django_cfg/modules/django_cfg_rpc_client/exceptions.py +201 -0
  286. django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
  287. django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
  288. django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
  289. django_cfg/modules/django_drf_theme/README.md +207 -0
  290. django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
  291. django_cfg/modules/django_drf_theme/__init__.py +23 -0
  292. django_cfg/modules/django_drf_theme/apps.py +15 -0
  293. django_cfg/modules/django_drf_theme/renderers.py +58 -0
  294. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
  295. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
  296. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
  297. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
  298. django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
  299. django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
  300. django_cfg/modules/django_email/__init__.py +14 -0
  301. django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
  302. django_cfg/modules/django_email/utils.py +40 -0
  303. django_cfg/modules/django_health/__init__.py +9 -0
  304. django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
  305. django_cfg/modules/django_llm/llm/client.py +155 -550
  306. django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
  307. django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
  308. django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
  309. django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
  310. django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
  311. django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
  312. django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
  313. django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
  314. django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
  315. django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
  316. django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
  317. django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
  318. django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
  319. django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
  320. django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
  321. django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
  322. django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
  323. django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
  324. django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
  325. django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
  326. django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
  327. django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
  328. django_cfg/modules/django_llm/translator/translator.py +150 -603
  329. django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
  330. django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
  331. django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
  332. django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
  333. django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
  334. django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
  335. django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
  336. django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
  337. django_cfg/modules/django_logging/__init__.py +14 -0
  338. django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
  339. django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
  340. django_cfg/modules/django_ngrok/__init__.py +39 -0
  341. django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
  342. django_cfg/modules/django_rpc_old/POETRY.md +344 -0
  343. django_cfg/modules/django_rpc_old/README.md +397 -0
  344. django_cfg/modules/django_rpc_old/TESTING.md +358 -0
  345. django_cfg/modules/django_rpc_old/__init__.py +39 -0
  346. django_cfg/modules/django_rpc_old/client.py +531 -0
  347. django_cfg/modules/django_rpc_old/config.py +279 -0
  348. django_cfg/modules/django_rpc_old/exceptions.py +172 -0
  349. django_cfg/modules/django_tailwind/README.md +478 -0
  350. django_cfg/modules/django_tailwind/__init__.py +7 -0
  351. django_cfg/modules/django_tailwind/apps.py +10 -0
  352. django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
  353. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
  354. django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
  355. django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
  356. django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
  357. django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
  358. django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
  359. django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
  360. django_cfg/modules/django_tasks/__init__.py +29 -0
  361. django_cfg/modules/django_tasks/factory.py +127 -0
  362. django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
  363. django_cfg/modules/django_tasks/settings.py +107 -0
  364. django_cfg/modules/django_telegram/__init__.py +29 -0
  365. django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
  366. django_cfg/modules/django_telegram/utils.py +62 -0
  367. django_cfg/modules/django_twilio/__init__.py +54 -107
  368. django_cfg/modules/django_twilio/_imports.py +30 -0
  369. django_cfg/modules/django_twilio/base.py +192 -0
  370. django_cfg/modules/django_twilio/email_otp.py +227 -0
  371. django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
  372. django_cfg/modules/django_twilio/simple_service.py +1 -2
  373. django_cfg/modules/django_twilio/sms.py +94 -0
  374. django_cfg/modules/django_twilio/twilio_service.py +2 -3
  375. django_cfg/modules/django_twilio/unified.py +310 -0
  376. django_cfg/modules/django_twilio/utils.py +190 -0
  377. django_cfg/modules/django_twilio/whatsapp.py +137 -0
  378. django_cfg/modules/django_unfold/callbacks/base.py +198 -7
  379. django_cfg/modules/django_unfold/callbacks/main.py +102 -10
  380. django_cfg/modules/django_unfold/dashboard.py +65 -43
  381. django_cfg/modules/django_unfold/models/config.py +13 -12
  382. django_cfg/modules/django_unfold/models/navigation.py +8 -3
  383. django_cfg/modules/django_unfold/models/tabs.py +2 -2
  384. django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
  385. django_cfg/registry/core.py +24 -26
  386. django_cfg/registry/modules.py +5 -2
  387. django_cfg/registry/services.py +20 -3
  388. django_cfg/registry/third_party.py +8 -8
  389. django_cfg/static/admin/css/dashboard.css +260 -0
  390. django_cfg/static/admin/js/commands.js +171 -0
  391. django_cfg/static/admin/js/dashboard.js +126 -0
  392. django_cfg/templates/admin/components/management_commands.js +375 -0
  393. django_cfg/templates/admin/components/progress_bar.html +18 -23
  394. django_cfg/templates/admin/index.html +48 -20
  395. django_cfg/templates/admin/index_new.html +106 -0
  396. django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
  397. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
  398. django_cfg/templates/admin/sections/commands_section.html +626 -0
  399. django_cfg/templates/admin/sections/overview_section.html +112 -0
  400. django_cfg/templates/admin/sections/stats_section.html +35 -0
  401. django_cfg/templates/admin/sections/system_section.html +99 -0
  402. django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
  403. django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
  404. django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
  405. django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
  406. django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
  407. django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
  408. django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
  409. django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
  410. django_cfg/templatetags/django_cfg.py +7 -1
  411. django_cfg/utils/smart_defaults.py +4 -4
  412. django_cfg-1.4.0.dist-info/METADATA +920 -0
  413. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/RECORD +424 -195
  414. django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
  415. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
  416. django_cfg/core/generation.py +0 -621
  417. django_cfg/management/commands/validate_config.py +0 -189
  418. django_cfg/models/database.py +0 -480
  419. django_cfg/models/drf.py +0 -272
  420. django_cfg/models/ngrok.py +0 -122
  421. django_cfg/models/services.py +0 -440
  422. django_cfg/models/tasks.py +0 -550
  423. django_cfg/modules/django_twilio/service.py +0 -942
  424. django_cfg/template_archive/django_sample.zip +0 -0
  425. django_cfg/templates/rest_framework/api.html +0 -12
  426. django_cfg/utils/toolkit.py +0 -703
  427. django_cfg-1.3.13.dist-info/METADATA +0 -1029
  428. /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
  429. /django_cfg/core/{environment.py → environment/detector.py} +0 -0
  430. /django_cfg/models/{cors.py → api/cors.py} +0 -0
  431. /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
  432. /django_cfg/models/{base.py → base/config.py} +0 -0
  433. /django_cfg/models/{cfg.py → base/module.py} +0 -0
  434. /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
  435. /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
  436. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/WHEEL +0 -0
  437. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/entry_points.txt +0 -0
  438. {django_cfg-1.3.13.dist-info → django_cfg-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,30 @@
1
+ """
2
+ Optional Twilio imports.
3
+
4
+ Makes twilio and sendgrid imports optional for testing and when not using Twilio functionality.
5
+ """
6
+
7
+ # Third-party imports (optional - only required when using Twilio functionality)
8
+ try:
9
+ from twilio.rest import Client
10
+ from twilio.base.exceptions import TwilioException
11
+ TWILIO_AVAILABLE = True
12
+ except ImportError:
13
+ Client = None # type: ignore
14
+ TwilioException = Exception # Fallback to base exception
15
+ TWILIO_AVAILABLE = False
16
+
17
+ try:
18
+ from sendgrid import SendGridAPIClient
19
+ SENDGRID_AVAILABLE = True
20
+ except ImportError:
21
+ SendGridAPIClient = None # type: ignore
22
+ SENDGRID_AVAILABLE = False
23
+
24
+ __all__ = [
25
+ 'Client',
26
+ 'TwilioException',
27
+ 'SendGridAPIClient',
28
+ 'TWILIO_AVAILABLE',
29
+ 'SENDGRID_AVAILABLE',
30
+ ]
@@ -0,0 +1,192 @@
1
+ """
2
+ Base service class for all Twilio operations.
3
+
4
+ Provides auto-configuration from DjangoConfig and common utilities
5
+ for all Twilio services including error handling and logging.
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ import random
11
+ import string
12
+ from typing import Optional, Dict, Any
13
+ from datetime import datetime, timedelta
14
+
15
+ # Third-party imports (optional)
16
+ from ._imports import Client, TwilioException, SendGridAPIClient, TWILIO_AVAILABLE, SENDGRID_AVAILABLE
17
+
18
+ # Django CFG imports
19
+ from django_cfg.modules.base import BaseCfgModule
20
+ from django_cfg.modules.django_twilio.models import TwilioConfig
21
+ from django_cfg.modules.django_twilio.exceptions import (
22
+ TwilioConfigurationError,
23
+ )
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ def is_async_context() -> bool:
29
+ """Detect if running in async context."""
30
+ try:
31
+ asyncio.get_running_loop()
32
+ return True
33
+ except RuntimeError:
34
+ return False
35
+
36
+
37
+ class BaseTwilioService(BaseCfgModule):
38
+ """
39
+ Base service class for all Twilio operations.
40
+
41
+ Provides auto-configuration from DjangoConfig and common utilities
42
+ for all Twilio services including error handling and logging.
43
+ """
44
+
45
+ def __init__(self):
46
+ """Initialize with auto-discovered configuration."""
47
+ super().__init__()
48
+ self._config: Optional[TwilioConfig] = None
49
+ self._twilio_client: Optional[Client] = None
50
+ self._sendgrid_client: Optional[SendGridAPIClient] = None
51
+ self._otp_storage: Dict[str, Dict[str, Any]] = {} # In-memory storage for development
52
+
53
+ def get_twilio_config(self) -> TwilioConfig:
54
+ """
55
+ Get Twilio configuration from DjangoConfig.
56
+
57
+ Returns:
58
+ TwilioConfig instance
59
+
60
+ Raises:
61
+ TwilioConfigurationError: If configuration is missing or invalid
62
+ """
63
+ if self._config is None:
64
+ django_config = self.get_config()
65
+ if not django_config:
66
+ raise TwilioConfigurationError(
67
+ "DjangoConfig instance not found",
68
+ suggestions=["Ensure DjangoConfig is properly initialized"]
69
+ )
70
+
71
+ twilio_config = getattr(django_config, 'twilio', None)
72
+ if not twilio_config:
73
+ raise TwilioConfigurationError(
74
+ "Twilio configuration not found in DjangoConfig",
75
+ missing_fields=["twilio"],
76
+ suggestions=["Add TwilioConfig to your DjangoConfig class"]
77
+ )
78
+
79
+ self._config = twilio_config
80
+
81
+ return self._config
82
+
83
+ def get_twilio_client(self) -> Client:
84
+ """
85
+ Get initialized Twilio client.
86
+
87
+ Returns:
88
+ Twilio Client instance
89
+
90
+ Raises:
91
+ TwilioConfigurationError: If client cannot be initialized
92
+ """
93
+ if self._twilio_client is None:
94
+ config = self.get_twilio_config()
95
+
96
+ try:
97
+ client_config = config.get_client_config()
98
+ self._twilio_client = Client(
99
+ client_config["username"],
100
+ client_config["password"],
101
+ region=client_config.get("region")
102
+ )
103
+
104
+ # Test connection with a simple API call
105
+ try:
106
+ self._twilio_client.api.v2010.accounts(config.account_sid).fetch()
107
+ except TwilioException as e:
108
+ raise TwilioConfigurationError(
109
+ f"Failed to authenticate with Twilio: {e}",
110
+ error_code=getattr(e, 'code', None),
111
+ suggestions=[
112
+ "Verify TWILIO_ACCOUNT_SID is correct",
113
+ "Verify TWILIO_AUTH_TOKEN is correct",
114
+ "Check Twilio account status"
115
+ ]
116
+ ) from e
117
+
118
+ except Exception as e:
119
+ raise TwilioConfigurationError(
120
+ f"Failed to initialize Twilio client: {e}",
121
+ suggestions=["Check Twilio configuration parameters"]
122
+ ) from e
123
+
124
+ return self._twilio_client
125
+
126
+ def get_sendgrid_client(self) -> Optional[SendGridAPIClient]:
127
+ """
128
+ Get initialized SendGrid client.
129
+
130
+ Returns:
131
+ SendGrid client instance or None if not configured
132
+
133
+ Raises:
134
+ TwilioConfigurationError: If client cannot be initialized
135
+ """
136
+ config = self.get_twilio_config()
137
+
138
+ if not config.sendgrid:
139
+ return None
140
+
141
+ if self._sendgrid_client is None:
142
+ try:
143
+ sendgrid_config = config.get_sendgrid_config()
144
+ if sendgrid_config:
145
+ self._sendgrid_client = SendGridAPIClient(
146
+ api_key=sendgrid_config["api_key"]
147
+ )
148
+
149
+ except Exception as e:
150
+ raise TwilioConfigurationError(
151
+ f"Failed to initialize SendGrid client: {e}",
152
+ suggestions=["Check SendGrid API key configuration"]
153
+ ) from e
154
+
155
+ return self._sendgrid_client
156
+
157
+ def _generate_otp(self, length: int = 6) -> str:
158
+ """Generate numeric OTP code."""
159
+ return ''.join(random.choices(string.digits, k=length))
160
+
161
+ def _store_otp(self, identifier: str, code: str, ttl_seconds: int = 600) -> None:
162
+ """Store OTP code with expiration (in-memory for development)."""
163
+ self._otp_storage[identifier] = {
164
+ 'code': code,
165
+ 'created_at': datetime.now(),
166
+ 'expires_at': datetime.now() + timedelta(seconds=ttl_seconds),
167
+ 'attempts': 0,
168
+ }
169
+
170
+ def _get_stored_otp(self, identifier: str) -> Optional[Dict[str, Any]]:
171
+ """Get stored OTP data."""
172
+ return self._otp_storage.get(identifier)
173
+
174
+ def _remove_otp(self, identifier: str) -> None:
175
+ """Remove OTP from storage."""
176
+ self._otp_storage.pop(identifier, None)
177
+
178
+ def _mask_identifier(self, identifier: str) -> str:
179
+ """Mask identifier for security in logs."""
180
+ if "@" in identifier: # Email
181
+ parts = identifier.split("@")
182
+ if len(parts) == 2:
183
+ return f"{parts[0][:2]}***@{parts[1]}"
184
+ else: # Phone number
185
+ return f"***{identifier[-4:]}" if len(identifier) > 4 else "***"
186
+ return "***"
187
+
188
+
189
+ __all__ = [
190
+ "is_async_context",
191
+ "BaseTwilioService",
192
+ ]
@@ -0,0 +1,227 @@
1
+ """
2
+ Email OTP service using SendGrid.
3
+
4
+ Provides OTP delivery via email with template support and
5
+ comprehensive deliverability optimization.
6
+ """
7
+
8
+ import logging
9
+ from typing import Optional, Tuple, Dict, Any
10
+ from django_cfg.modules.django_twilio._imports import SendGridAPIClient, SENDGRID_AVAILABLE
11
+
12
+ # Import Mail helper conditionally
13
+ try:
14
+ from sendgrid.helpers.mail import Mail
15
+ except ImportError:
16
+ Mail = None # type: ignore
17
+
18
+ from asgiref.sync import sync_to_async
19
+
20
+ from .base import BaseTwilioService
21
+ from .models import SendGridConfig
22
+ from .exceptions import (
23
+ TwilioConfigurationError,
24
+ TwilioSendError,
25
+ )
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class EmailOTPService(BaseTwilioService):
31
+ """
32
+ Email OTP service using SendGrid.
33
+
34
+ Provides OTP delivery via email with template support and
35
+ comprehensive deliverability optimization.
36
+ """
37
+
38
+ def send_otp(
39
+ self,
40
+ email: str,
41
+ subject: Optional[str] = None,
42
+ template_data: Optional[Dict[str, Any]] = None
43
+ ) -> Tuple[bool, str, str]:
44
+ """
45
+ Send OTP via email.
46
+
47
+ Args:
48
+ email: Recipient email address
49
+ subject: Custom email subject (uses default if not provided)
50
+ template_data: Additional data for email template
51
+
52
+ Returns:
53
+ Tuple[bool, str, str]: (success, message, otp_code)
54
+
55
+ Raises:
56
+ TwilioConfigurationError: If SendGrid is not configured
57
+ TwilioSendError: If email sending fails
58
+ """
59
+ config = self.get_twilio_config()
60
+
61
+ if not config.sendgrid:
62
+ raise TwilioConfigurationError(
63
+ "SendGrid configuration not found",
64
+ missing_fields=["sendgrid"],
65
+ suggestions=["Configure SendGridConfig in your Twilio settings"]
66
+ )
67
+
68
+ sendgrid_client = self.get_sendgrid_client()
69
+ if not sendgrid_client:
70
+ raise TwilioConfigurationError("SendGrid client not initialized")
71
+
72
+ try:
73
+ # Generate OTP code
74
+ otp_code = self._generate_otp(6)
75
+
76
+ # Store OTP for verification
77
+ self._store_otp(email, otp_code, config.verify.ttl_seconds if config.verify else 600)
78
+
79
+ # Prepare email content
80
+ if config.sendgrid.otp_template_id:
81
+ # Use dynamic template
82
+ success, message = self._send_template_email(
83
+ sendgrid_client, config.sendgrid, email, otp_code, template_data
84
+ )
85
+ else:
86
+ # Use simple HTML email
87
+ success, message = self._send_simple_email(
88
+ sendgrid_client, config.sendgrid, email, otp_code, subject
89
+ )
90
+
91
+ if success:
92
+ logger.info(f"Email OTP sent successfully to {self._mask_identifier(email)}")
93
+ return True, message, otp_code
94
+ else:
95
+ raise TwilioSendError(message, channel="email", recipient=email)
96
+
97
+ except Exception as e:
98
+ if isinstance(e, TwilioSendError):
99
+ raise
100
+ raise TwilioSendError(
101
+ f"Failed to send email OTP: {e}",
102
+ channel="email",
103
+ recipient=email
104
+ ) from e
105
+
106
+ async def asend_otp(
107
+ self,
108
+ email: str,
109
+ subject: Optional[str] = None,
110
+ template_data: Optional[Dict[str, Any]] = None
111
+ ) -> Tuple[bool, str, str]:
112
+ """Async version of send_otp."""
113
+ return await sync_to_async(self.send_otp)(email, subject, template_data)
114
+
115
+ def _send_template_email(
116
+ self,
117
+ client: SendGridAPIClient,
118
+ config: SendGridConfig,
119
+ email: str,
120
+ otp_code: str,
121
+ template_data: Optional[Dict[str, Any]] = None
122
+ ) -> Tuple[bool, str]:
123
+ """Send email using SendGrid dynamic template."""
124
+ try:
125
+ # Prepare template data
126
+ dynamic_data = {
127
+ 'verification_code': otp_code,
128
+ 'user_email': email,
129
+ 'expiry_minutes': 10,
130
+ 'company_name': config.from_name,
131
+ **config.custom_template_data,
132
+ **(template_data or {})
133
+ }
134
+
135
+ message = Mail(
136
+ from_email=(config.from_email, config.from_name),
137
+ to_emails=email
138
+ )
139
+
140
+ message.template_id = config.otp_template_id
141
+ message.dynamic_template_data = dynamic_data
142
+
143
+ if config.reply_to_email:
144
+ message.reply_to = config.reply_to_email
145
+
146
+ response = client.send(message)
147
+
148
+ if response.status_code in [200, 201, 202]:
149
+ return True, f"OTP sent via email template to {self._mask_identifier(email)}"
150
+ else:
151
+ return False, f"SendGrid API error: {response.status_code}"
152
+
153
+ except Exception as e:
154
+ return False, f"Template email error: {e}"
155
+
156
+ def _send_simple_email(
157
+ self,
158
+ client: SendGridAPIClient,
159
+ config: SendGridConfig,
160
+ email: str,
161
+ otp_code: str,
162
+ subject: Optional[str] = None
163
+ ) -> Tuple[bool, str]:
164
+ """Send simple HTML email without template."""
165
+ try:
166
+ html_content = self._generate_html_content(otp_code, config.from_name)
167
+ plain_content = self._generate_plain_content(otp_code)
168
+
169
+ message = Mail(
170
+ from_email=(config.from_email, config.from_name),
171
+ to_emails=email,
172
+ subject=subject or config.default_subject,
173
+ html_content=html_content,
174
+ plain_text_content=plain_content
175
+ )
176
+
177
+ if config.reply_to_email:
178
+ message.reply_to = config.reply_to_email
179
+
180
+ response = client.send(message)
181
+
182
+ if response.status_code in [200, 201, 202]:
183
+ return True, f"OTP sent via email to {self._mask_identifier(email)}"
184
+ else:
185
+ return False, f"SendGrid API error: {response.status_code}"
186
+
187
+ except Exception as e:
188
+ return False, f"Simple email error: {e}"
189
+
190
+ def _generate_html_content(self, otp_code: str, company_name: str) -> str:
191
+ """Generate HTML email content."""
192
+ return f"""
193
+ <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
194
+ <div style="background-color: #f8f9fa; padding: 30px; border-radius: 10px; text-align: center;">
195
+ <h1 style="color: #333; margin-bottom: 20px;">Verification Code</h1>
196
+ <p style="color: #666; font-size: 16px; margin-bottom: 30px;">
197
+ Your verification code is:
198
+ </p>
199
+ <div style="background-color: #007bff; color: white; font-size: 32px; font-weight: bold;
200
+ padding: 20px; border-radius: 8px; letter-spacing: 5px; margin: 30px 0;">
201
+ {otp_code}
202
+ </div>
203
+ <p style="color: #999; font-size: 14px;">
204
+ This code expires in 10 minutes<br>
205
+ If you didn't request this code, please ignore this email
206
+ </p>
207
+ <hr style="border: none; border-top: 1px solid #eee; margin: 30px 0;">
208
+ <p style="color: #999; font-size: 12px;">
209
+ Sent by {company_name}
210
+ </p>
211
+ </div>
212
+ </div>
213
+ """
214
+
215
+ def _generate_plain_content(self, otp_code: str) -> str:
216
+ """Generate plain text email content."""
217
+ return f"""
218
+ Your verification code: {otp_code}
219
+
220
+ This code expires in 10 minutes.
221
+ If you didn't request this code, please ignore this email.
222
+ """.strip()
223
+
224
+
225
+ __all__ = [
226
+ "EmailOTPService",
227
+ ]
@@ -359,7 +359,7 @@ class SendGridService(BaseCfgModule):
359
359
  """Send simple HTML email using Django templates."""
360
360
  try:
361
361
  # Get current config for template context
362
- from django_cfg.core.config import get_current_config
362
+ from django_cfg.core.state import get_current_config
363
363
  current_config = get_current_config()
364
364
 
365
365
  # Prepare context for unified template
@@ -7,8 +7,7 @@ without the complexity of the OTP system.
7
7
 
8
8
  import logging
9
9
  from typing import Optional, Dict, Any
10
- from twilio.rest import Client
11
- from twilio.base.exceptions import TwilioException
10
+ from ._imports import Client, TwilioException
12
11
 
13
12
  from django_cfg.modules.base import BaseCfgModule
14
13
  from django_cfg.modules.django_twilio.models import TwilioConfig
@@ -0,0 +1,94 @@
1
+ """
2
+ SMS OTP service using Twilio Verify API.
3
+
4
+ Provides reliable SMS OTP delivery with comprehensive
5
+ error handling and international support.
6
+ """
7
+
8
+ import logging
9
+ from typing import Tuple
10
+ from asgiref.sync import sync_to_async
11
+
12
+ from .base import BaseTwilioService
13
+ from .exceptions import (
14
+ TwilioConfigurationError,
15
+ TwilioSendError,
16
+ )
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class SMSOTPService(BaseTwilioService):
22
+ """
23
+ SMS OTP service using Twilio Verify API.
24
+
25
+ Provides reliable SMS OTP delivery with comprehensive
26
+ error handling and international support.
27
+ """
28
+
29
+ def send_otp(self, phone_number: str) -> Tuple[bool, str]:
30
+ """
31
+ Send OTP via SMS.
32
+
33
+ Args:
34
+ phone_number: Phone number in E.164 format
35
+
36
+ Returns:
37
+ Tuple[bool, str]: (success, message)
38
+
39
+ Raises:
40
+ TwilioConfigurationError: If Verify service not configured
41
+ TwilioSendError: If SMS sending fails
42
+ """
43
+ config = self.get_twilio_config()
44
+
45
+ if not config.verify:
46
+ raise TwilioConfigurationError(
47
+ "Twilio Verify service not configured",
48
+ missing_fields=["verify"],
49
+ suggestions=["Configure TwilioVerifyConfig in your Twilio settings"]
50
+ )
51
+
52
+ client = self.get_twilio_client()
53
+
54
+ try:
55
+ verification = client.verify.v2.services(
56
+ config.verify.service_sid
57
+ ).verifications.create(
58
+ to=phone_number,
59
+ channel='sms'
60
+ )
61
+
62
+ if verification.status == 'pending':
63
+ logger.info(f"SMS OTP sent successfully to {self._mask_identifier(phone_number)}")
64
+ return True, f"OTP sent via SMS to {self._mask_identifier(phone_number)}"
65
+ else:
66
+ raise TwilioSendError(
67
+ f"SMS OTP failed with status: {verification.status}",
68
+ channel="sms",
69
+ recipient=phone_number
70
+ )
71
+
72
+ except TwilioException as e:
73
+ raise TwilioSendError(
74
+ f"SMS OTP failed: {e}",
75
+ channel="sms",
76
+ recipient=phone_number,
77
+ twilio_error_code=getattr(e, 'code', None),
78
+ twilio_error_message=str(e)
79
+ ) from e
80
+ except Exception as e:
81
+ raise TwilioSendError(
82
+ f"Unexpected error sending SMS OTP: {e}",
83
+ channel="sms",
84
+ recipient=phone_number
85
+ ) from e
86
+
87
+ async def asend_otp(self, phone_number: str) -> Tuple[bool, str]:
88
+ """Async version of send_otp."""
89
+ return await sync_to_async(self.send_otp)(phone_number)
90
+
91
+
92
+ __all__ = [
93
+ "SMSOTPService",
94
+ ]
@@ -13,8 +13,7 @@ import string
13
13
  from typing import Optional, Dict, Any, Tuple
14
14
  from datetime import datetime, timedelta
15
15
 
16
- from twilio.rest import Client
17
- from twilio.base.exceptions import TwilioException
16
+ from ._imports import Client, TwilioException
18
17
  from asgiref.sync import sync_to_async
19
18
 
20
19
  from django_cfg.modules.base import BaseCfgModule
@@ -256,7 +255,7 @@ class TwilioService(BaseCfgModule):
256
255
 
257
256
  # STEP 1: Try Direct WhatsApp with custom OTP
258
257
  try:
259
- from django_cfg.core.config import get_current_config
258
+ from django_cfg.core.state import get_current_config
260
259
  django_config = get_current_config()
261
260
  site_name = django_config.project_name if django_config else "Django CFG"
262
261