django-cfg 1.1.52__tar.gz → 1.1.54__tar.gz

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 (271) hide show
  1. {django_cfg-1.1.52 → django_cfg-1.1.54}/PKG-INFO +6 -1
  2. {django_cfg-1.1.52 → django_cfg-1.1.54}/pyproject.toml +9 -2
  3. {django_cfg-1.1.52 → django_cfg-1.1.54}/requirements-dev.txt +5 -0
  4. {django_cfg-1.1.52 → django_cfg-1.1.54}/requirements-test.txt +5 -0
  5. {django_cfg-1.1.52 → django_cfg-1.1.54}/requirements.txt +5 -0
  6. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/__init__.py +3 -3
  7. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/__init__.py +0 -2
  8. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/filters.py +0 -54
  9. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/otp.py +1 -12
  10. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/managers/user_manager.py +0 -16
  11. django_cfg-1.1.54/src/django_cfg/apps/accounts/migrations/0004_delete_twilioresponse.py +16 -0
  12. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/models.py +0 -93
  13. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/serializers/otp.py +2 -2
  14. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/services/otp_service.py +25 -121
  15. django_cfg-1.1.54/src/django_cfg/apps/accounts/templates/emails/otp_email.html +94 -0
  16. django_cfg-1.1.54/src/django_cfg/apps/accounts/templates/emails/otp_email.txt +16 -0
  17. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/urls.py +1 -2
  18. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/utils/notifications.py +32 -184
  19. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/views/__init__.py +0 -3
  20. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/views/otp.py +0 -8
  21. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/commands/urls.py +0 -2
  22. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/health/urls.py +0 -2
  23. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/tasks/admin.py +5 -6
  24. django_cfg-1.1.54/src/django_cfg/apps/tasks/serializers.py +82 -0
  25. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/css/dashboard.css +269 -0
  26. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/js/api.js +144 -0
  27. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/js/dashboard.js +614 -0
  28. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/js/modals.js +452 -0
  29. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/js/notifications.js +144 -0
  30. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/js/task-monitor.js +454 -0
  31. django_cfg-1.1.54/src/django_cfg/apps/tasks/static/tasks/js/theme.js +77 -0
  32. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/base.html +96 -0
  33. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/info_cards.html +85 -0
  34. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/management_actions.html +53 -0
  35. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +22 -0
  36. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +19 -0
  37. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/status_cards.html +50 -0
  38. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +27 -0
  39. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +103 -0
  40. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +32 -0
  41. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +29 -0
  42. django_cfg-1.1.54/src/django_cfg/apps/tasks/templates/tasks/dashboard.html +29 -0
  43. django_cfg-1.1.54/src/django_cfg/apps/tasks/urls.py +23 -0
  44. django_cfg-1.1.54/src/django_cfg/apps/tasks/views.py +448 -0
  45. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/archive/django_sample.zip +0 -0
  46. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/README.md +1 -1
  47. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/commands/create_project.py +2 -2
  48. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/commands/info.py +1 -1
  49. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/core/config.py +0 -6
  50. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/core/generation.py +23 -1
  51. django_cfg-1.1.54/src/django_cfg/management/commands/clear_constance.py +200 -0
  52. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/rundramatiq.py +7 -5
  53. django_cfg-1.1.54/src/django_cfg/management/commands/show_urls.py +341 -0
  54. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/test_email.py +1 -1
  55. django_cfg-1.1.54/src/django_cfg/management/commands/test_twilio.py +101 -0
  56. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/constance.py +29 -23
  57. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/base.py +19 -1
  58. django_cfg-1.1.54/src/django_cfg/modules/django_llm/README.md +388 -0
  59. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/__init__.py +5 -9
  60. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/llm/client.py +197 -178
  61. django_cfg-1.1.54/src/django_cfg/modules/django_llm/llm/costs.py +188 -0
  62. django_cfg-1.1.54/src/django_cfg/modules/django_llm/llm/extractor.py +85 -0
  63. django_cfg-1.1.54/src/django_cfg/modules/django_llm/llm/tokenizer.py +83 -0
  64. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_tasks.py +282 -53
  65. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/README.md +1 -1
  66. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/__init__.py +37 -50
  67. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/models.py +16 -34
  68. django_cfg-1.1.54/src/django_cfg/modules/django_twilio/service.py +942 -0
  69. django_cfg-1.1.54/src/django_cfg/modules/django_twilio/simple_service.py +290 -0
  70. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/unfold/dashboard.py +1 -45
  71. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/utils/smart_defaults.py +17 -1
  72. django_cfg-1.1.52/src/django_cfg/apps/accounts/templates/emails/otp_email.html +0 -213
  73. django_cfg-1.1.52/src/django_cfg/apps/accounts/templates/emails/otp_email.txt +0 -29
  74. django_cfg-1.1.52/src/django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -449
  75. django_cfg-1.1.52/src/django_cfg/apps/tasks/urls.py +0 -21
  76. django_cfg-1.1.52/src/django_cfg/apps/tasks/views.py +0 -210
  77. django_cfg-1.1.52/src/django_cfg/management/commands/show_urls.py +0 -302
  78. django_cfg-1.1.52/src/django_cfg/management/commands/test_twilio.py +0 -614
  79. django_cfg-1.1.52/src/django_cfg/modules/django_llm/README.md +0 -524
  80. django_cfg-1.1.52/src/django_cfg/modules/django_llm/service.py +0 -423
  81. {django_cfg-1.1.52 → django_cfg-1.1.54}/.gitignore +0 -0
  82. {django_cfg-1.1.52 → django_cfg-1.1.54}/LICENSE +0 -0
  83. {django_cfg-1.1.52 → django_cfg-1.1.54}/MANIFEST.in +0 -0
  84. {django_cfg-1.1.52 → django_cfg-1.1.54}/README.md +0 -0
  85. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/__init__.py +0 -0
  86. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/README.md +0 -0
  87. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/__init__.py +0 -0
  88. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/activity.py +0 -0
  89. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/group.py +0 -0
  90. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/inlines.py +0 -0
  91. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/registration_source.py +0 -0
  92. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/twilio_response.py +0 -0
  93. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/admin/user.py +0 -0
  94. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/apps.py +0 -0
  95. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/management/commands/test_otp.py +0 -0
  96. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/managers/__init__.py +0 -0
  97. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/migrations/0001_initial.py +0 -0
  98. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/migrations/0002_add_phone_otp_clean.py +0 -0
  99. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/migrations/0003_twilioresponse.py +0 -0
  100. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/migrations/__init__.py +0 -0
  101. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/serializers/__init__.py +0 -0
  102. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/serializers/profile.py +0 -0
  103. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/serializers/webhook.py +0 -0
  104. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/services/__init__.py +0 -0
  105. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/services/activity_service.py +0 -0
  106. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/signals.py +0 -0
  107. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/templates/emails/base_email.html +0 -0
  108. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/templates/emails/base_email.txt +0 -0
  109. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/templates/emails/welcome_email.html +0 -0
  110. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/templates/emails/welcome_email.txt +0 -0
  111. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/views/profile.py +0 -0
  112. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/accounts/views/webhook.py +0 -0
  113. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/__init__.py +0 -0
  114. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/commands/__init__.py +0 -0
  115. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/commands/views.py +0 -0
  116. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/health/__init__.py +0 -0
  117. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/api/health/views.py +0 -0
  118. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/README.md +0 -0
  119. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/__init__.py +0 -0
  120. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/admin.py +0 -0
  121. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/apps.py +0 -0
  122. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/migrations/0001_initial.py +0 -0
  123. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/migrations/__init__.py +0 -0
  124. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/models.py +0 -0
  125. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/serializers.py +0 -0
  126. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/signals.py +0 -0
  127. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/tests.py +0 -0
  128. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/urls.py +0 -0
  129. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/leads/views.py +0 -0
  130. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/README.md +0 -0
  131. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/__init__.py +0 -0
  132. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/admin.py +0 -0
  133. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/admin_filters.py +0 -0
  134. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/apps.py +0 -0
  135. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/management/__init__.py +0 -0
  136. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/management/commands/__init__.py +0 -0
  137. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/management/commands/test_newsletter.py +0 -0
  138. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/managers/README.md +0 -0
  139. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/managers/__init__.py +0 -0
  140. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/migrations/0001_initial.py +0 -0
  141. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/migrations/__init__.py +0 -0
  142. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/models.py +0 -0
  143. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/serializers.py +0 -0
  144. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/services/email_service.py +0 -0
  145. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/signals.py +0 -0
  146. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/urls.py +0 -0
  147. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/utils/__init__.py +0 -0
  148. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/views/__init__.py +0 -0
  149. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/views/campaigns.py +0 -0
  150. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/views/emails.py +0 -0
  151. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/views/newsletters.py +0 -0
  152. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/views/subscriptions.py +0 -0
  153. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/newsletter/views/tracking.py +0 -0
  154. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/__init__.py +0 -0
  155. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/admin.py +0 -0
  156. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/admin_filters.py +0 -0
  157. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/apps.py +0 -0
  158. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/managers/message_manager.py +0 -0
  159. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/managers/ticket_manager.py +0 -0
  160. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/migrations/0001_initial.py +0 -0
  161. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/migrations/0002_alter_message_ticket.py +0 -0
  162. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/migrations/__init__.py +0 -0
  163. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/models.py +0 -0
  164. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/serializers.py +0 -0
  165. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/signals.py +0 -0
  166. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/templates/support/chat/access_denied.html +0 -0
  167. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/templates/support/chat/ticket_chat.html +0 -0
  168. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/urls.py +0 -0
  169. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/utils/__init__.py +0 -0
  170. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/utils/support_email_service.py +0 -0
  171. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/views/__init__.py +0 -0
  172. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/views/admin.py +0 -0
  173. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/views/api.py +0 -0
  174. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/support/views/chat.py +0 -0
  175. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/tasks/__init__.py +0 -0
  176. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/tasks/apps.py +0 -0
  177. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps/urls.py +0 -0
  178. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/apps.py +0 -0
  179. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/__init__.py +0 -0
  180. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/commands/__init__.py +0 -0
  181. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/main.py +0 -0
  182. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/cli/utils.py +0 -0
  183. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/core/__init__.py +0 -0
  184. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/core/environment.py +0 -0
  185. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/core/validation.py +0 -0
  186. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/exceptions.py +0 -0
  187. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/integration.py +0 -0
  188. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/__init__.py +0 -0
  189. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/__init__.py +0 -0
  190. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/check_settings.py +0 -0
  191. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/create_token.py +0 -0
  192. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/generate.py +0 -0
  193. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/list_urls.py +0 -0
  194. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/migrator.py +0 -0
  195. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/runserver_ngrok.py +0 -0
  196. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/script.py +0 -0
  197. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/show_config.py +0 -0
  198. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/superuser.py +0 -0
  199. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/task_clear.py +0 -0
  200. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/task_status.py +0 -0
  201. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/test_telegram.py +0 -0
  202. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/tree.py +0 -0
  203. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/management/commands/validate_config.py +0 -0
  204. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/middleware/README.md +0 -0
  205. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/middleware/__init__.py +0 -0
  206. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/middleware/user_activity.py +0 -0
  207. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/__init__.py +0 -0
  208. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/cache.py +0 -0
  209. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/database.py +0 -0
  210. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/drf.py +0 -0
  211. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/jwt.py +0 -0
  212. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/limits.py +0 -0
  213. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/ngrok.py +0 -0
  214. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/revolution.py +0 -0
  215. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/services.py +0 -0
  216. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/tasks.py +0 -0
  217. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/models/unfold.py +0 -0
  218. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/__init__.py +0 -0
  219. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_currency/README.md +0 -0
  220. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_currency/__init__.py +0 -0
  221. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_currency/cache.py +0 -0
  222. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_currency/converter.py +0 -0
  223. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_currency/service.py +0 -0
  224. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_email.py +0 -0
  225. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/example.py +0 -0
  226. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/llm/__init__.py +0 -0
  227. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/llm/cache.py +0 -0
  228. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/llm/models_cache.py +0 -0
  229. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/translator/__init__.py +0 -0
  230. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/translator/cache.py +0 -0
  231. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_llm/translator/translator.py +0 -0
  232. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_logger.py +0 -0
  233. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_ngrok.py +0 -0
  234. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_telegram.py +0 -0
  235. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/exceptions.py +0 -0
  236. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/sendgrid_service.py +0 -0
  237. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/templates/guide.md +0 -0
  238. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/templates/sendgrid_otp_email.html +0 -0
  239. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/templates/sendgrid_test_data.json +0 -0
  240. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/django_twilio/twilio_service.py +0 -0
  241. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/logger.py +0 -0
  242. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/unfold/__init__.py +0 -0
  243. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/unfold/callbacks.py +0 -0
  244. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/unfold/models.py +0 -0
  245. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/unfold/system_monitor.py +0 -0
  246. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/modules/unfold/tailwind.py +0 -0
  247. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/routers.py +0 -0
  248. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/__init__.py +0 -0
  249. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/index.html +0 -0
  250. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/layouts/dashboard_with_tabs.html +0 -0
  251. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/activity_tracker.html +0 -0
  252. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/charts_section.html +0 -0
  253. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/django_commands.html +0 -0
  254. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/quick_actions.html +0 -0
  255. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/recent_activity.html +0 -0
  256. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/recent_users_table.html +0 -0
  257. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/stats_cards.html +0 -0
  258. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/stats_tiles.html +0 -0
  259. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/system_health.html +0 -0
  260. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/system_metrics.html +0 -0
  261. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/components/user_permissions.html +0 -0
  262. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/tabs/app_stats_tab.html +0 -0
  263. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/tabs/commands_tab.html +0 -0
  264. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/tabs/overview_tab.html +0 -0
  265. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/tabs/stats_tab.html +0 -0
  266. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/tabs/users_tab.html +0 -0
  267. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/admin/snippets/zones/zones_table.html +0 -0
  268. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/templates/emails/base_email.html +0 -0
  269. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/utils/__init__.py +0 -0
  270. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/utils/path_resolution.py +0 -0
  271. {django_cfg-1.1.52 → django_cfg-1.1.54}/src/django_cfg/version_check.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.1.52
3
+ Version: 1.1.54
4
4
  Summary: 🚀 Production-ready Django configuration framework with type-safe settings, smart automation, and modern developer experience
5
5
  Project-URL: Homepage, https://github.com/markolofsen/django-cfg
6
6
  Project-URL: Documentation, https://django-cfg.readthedocs.io
@@ -30,6 +30,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
30
30
  Classifier: Topic :: System :: Systems Administration
31
31
  Classifier: Typing :: Typed
32
32
  Requires-Python: <4.0,>=3.12
33
+ Requires-Dist: beautifulsoup4<5.0.0,>=4.13.5
33
34
  Requires-Dist: cachetools>=6.1.0
34
35
  Requires-Dist: click>=8.2.0
35
36
  Requires-Dist: colorlog>=6.9.0
@@ -42,6 +43,7 @@ Requires-Dist: django-cors-headers>=4.7.0
42
43
  Requires-Dist: django-extensions>=4.1
43
44
  Requires-Dist: django-filter>=25.0
44
45
  Requires-Dist: django-json-widget>=2.0.3
46
+ Requires-Dist: django-ratelimit<5.0.0,>=4.1.0
45
47
  Requires-Dist: django-redis>=6.0.0
46
48
  Requires-Dist: django-revolution>=1.0.34
47
49
  Requires-Dist: django-unfold>=0.64.0
@@ -53,8 +55,10 @@ Requires-Dist: drf-spectacular-sidecar>=2025.8.1
53
55
  Requires-Dist: drf-spectacular>=0.28.0
54
56
  Requires-Dist: hiredis>=2.0.0
55
57
  Requires-Dist: loguru>=0.7.0
58
+ Requires-Dist: lxml<7.0.0,>=6.0.1
56
59
  Requires-Dist: ngrok>=1.5.1; python_version >= '3.12'
57
60
  Requires-Dist: openai<2.0.0,>=1.107.1
61
+ Requires-Dist: pgvector<0.5.0,>=0.4.1
58
62
  Requires-Dist: psycopg[binary,pool]>=3.2.0
59
63
  Requires-Dist: pydantic-yaml>=1.6.0
60
64
  Requires-Dist: pydantic<3.0,>=2.11
@@ -68,6 +72,7 @@ Requires-Dist: requests<3.0.0,>=2.32.5
68
72
  Requires-Dist: rich>=14.1.0
69
73
  Requires-Dist: sendgrid<7.0.0,>=6.12.4
70
74
  Requires-Dist: tiktoken<0.12.0,>=0.11.0
75
+ Requires-Dist: toml<0.11.0,>=0.10.2
71
76
  Requires-Dist: twilio<10.0.0,>=9.8.0
72
77
  Requires-Dist: whitenoise>=6.8.0
73
78
  Provides-Extra: dev
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "django-cfg"
7
- version = "1.1.52"
7
+ version = "1.1.54"
8
8
  description = "🚀 Production-ready Django configuration framework with type-safe settings, smart automation, and modern developer experience"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -75,12 +75,13 @@ dependencies = [
75
75
  "djangorestframework-simplejwt[token-blacklist]>=5.5.0",
76
76
  "drf-nested-routers>=0.94.2",
77
77
  "django-filter>=25.0",
78
+ "django-ratelimit (>=4.1.0,<5.0.0)",
78
79
  "drf-spectacular>=0.28.0",
79
80
  "drf-spectacular-sidecar>=2025.8.1",
80
81
  "django-json-widget>=2.0.3",
81
82
  "django-extensions>=4.1",
82
83
  "django-constance>=4.3.2",
83
- "django-revolution>=1.0.34", # Temporarily commented for local dev
84
+ "django-revolution>=1.0.34",
84
85
  "django-unfold>=0.64.0",
85
86
  "django-redis>=6.0.0",
86
87
  "redis>=6.4.0",
@@ -97,6 +98,12 @@ dependencies = [
97
98
  "openai (>=1.107.1,<2.0.0)",
98
99
  "twilio (>=9.8.0,<10.0.0)",
99
100
  "sendgrid (>=6.12.4,<7.0.0)",
101
+
102
+ # Knowbase
103
+ "beautifulsoup4 (>=4.13.5,<5.0.0)",
104
+ "lxml (>=6.0.1,<7.0.0)",
105
+ "pgvector (>=0.4.1,<0.5.0)",
106
+ "toml (>=0.10.2,<0.11.0)",
100
107
  ]
101
108
 
102
109
  [project.optional-dependencies]
@@ -3,6 +3,7 @@
3
3
  # Do not edit manually!
4
4
 
5
5
  PyYAML>=6.0
6
+ beautifulsoup4 (>=4.13.5,<5.0.0)
6
7
  black>=23.0.0
7
8
  build>=1.0.0
8
9
  cachetools>=6.1.0
@@ -18,6 +19,7 @@ django-dramatiq>=0.14.0,<1.0
18
19
  django-extensions>=4.1
19
20
  django-filter>=25.0
20
21
  django-json-widget>=2.0.3
22
+ django-ratelimit (>=4.1.0,<5.0.0)
21
23
  django-redis>=6.0.0
22
24
  django-revolution>=1.0.34
23
25
  django-unfold>=0.64.0
@@ -34,12 +36,14 @@ flake8>=6.0.0
34
36
  hiredis>=2.0.0
35
37
  isort>=5.12.0
36
38
  loguru>=0.7.0
39
+ lxml (>=6.0.1,<7.0.0)
37
40
  mkdocs-material>=9.0.0
38
41
  mkdocs>=1.5.0
39
42
  mkdocstrings[python]>=0.22.0
40
43
  mypy>=1.5.0
41
44
  ngrok>=1.5.1; python_version>='3.12'
42
45
  openai (>=1.107.1,<2.0.0)
46
+ pgvector (>=0.4.1,<0.5.0)
43
47
  pre-commit>=3.0.0
44
48
  psycopg[binary,pool]>=3.2.0
45
49
  pyTelegramBotAPI>=4.28.0
@@ -60,6 +64,7 @@ rich>=13.0.0
60
64
  rich>=14.1.0
61
65
  sendgrid (>=6.12.4,<7.0.0)
62
66
  tiktoken (>=0.11.0,<0.12.0)
67
+ toml (>=0.10.2,<0.11.0)
63
68
  tomlkit>=0.13.3
64
69
  twilio (>=9.8.0,<10.0.0)
65
70
  twine>=4.0.0
@@ -3,6 +3,7 @@
3
3
  # Do not edit manually!
4
4
 
5
5
  PyYAML>=6.0
6
+ beautifulsoup4 (>=4.13.5,<5.0.0)
6
7
  cachetools>=6.1.0
7
8
  click>=8.2.0
8
9
  colorlog>=6.9.0
@@ -15,6 +16,7 @@ django-cors-headers>=4.7.0
15
16
  django-extensions>=4.1
16
17
  django-filter>=25.0
17
18
  django-json-widget>=2.0.3
19
+ django-ratelimit (>=4.1.0,<5.0.0)
18
20
  django-redis>=6.0.0
19
21
  django-revolution>=1.0.34
20
22
  django-unfold>=0.64.0
@@ -28,8 +30,10 @@ drf-spectacular>=0.28.0
28
30
  factory-boy>=3.2.0
29
31
  hiredis>=2.0.0
30
32
  loguru>=0.7.0
33
+ lxml (>=6.0.1,<7.0.0)
31
34
  ngrok>=1.5.1; python_version>='3.12'
32
35
  openai (>=1.107.1,<2.0.0)
36
+ pgvector (>=0.4.1,<0.5.0)
33
37
  psycopg[binary,pool]>=3.2.0
34
38
  pyTelegramBotAPI>=4.28.0
35
39
  pydantic-yaml>=1.6.0
@@ -47,5 +51,6 @@ requests (>=2.32.5,<3.0.0)
47
51
  rich>=14.1.0
48
52
  sendgrid (>=6.12.4,<7.0.0)
49
53
  tiktoken (>=0.11.0,<0.12.0)
54
+ toml (>=0.10.2,<0.11.0)
50
55
  twilio (>=9.8.0,<10.0.0)
51
56
  whitenoise>=6.8.0
@@ -3,6 +3,7 @@
3
3
  # Do not edit manually!
4
4
 
5
5
  PyYAML>=6.0
6
+ beautifulsoup4 (>=4.13.5,<5.0.0)
6
7
  cachetools>=6.1.0
7
8
  click>=8.2.0
8
9
  colorlog>=6.9.0
@@ -15,6 +16,7 @@ django-cors-headers>=4.7.0
15
16
  django-extensions>=4.1
16
17
  django-filter>=25.0
17
18
  django-json-widget>=2.0.3
19
+ django-ratelimit (>=4.1.0,<5.0.0)
18
20
  django-redis>=6.0.0
19
21
  django-revolution>=1.0.34
20
22
  django-unfold>=0.64.0
@@ -26,8 +28,10 @@ drf-spectacular-sidecar>=2025.8.1
26
28
  drf-spectacular>=0.28.0
27
29
  hiredis>=2.0.0
28
30
  loguru>=0.7.0
31
+ lxml (>=6.0.1,<7.0.0)
29
32
  ngrok>=1.5.1; python_version>='3.12'
30
33
  openai (>=1.107.1,<2.0.0)
34
+ pgvector (>=0.4.1,<0.5.0)
31
35
  psycopg[binary,pool]>=3.2.0
32
36
  pyTelegramBotAPI>=4.28.0
33
37
  pydantic-yaml>=1.6.0
@@ -40,5 +44,6 @@ requests (>=2.32.5,<3.0.0)
40
44
  rich>=14.1.0
41
45
  sendgrid (>=6.12.4,<7.0.0)
42
46
  tiktoken (>=0.11.0,<0.12.0)
47
+ toml (>=0.10.2,<0.11.0)
43
48
  twilio (>=9.8.0,<10.0.0)
44
49
  whitenoise>=6.8.0
@@ -38,9 +38,9 @@ default_app_config = "django_cfg.apps.DjangoCfgConfig"
38
38
  from typing import TYPE_CHECKING
39
39
 
40
40
  # Version information
41
- __version__ = "1.1.52"
42
- __author__ = "ReformsAI Team"
43
- __email__ = "info@reforms.ai"
41
+ __version__ = "1.1.54"
42
+ __author__ = "Unrealos Team"
43
+ __email__ = "info@unrealos.com"
44
44
  __license__ = "MIT"
45
45
 
46
46
  # Core exports - only import when needed to avoid circular imports
@@ -7,7 +7,6 @@ from .otp import OTPSecretAdmin
7
7
  from .registration_source import RegistrationSourceAdmin, UserRegistrationSourceAdmin
8
8
  from .activity import UserActivityAdmin
9
9
  from .group import GroupAdmin
10
- from .twilio_response import TwilioResponseAdmin
11
10
 
12
11
  __all__ = [
13
12
  'CustomUserAdmin',
@@ -16,5 +15,4 @@ __all__ = [
16
15
  'UserRegistrationSourceAdmin',
17
16
  'UserActivityAdmin',
18
17
  'GroupAdmin',
19
- 'TwilioResponseAdmin',
20
18
  ]
@@ -96,57 +96,3 @@ class ActivityTypeFilter(admin.SimpleListFilter):
96
96
  elif self.value():
97
97
  return queryset.filter(activity_type=self.value())
98
98
  return queryset
99
-
100
-
101
- class TwilioResponseStatusFilter(admin.SimpleListFilter):
102
- title = "Response Status"
103
- parameter_name = "twilio_status"
104
-
105
- def lookups(self, request, model_admin):
106
- return (
107
- ("successful", "Successful"),
108
- ("failed", "Failed"),
109
- ("pending", "Pending"),
110
- ("with_errors", "With Errors"),
111
- ("recent", "Recent (24h)"),
112
- )
113
-
114
- def queryset(self, request, queryset):
115
- now = timezone.now()
116
- if self.value() == "successful":
117
- return queryset.filter(
118
- status__in=['sent', 'delivered', 'approved'],
119
- error_code__isnull=True
120
- )
121
- elif self.value() == "failed":
122
- return queryset.filter(
123
- status__in=['failed', 'undelivered', 'rejected']
124
- )
125
- elif self.value() == "pending":
126
- return queryset.filter(status='pending')
127
- elif self.value() == "with_errors":
128
- return queryset.exclude(error_code__isnull=True)
129
- elif self.value() == "recent":
130
- return queryset.filter(created_at__gte=now - timedelta(hours=24))
131
- return queryset
132
-
133
-
134
- class TwilioResponseTypeFilter(admin.SimpleListFilter):
135
- title = "Response Type"
136
- parameter_name = "twilio_response_type"
137
-
138
- def lookups(self, request, model_admin):
139
- return (
140
- ("api_send", "API Send"),
141
- ("api_verify", "API Verify"),
142
- ("webhook_status", "Webhook Status"),
143
- ("webhook_delivery", "Webhook Delivery"),
144
- ("otp_related", "OTP Related"),
145
- )
146
-
147
- def queryset(self, request, queryset):
148
- if self.value() == "otp_related":
149
- return queryset.filter(otp_secret__isnull=False)
150
- elif self.value():
151
- return queryset.filter(response_type=self.value())
152
- return queryset
@@ -8,18 +8,16 @@ from unfold.admin import ModelAdmin
8
8
 
9
9
  from ..models import OTPSecret
10
10
  from .filters import OTPStatusFilter
11
- from .twilio_response import TwilioResponseInline
12
11
 
13
12
 
14
13
  @admin.register(OTPSecret)
15
14
  class OTPSecretAdmin(ModelAdmin):
16
- list_display = ["recipient", "channel_type", "secret", "status", "twilio_responses_count", "created", "expires"]
15
+ list_display = ["recipient", "channel_type", "secret", "status", "created", "expires"]
17
16
  list_display_links = ["recipient", "secret"]
18
17
  list_filter = [OTPStatusFilter, "channel_type", "is_used", "created_at"]
19
18
  search_fields = ["recipient", "secret"]
20
19
  readonly_fields = ["created_at", "expires_at"]
21
20
  ordering = ["-created_at"]
22
- inlines = [TwilioResponseInline]
23
21
 
24
22
  fieldsets = (
25
23
  (
@@ -59,12 +57,3 @@ class OTPSecretAdmin(ModelAdmin):
59
57
  return naturaltime(obj.expires_at)
60
58
 
61
59
  expires.short_description = "Expires"
62
-
63
- def twilio_responses_count(self, obj):
64
- """Count of related Twilio responses."""
65
- count = obj.twilio_responses.count()
66
- if count == 0:
67
- return "—"
68
- return f"{count} response{'s' if count != 1 else ''}"
69
-
70
- twilio_responses_count.short_description = "Twilio"
@@ -246,11 +246,6 @@ class UserManager(UserManager):
246
246
  return user.first_name
247
247
  elif user.last_name:
248
248
  return user.last_name
249
-
250
- # For phone users with temp email, use display_username instead
251
- if user.email and user.email.startswith('phone_') and '@temp.' in user.email:
252
- return self.get_display_username(user)
253
-
254
249
  return user.email
255
250
 
256
251
  def get_initials(self, user) -> str:
@@ -267,17 +262,6 @@ class UserManager(UserManager):
267
262
  return user.first_name[0].upper()
268
263
  elif user.last_name:
269
264
  return user.last_name[0].upper()
270
-
271
- # For phone users with temp email, use username initials instead
272
- if user.email and user.email.startswith('phone_') and '@temp.' in user.email:
273
- if user.username:
274
- # Take first two characters of username
275
- clean_username = user.username.replace("_", "").replace("-", "").replace(".", "")
276
- if len(clean_username) >= 2:
277
- return f"{clean_username[0]}{clean_username[1]}".upper()
278
- elif len(clean_username) == 1:
279
- return clean_username[0].upper()
280
-
281
265
  return user.email[0].upper()
282
266
 
283
267
  def get_display_username(self, user) -> str:
@@ -0,0 +1,16 @@
1
+ # Generated by Django 5.2.6 on 2025-09-16 18:57
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('django_cfg_accounts', '0003_twilioresponse'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.DeleteModel(
14
+ name='TwilioResponse',
15
+ ),
16
+ ]
@@ -203,99 +203,6 @@ class OTPSecret(models.Model):
203
203
  ]
204
204
 
205
205
 
206
- class TwilioResponse(models.Model):
207
- """
208
- Store Twilio API responses and webhook events.
209
-
210
- This model tracks all interactions with Twilio including:
211
- - API responses from sending messages/OTP
212
- - Webhook events for delivery status updates
213
- - Error tracking and debugging information
214
- """
215
-
216
- RESPONSE_TYPES = [
217
- ('api_send', 'API Send Request'),
218
- ('api_verify', 'API Verify Request'),
219
- ('webhook_status', 'Webhook Status Update'),
220
- ('webhook_delivery', 'Webhook Delivery Report'),
221
- ]
222
-
223
- SERVICE_TYPES = [
224
- ('whatsapp', 'WhatsApp'),
225
- ('sms', 'SMS'),
226
- ('voice', 'Voice'),
227
- ('email', 'Email'),
228
- ('verify', 'Verify API'),
229
- ]
230
-
231
- # Basic info
232
- response_type = models.CharField(max_length=20, choices=RESPONSE_TYPES)
233
- service_type = models.CharField(max_length=10, choices=SERVICE_TYPES)
234
-
235
- # Twilio identifiers
236
- message_sid = models.CharField(max_length=34, blank=True, help_text="Twilio Message SID")
237
- verification_sid = models.CharField(max_length=34, blank=True, help_text="Twilio Verification SID")
238
-
239
- # Request/Response data
240
- request_data = models.JSONField(default=dict, help_text="Original request parameters")
241
- response_data = models.JSONField(default=dict, help_text="Twilio API response")
242
-
243
- # Status tracking
244
- status = models.CharField(max_length=20, blank=True, help_text="Message/Verification status")
245
- error_code = models.CharField(max_length=10, blank=True, help_text="Twilio error code")
246
- error_message = models.TextField(blank=True, help_text="Error description")
247
-
248
- # Recipient info
249
- to_number = models.CharField(max_length=20, blank=True, help_text="Recipient phone/email")
250
- from_number = models.CharField(max_length=20, blank=True, help_text="Sender phone/email")
251
-
252
- # Pricing
253
- price = models.DecimalField(max_digits=10, decimal_places=6, null=True, blank=True)
254
- price_unit = models.CharField(max_length=3, blank=True, help_text="Currency code")
255
-
256
- # Timestamps
257
- created_at = models.DateTimeField(auto_now_add=True)
258
- updated_at = models.DateTimeField(auto_now=True)
259
- twilio_created_at = models.DateTimeField(null=True, blank=True, help_text="Timestamp from Twilio")
260
-
261
- # Relations
262
- otp_secret = models.ForeignKey(
263
- 'OTPSecret',
264
- on_delete=models.SET_NULL,
265
- null=True,
266
- blank=True,
267
- related_name='twilio_responses',
268
- help_text="Related OTP if applicable"
269
- )
270
-
271
- class Meta:
272
- app_label = 'django_cfg_accounts'
273
- verbose_name = 'Twilio Response'
274
- verbose_name_plural = 'Twilio Responses'
275
- ordering = ['-created_at']
276
- indexes = [
277
- models.Index(fields=['message_sid']),
278
- models.Index(fields=['verification_sid']),
279
- models.Index(fields=['status', 'created_at']),
280
- models.Index(fields=['response_type', 'service_type']),
281
- ]
282
-
283
- def __str__(self):
284
- identifier = self.message_sid or self.verification_sid or 'Unknown'
285
- return f"{self.get_service_type_display()} {self.get_response_type_display()} - {identifier}"
286
-
287
- @property
288
- def is_successful(self):
289
- """Check if the response indicates success."""
290
- success_statuses = ['sent', 'delivered', 'pending', 'approved']
291
- return self.status.lower() in success_statuses if self.status else False
292
-
293
- @property
294
- def has_error(self):
295
- """Check if the response has an error."""
296
- return bool(self.error_code or self.error_message)
297
-
298
-
299
206
  class UserActivity(models.Model):
300
207
  """
301
208
  User activity log.
@@ -26,7 +26,7 @@ class OTPRequestSerializer(serializers.Serializer):
26
26
  source_url = serializers.URLField(
27
27
  required=False,
28
28
  allow_blank=True,
29
- help_text="Source URL for tracking registration (e.g., https://reforms.ai)",
29
+ help_text="Source URL for tracking registration (e.g., https://unrealos.com)",
30
30
  )
31
31
 
32
32
  def validate_identifier(self, value):
@@ -76,7 +76,7 @@ class OTPVerifySerializer(serializers.Serializer):
76
76
  source_url = serializers.URLField(
77
77
  required=False,
78
78
  allow_blank=True,
79
- help_text="Source URL for tracking login (e.g., https://reforms.ai)",
79
+ help_text="Source URL for tracking login (e.g., https://unrealos.com)",
80
80
  )
81
81
 
82
82
  def validate_identifier(self, value):
@@ -6,7 +6,7 @@ from typing import Optional, Tuple
6
6
  import re
7
7
 
8
8
  from django_cfg.modules.django_telegram import DjangoTelegram
9
- from django_cfg.modules.django_twilio import SimpleTwilioService, send_whatsapp_otp_hybrid, verify_otp
9
+ from django_cfg.modules.django_twilio import SimpleTwilioService
10
10
  from ..models import OTPSecret, CustomUser
11
11
  from ..utils.notifications import AccountNotifications
12
12
  from ..signals import notify_failed_otp_attempt
@@ -28,53 +28,6 @@ class OTPService:
28
28
  phone_pattern = r'^\+[1-9]\d{6,14}$' # E.164 format: minimum 7 digits, maximum 15
29
29
  return bool(re.match(phone_pattern, clean_phone))
30
30
 
31
- @staticmethod
32
- def _get_temp_email_domain(source_url: Optional[str] = None) -> str:
33
- """
34
- Get domain for temporary email addresses.
35
-
36
- Priority:
37
- 1. Extract domain from source_url
38
- 2. Use config.site_url domain
39
- 3. Fallback to 'temp.local'
40
- """
41
- try:
42
- from django_cfg.core.config import get_current_config
43
- from urllib.parse import urlparse
44
-
45
- config = get_current_config()
46
-
47
- # Try to extract domain from source_url
48
- if source_url:
49
- try:
50
- parsed = urlparse(source_url)
51
- if parsed.netloc:
52
- # Remove www. prefix if present
53
- domain = parsed.netloc
54
- if domain.startswith("www."):
55
- domain = domain[4:]
56
- return domain
57
- except:
58
- pass
59
-
60
- # Try to use config.site_url domain
61
- if config and config.site_url:
62
- try:
63
- parsed = urlparse(config.site_url)
64
- if parsed.netloc:
65
- domain = parsed.netloc
66
- if domain.startswith("www."):
67
- domain = domain[4:]
68
- return domain
69
- except:
70
- pass
71
-
72
- # Fallback to temp.local
73
- return "temp.local"
74
-
75
- except Exception:
76
- return "temp.local"
77
-
78
31
  @staticmethod
79
32
  def _determine_channel(identifier: str) -> str:
80
33
  """Determine if identifier is email or phone."""
@@ -161,10 +114,8 @@ class OTPService:
161
114
  user = CustomUser.objects.get(phone=cleaned_identifier)
162
115
  created = False
163
116
  except CustomUser.DoesNotExist:
164
- # Create user with temp email based on phone and domain
165
- phone_clean = cleaned_identifier.replace('+', '').replace(' ', '')
166
- domain = OTPService._get_temp_email_domain(source_url)
167
- temp_email = f"phone_{phone_clean}@{domain}"
117
+ # Create user with temp email based on phone
118
+ temp_email = f"phone_{cleaned_identifier.replace('+', '').replace(' ', '')}@temp.local"
168
119
  user, created = CustomUser.objects.register_user(
169
120
  temp_email, source_url=source_url
170
121
  )
@@ -219,36 +170,10 @@ class OTPService:
219
170
  user, otp_code, is_new_user=created, source_url=source_url, channel='email'
220
171
  )
221
172
  else: # phone channel
222
- # Use hybrid WhatsApp OTP from twilio_service
223
- success, message = send_whatsapp_otp_hybrid(cleaned_identifier, otp_code)
224
-
225
- if not success:
226
- logger.error(f"❌ Failed to send phone OTP to {cleaned_identifier[:8]}: {message}")
227
- return False, "phone_send_failed"
228
-
229
- logger.info(f"🎉 Phone OTP sent successfully to {cleaned_identifier[:8]}: {message}")
230
-
231
- # Send telegram notification for admin
232
- try:
233
- # Extract method from message (e.g., "OTP sent via WhatsApp... (Direct WhatsApp)")
234
- method_used = "Hybrid WhatsApp"
235
- if "(Direct WhatsApp)" in message:
236
- method_used = "Direct WhatsApp"
237
- elif "(Verify API)" in message:
238
- method_used = "Verify API"
239
-
240
- DjangoTelegram.send_info(
241
- f"📱 Phone OTP Request ({method_used})",
242
- {
243
- "phone": cleaned_identifier,
244
- "method": method_used,
245
- "user_type": "New User" if created else "Existing User",
246
- "source_url": source_url or "Direct",
247
- "timestamp": timezone.now().strftime("%Y-%m-%d %H:%M:%S UTC")
248
- }
249
- )
250
- except Exception as e:
251
- logger.error(f"Failed to send telegram notification: {e}")
173
+ # Send OTP via SMS using Twilio
174
+ AccountNotifications.send_phone_otp_notification(
175
+ user, otp_code, cleaned_identifier, is_new_user=created, source_url=source_url
176
+ )
252
177
 
253
178
  return True, "success"
254
179
  except Exception as e:
@@ -306,47 +231,26 @@ class OTPService:
306
231
  return None
307
232
 
308
233
  try:
309
- if channel == 'phone':
310
- # Use Twilio Verify API for phone OTP verification
311
- try:
312
- is_valid, message = verify_otp(cleaned_identifier, cleaned_otp)
313
- if not is_valid:
314
- logger.warning(f"Twilio Verify API: Invalid OTP for {cleaned_identifier}")
315
-
316
- # Send notification for failed OTP attempt
317
- AccountNotifications.send_failed_otp_attempt(
318
- cleaned_identifier, channel=channel, reason=f"Verify API: {message}"
319
- )
320
-
321
- return None
322
-
323
- logger.info(f"Twilio Verify API: OTP verified for {cleaned_identifier}")
324
-
325
- except Exception as e:
326
- logger.error(f"Twilio Verify API error during verification: {e}")
327
- return None
328
- else:
329
- # Use OTPSecret for email channel
330
- otp_secret = OTPSecret.objects.filter(
331
- recipient=cleaned_identifier,
332
- channel_type=channel,
333
- secret=cleaned_otp,
334
- is_used=False,
335
- expires_at__gt=timezone.now(),
336
- ).first()
234
+ otp_secret = OTPSecret.objects.filter(
235
+ recipient=cleaned_identifier,
236
+ channel_type=channel,
237
+ secret=cleaned_otp,
238
+ is_used=False,
239
+ expires_at__gt=timezone.now(),
240
+ ).first()
337
241
 
338
- if not otp_secret or not otp_secret.is_valid:
339
- logger.warning(f"Invalid OTP for {cleaned_identifier} ({channel})")
340
-
341
- # Send notification for failed OTP attempt
342
- AccountNotifications.send_failed_otp_attempt(
343
- cleaned_identifier, channel=channel, reason="Invalid or expired OTP"
344
- )
345
-
346
- return None
242
+ if not otp_secret or not otp_secret.is_valid:
243
+ logger.warning(f"Invalid OTP for {cleaned_identifier} ({channel})")
244
+
245
+ # Send notification for failed OTP attempt
246
+ AccountNotifications.send_failed_otp_attempt(
247
+ cleaned_identifier, channel=channel, reason="Invalid or expired OTP"
248
+ )
249
+
250
+ return None
347
251
 
348
- # Mark OTP as used
349
- otp_secret.mark_used()
252
+ # Mark OTP as used
253
+ otp_secret.mark_used()
350
254
 
351
255
  # Get user based on channel
352
256
  try: