django-cfg 1.3.7__py3-none-any.whl → 1.3.11__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 (246) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +269 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +183 -460
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  48. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  49. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  50. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  51. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  52. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  53. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  54. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
  55. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  56. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  57. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
  58. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  59. django_cfg/apps/payments/config/__init__.py +14 -15
  60. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  61. django_cfg/apps/payments/config/helpers.py +8 -13
  62. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  63. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  64. django_cfg/apps/payments/middleware/api_access.py +32 -6
  65. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  66. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  67. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  68. django_cfg/apps/payments/models/balance.py +12 -0
  69. django_cfg/apps/payments/models/currencies.py +106 -32
  70. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  71. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  72. django_cfg/apps/payments/models/payments.py +94 -0
  73. django_cfg/apps/payments/services/core/base.py +4 -4
  74. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  75. django_cfg/apps/payments/services/core/payment_service.py +266 -39
  76. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  77. django_cfg/apps/payments/services/providers/base.py +303 -41
  78. django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
  79. django_cfg/apps/payments/services/providers/models/base.py +145 -0
  80. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  81. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  82. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  83. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  84. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  85. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  86. django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
  87. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  88. django_cfg/apps/payments/services/providers/registry.py +9 -37
  89. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  90. django_cfg/apps/payments/services/types/requests.py +19 -7
  91. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  92. django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
  93. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  94. django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
  95. django_cfg/apps/payments/tasks/__init__.py +39 -0
  96. django_cfg/apps/payments/tasks/types.py +73 -0
  97. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  98. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  99. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  100. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  101. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  102. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  103. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  104. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  105. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  106. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  107. django_cfg/apps/payments/urls.py +3 -2
  108. django_cfg/apps/payments/urls_admin.py +1 -1
  109. django_cfg/apps/payments/views/api/currencies.py +8 -5
  110. django_cfg/apps/payments/views/overview/services.py +2 -2
  111. django_cfg/apps/payments/views/serializers/currencies.py +22 -8
  112. django_cfg/apps/support/admin/__init__.py +10 -1
  113. django_cfg/apps/support/admin/support_admin.py +338 -141
  114. django_cfg/apps/tasks/admin/__init__.py +11 -0
  115. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  116. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  117. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  118. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  119. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  120. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  121. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  122. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  123. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  124. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  125. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  126. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  127. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  128. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  129. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  130. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  131. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  132. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  133. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  134. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  135. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  136. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  137. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  138. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  139. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  140. django_cfg/apps/tasks/urls.py +2 -2
  141. django_cfg/apps/tasks/urls_admin.py +2 -2
  142. django_cfg/apps/tasks/utils/__init__.py +1 -0
  143. django_cfg/apps/tasks/utils/simulator.py +356 -0
  144. django_cfg/apps/tasks/views/__init__.py +16 -0
  145. django_cfg/apps/tasks/views/api.py +569 -0
  146. django_cfg/apps/tasks/views/dashboard.py +58 -0
  147. django_cfg/config.py +1 -1
  148. django_cfg/core/config.py +10 -5
  149. django_cfg/core/generation.py +1 -1
  150. django_cfg/core/integration/__init__.py +21 -0
  151. django_cfg/management/commands/__init__.py +13 -1
  152. django_cfg/management/commands/migrate_all.py +9 -3
  153. django_cfg/management/commands/migrator.py +11 -6
  154. django_cfg/management/commands/rundramatiq.py +3 -2
  155. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  156. django_cfg/middleware/__init__.py +0 -2
  157. django_cfg/models/api_keys.py +115 -0
  158. django_cfg/models/constance.py +0 -11
  159. django_cfg/models/payments.py +137 -3
  160. django_cfg/modules/django_admin/__init__.py +64 -0
  161. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  162. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  163. django_cfg/modules/django_admin/decorators/display.py +106 -0
  164. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  165. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  166. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  167. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  168. django_cfg/modules/django_admin/models/__init__.py +20 -0
  169. django_cfg/modules/django_admin/models/action_models.py +33 -0
  170. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  171. django_cfg/modules/django_admin/models/base.py +26 -0
  172. django_cfg/modules/django_admin/models/display_models.py +31 -0
  173. django_cfg/modules/django_admin/utils/badges.py +159 -0
  174. django_cfg/modules/django_admin/utils/displays.py +247 -0
  175. django_cfg/modules/django_currency/__init__.py +2 -2
  176. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  177. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  178. django_cfg/modules/django_currency/core/converter.py +12 -12
  179. django_cfg/modules/django_currency/database/__init__.py +2 -2
  180. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  181. django_cfg/modules/django_llm/llm/client.py +10 -2
  182. django_cfg/modules/django_tasks.py +54 -21
  183. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  184. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  185. django_cfg/modules/django_unfold/dashboard.py +14 -13
  186. django_cfg/modules/django_unfold/models/config.py +1 -1
  187. django_cfg/registry/core.py +7 -9
  188. django_cfg/registry/third_party.py +2 -2
  189. django_cfg/template_archive/django_sample.zip +0 -0
  190. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
  191. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
  192. django_cfg/apps/accounts/admin/activity.py +0 -96
  193. django_cfg/apps/accounts/admin/group.py +0 -17
  194. django_cfg/apps/accounts/admin/otp.py +0 -59
  195. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  196. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  197. django_cfg/apps/accounts/admin/user.py +0 -300
  198. django_cfg/apps/agents/core/agent.py +0 -281
  199. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  200. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  201. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  202. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  203. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  204. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  205. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  206. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  207. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  208. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  209. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  210. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  211. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  212. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  213. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  214. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  215. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  216. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  217. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  218. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  219. django_cfg/apps/payments/config/constance/fields.py +0 -69
  220. django_cfg/apps/payments/config/constance/settings.py +0 -160
  221. django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
  222. django_cfg/apps/tasks/admin.py +0 -320
  223. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  224. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  225. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  226. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  227. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  228. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  229. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  230. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  231. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  232. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  233. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  234. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  235. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  236. django_cfg/apps/tasks/views.py +0 -461
  237. django_cfg/management/commands/auto_generate.py +0 -486
  238. django_cfg/middleware/static_nocache.py +0 -55
  239. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  240. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  241. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  242. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  243. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  244. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  245. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  246. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,486 +0,0 @@
1
- """
2
- Auto Generation Command for Django Config Toolkit
3
- Generate configuration files, models, and other Django components.
4
- """
5
-
6
- import os
7
- import json
8
- from pathlib import Path
9
- from django.core.management.base import BaseCommand
10
- from django.core.management import call_command
11
- from django.conf import settings
12
- import questionary
13
- from datetime import datetime
14
- from django_cfg.modules.django_logger import get_logger
15
-
16
- from django_cfg import ConfigToolkit
17
-
18
- logger = get_logger('auto_generate')
19
-
20
-
21
- class Command(BaseCommand):
22
- help = 'Auto-generate configuration files and Django components'
23
-
24
- def add_arguments(self, parser):
25
- parser.add_argument(
26
- '--config',
27
- action='store_true',
28
- help='Generate configuration files only'
29
- )
30
- parser.add_argument(
31
- '--models',
32
- action='store_true',
33
- help='Generate model files only'
34
- )
35
- parser.add_argument(
36
- '--all',
37
- action='store_true',
38
- help='Generate all components'
39
- )
40
-
41
- def handle(self, *args, **options):
42
- logger.info("Starting auto_generate command")
43
- if options['all']:
44
- self.generate_all()
45
- elif options['config']:
46
- self.generate_config_files()
47
- elif options['models']:
48
- self.generate_model_files()
49
- else:
50
- self.show_interactive_menu()
51
-
52
- def show_interactive_menu(self):
53
- """Show interactive menu with generation options"""
54
- self.stdout.write(self.style.SUCCESS('\n🚀 Auto Generation Tool - Django Config Toolkit\n'))
55
-
56
- choices = [
57
- questionary.Choice('⚙️ Generate Configuration Files', value='config'),
58
- questionary.Choice('📊 Generate Model Files', value='models'),
59
- questionary.Choice('🔄 Generate All Components', value='all'),
60
- questionary.Choice('📝 Generate Environment Template', value='env'),
61
- questionary.Choice('🔧 Generate Settings Template', value='settings'),
62
- questionary.Choice('❌ Exit', value='exit')
63
- ]
64
-
65
- choice = questionary.select(
66
- 'Select generation option:',
67
- choices=choices
68
- ).ask()
69
-
70
- if choice == 'config':
71
- self.generate_config_files()
72
- elif choice == 'models':
73
- self.generate_model_files()
74
- elif choice == 'all':
75
- self.generate_all()
76
- elif choice == 'env':
77
- self.generate_env_template()
78
- elif choice == 'settings':
79
- self.generate_settings_template()
80
- elif choice == 'exit':
81
- self.stdout.write('Goodbye! 👋')
82
- return
83
-
84
- def generate_all(self):
85
- """Generate all components"""
86
- self.stdout.write(self.style.SUCCESS('🔄 Generating all components...'))
87
-
88
- self.generate_config_files()
89
- self.generate_model_files()
90
- self.generate_env_template()
91
- self.generate_settings_template()
92
-
93
- self.stdout.write(self.style.SUCCESS('✅ All components generated!'))
94
-
95
- def generate_config_files(self):
96
- """Generate configuration files"""
97
- self.stdout.write(self.style.SUCCESS('⚙️ Generating configuration files...'))
98
-
99
- # Generate config.py
100
- self.generate_config_py()
101
-
102
- # Generate database config
103
- self.generate_database_config()
104
-
105
- # Generate security config
106
- self.generate_security_config()
107
-
108
- self.stdout.write(self.style.SUCCESS('✅ Configuration files generated!'))
109
-
110
- def generate_model_files(self):
111
- """Generate model files"""
112
- self.stdout.write(self.style.SUCCESS('📊 Generating model files...'))
113
-
114
- # Generate base models
115
- self.generate_base_models()
116
-
117
- # Generate API models
118
- self.generate_api_models()
119
-
120
- self.stdout.write(self.style.SUCCESS('✅ Model files generated!'))
121
-
122
- def generate_config_py(self):
123
- """Generate main config.py file"""
124
- config_content = '''"""
125
- Configuration file for Django Config Toolkit
126
- Auto-generated configuration with smart defaults.
127
- """
128
-
129
- from django_cfg import ConfigToolkit
130
-
131
- # Initialize configuration
132
- config = ConfigToolkit()
133
-
134
- # Export all settings
135
- globals().update(config.get_django_settings())
136
-
137
- # Type-safe access to configuration
138
- DEBUG = config.debug
139
- SECRET_KEY = config.secret_key
140
- DATABASE_URL = config.database_url
141
- ALLOWED_HOSTS = config.allowed_hosts
142
- '''
143
-
144
- config_path = Path('config.py')
145
- if not config_path.exists():
146
- with open(config_path, 'w') as f:
147
- f.write(config_content)
148
- self.stdout.write(f' 📄 Created {config_path}')
149
-
150
- def generate_database_config(self):
151
- """Generate database configuration"""
152
- db_config_content = '''"""
153
- Database Configuration
154
- Auto-generated database settings.
155
- """
156
-
157
- from django_cfg import DatabaseConfig
158
-
159
- # Database configuration
160
- db_config = DatabaseConfig(
161
- database_url="sqlite:///db.sqlite3",
162
- max_connections=20,
163
- conn_max_age=600,
164
- conn_health_checks=True,
165
- ssl_require=False,
166
- ssl_mode="prefer",
167
- query_timeout=30,
168
- )
169
-
170
- # Additional databases (uncomment and configure as needed)
171
- # db_config.read_replica_url = "postgresql://user:pass@host:port/db"
172
- # db_config.cache_db_url = "redis://localhost:6379/1"
173
- # db_config.analytics_db_url = "postgresql://user:pass@host:port/analytics"
174
-
175
- # Export database settings
176
- globals().update(db_config.to_django_settings())
177
- '''
178
-
179
- db_config_path = Path('database_config.py')
180
- if not db_config_path.exists():
181
- with open(db_config_path, 'w') as f:
182
- f.write(db_config_content)
183
- self.stdout.write(f' 📄 Created {db_config_path}')
184
-
185
- def generate_security_config(self):
186
- """Generate security configuration"""
187
- security_config_content = '''"""
188
- Security Configuration
189
- Auto-generated security settings.
190
- """
191
-
192
- from django_cfg import SecurityConfig
193
-
194
- # Security configuration
195
- security_config = SecurityConfig(
196
- secret_key="your-secret-key-here",
197
- debug=False,
198
- allowed_hosts=["localhost", "127.0.0.1"],
199
- csrf_trusted_origins=["http://localhost:3000"],
200
- cors_allowed_origins=["http://localhost:3000"],
201
- cors_allowed_methods=["GET", "POST", "PUT", "DELETE"],
202
- cors_allowed_headers=["*"],
203
- )
204
-
205
- # Export security settings
206
- globals().update(security_config.to_django_settings())
207
- '''
208
-
209
- security_config_path = Path('security_config.py')
210
- if not security_config_path.exists():
211
- with open(security_config_path, 'w') as f:
212
- f.write(security_config_content)
213
- self.stdout.write(f' 📄 Created {security_config_path}')
214
-
215
- def generate_base_models(self):
216
- """Generate base model files"""
217
- base_models_content = '''"""
218
- Base Models
219
- Auto-generated base model classes.
220
- """
221
-
222
- from django.db import models
223
- from django.utils import timezone
224
-
225
-
226
- class BaseModel(models.Model):
227
- """Base model with common fields."""
228
-
229
- created_at = models.DateTimeField(auto_now_add=True)
230
- updated_at = models.DateTimeField(auto_now=True)
231
- is_active = models.BooleanField(default=True)
232
-
233
- class Meta:
234
- abstract = True
235
-
236
- def __str__(self):
237
- return f"{self.__class__.__name__} {self.id}"
238
-
239
-
240
- class TimestampedModel(BaseModel):
241
- """Model with timestamps."""
242
-
243
- created_by = models.ForeignKey(
244
- 'auth.User',
245
- on_delete=models.SET_NULL,
246
- null=True,
247
- blank=True,
248
- related_name='%(class)s_created'
249
- )
250
- updated_by = models.ForeignKey(
251
- 'auth.User',
252
- on_delete=models.SET_NULL,
253
- null=True,
254
- blank=True,
255
- related_name='%(class)s_updated'
256
- )
257
-
258
- class Meta:
259
- abstract = True
260
- '''
261
-
262
- base_models_path = Path('models/base.py')
263
- base_models_path.parent.mkdir(exist_ok=True)
264
-
265
- if not base_models_path.exists():
266
- with open(base_models_path, 'w') as f:
267
- f.write(base_models_content)
268
- self.stdout.write(f' 📄 Created {base_models_path}')
269
-
270
- def generate_api_models(self):
271
- """Generate API model files"""
272
- api_models_content = '''"""
273
- API Models
274
- Auto-generated API model classes.
275
- """
276
-
277
- from django.db import models
278
- from .base import BaseModel
279
-
280
-
281
- class APIModel(BaseModel):
282
- """Base model for API resources."""
283
-
284
- name = models.CharField(max_length=255)
285
- description = models.TextField(blank=True)
286
- slug = models.SlugField(max_length=255, unique=True)
287
-
288
- class Meta:
289
- abstract = True
290
-
291
- def __str__(self):
292
- return self.name
293
-
294
-
295
- class ConfigModel(APIModel):
296
- """Configuration model for storing settings."""
297
-
298
- key = models.CharField(max_length=255, unique=True)
299
- value = models.JSONField()
300
- value_type = models.CharField(
301
- max_length=50,
302
- choices=[
303
- ('string', 'String'),
304
- ('integer', 'Integer'),
305
- ('float', 'Float'),
306
- ('boolean', 'Boolean'),
307
- ('json', 'JSON'),
308
- ],
309
- default='string'
310
- )
311
-
312
- class Meta:
313
- verbose_name = 'Configuration'
314
- verbose_name_plural = 'Configurations'
315
- '''
316
-
317
- api_models_path = Path('models/api.py')
318
- api_models_path.parent.mkdir(exist_ok=True)
319
-
320
- if not api_models_path.exists():
321
- with open(api_models_path, 'w') as f:
322
- f.write(api_models_content)
323
- self.stdout.write(f' 📄 Created {api_models_path}')
324
-
325
- def generate_env_template(self):
326
- """Generate environment template file"""
327
- env_template_content = '''# Environment Configuration Template
328
- # Copy this file to .env and configure your settings
329
-
330
- # Django Settings
331
- DEBUG=True
332
- SECRET_KEY=your-secret-key-here
333
- ALLOWED_HOSTS=localhost,127.0.0.1
334
-
335
- # Database Settings
336
- DATABASE_URL=sqlite:///db.sqlite3
337
- # DATABASE_URL=postgresql://user:password@localhost:5432/dbname
338
- # DATABASE_URL=mysql://user:password@localhost:3306/dbname
339
-
340
- # Additional Databases (optional)
341
- # DATABASE_URL_CARS=postgresql://user:password@localhost:5432/cars_db
342
- # DATABASE_URL_ANALYTICS=postgresql://user:password@localhost:5432/analytics_db
343
- # DATABASE_URL_CACHE=redis://localhost:6379/1
344
-
345
- # Email Settings
346
- EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
347
- EMAIL_HOST=smtp.gmail.com
348
- EMAIL_PORT=587
349
- EMAIL_USE_TLS=True
350
- EMAIL_HOST_USER=your-email@gmail.com
351
- EMAIL_HOST_PASSWORD=your-app-password
352
-
353
- # Cache Settings
354
- CACHE_BACKEND=django.core.cache.backends.locmem.LocMemCache
355
- # CACHE_BACKEND=django.core.cache.backends.redis.RedisCache
356
- # CACHE_LOCATION=redis://127.0.0.1:6379/1
357
-
358
- # Security Settings
359
- CSRF_TRUSTED_ORIGINS=http://localhost:3000
360
- CORS_ALLOWED_ORIGINS=http://localhost:3000
361
-
362
- # API Settings
363
- API_KEY=your-api-key-here
364
- API_RATE_LIMIT=1000
365
-
366
- # Logging Settings
367
- LOG_LEVEL=INFO
368
- LOG_FILE=logs/app.log
369
- '''
370
-
371
- env_template_path = Path('.env.template')
372
- if not env_template_path.exists():
373
- with open(env_template_path, 'w') as f:
374
- f.write(env_template_content)
375
- self.stdout.write(f' 📄 Created {env_template_path}')
376
-
377
- def generate_settings_template(self):
378
- """Generate Django settings template"""
379
- settings_template_content = '''"""
380
- Django Settings Template
381
- Auto-generated Django settings with Django Config Toolkit.
382
- """
383
-
384
- import os
385
- from pathlib import Path
386
-
387
- # Build paths inside the project like this: BASE_DIR / 'subdir'.
388
- BASE_DIR = Path(__file__).resolve().parent.parent
389
-
390
- # Import configuration from Django Config Toolkit
391
- from django_cfg import ConfigToolkit
392
-
393
- # Initialize configuration
394
- config = ConfigToolkit()
395
-
396
- # Export all settings
397
- globals().update(config.get_django_settings())
398
-
399
- # Application definition
400
- INSTALLED_APPS = [
401
- 'django.contrib.admin',
402
- 'django.contrib.auth',
403
- 'django.contrib.contenttypes',
404
- 'django.contrib.sessions',
405
- 'django.contrib.messages',
406
- 'django.contrib.staticfiles',
407
-
408
- # Third party apps
409
- 'rest_framework',
410
- 'corsheaders',
411
- 'django_cfg',
412
-
413
- # Local apps
414
- # Add your apps here
415
- ]
416
-
417
- MIDDLEWARE = [
418
- 'corsheaders.middleware.CorsMiddleware',
419
- 'django.middleware.security.SecurityMiddleware',
420
- 'django.contrib.sessions.middleware.SessionMiddleware',
421
- 'django.middleware.common.CommonMiddleware',
422
- 'django.middleware.csrf.CsrfViewMiddleware',
423
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
424
- 'django.contrib.messages.middleware.MessageMiddleware',
425
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
426
- ]
427
-
428
- ROOT_URLCONF = 'project.urls'
429
-
430
- TEMPLATES = [
431
- {
432
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
433
- 'DIRS': [BASE_DIR / 'templates'],
434
- 'APP_DIRS': True,
435
- 'OPTIONS': {
436
- 'context_processors': [
437
- 'django.template.context_processors.debug',
438
- 'django.template.context_processors.request',
439
- 'django.contrib.auth.context_processors.auth',
440
- 'django.contrib.messages.context_processors.messages',
441
- ],
442
- },
443
- },
444
- ]
445
-
446
- WSGI_APPLICATION = 'project.wsgi.application'
447
-
448
- # Static files (CSS, JavaScript, Images)
449
- STATIC_URL = '/static/'
450
- STATIC_ROOT = BASE_DIR / 'staticfiles'
451
- STATICFILES_DIRS = [BASE_DIR / 'static']
452
-
453
- # Media files
454
- MEDIA_URL = '/media/'
455
- MEDIA_ROOT = BASE_DIR / 'media'
456
-
457
- # Default primary key field type
458
- DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
459
-
460
- # REST Framework settings
461
- REST_FRAMEWORK = {
462
- 'DEFAULT_AUTHENTICATION_CLASSES': [
463
- 'rest_framework.authentication.SessionAuthentication',
464
- 'rest_framework.authentication.TokenAuthentication',
465
- ],
466
- 'DEFAULT_PERMISSION_CLASSES': [
467
- 'rest_framework.permissions.IsAuthenticated',
468
- ],
469
- 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
470
- 'PAGE_SIZE': 20,
471
- }
472
-
473
- # Health check URLs
474
- HEALTH_CHECK_URLS = [
475
- 'health/',
476
- 'health/detailed/',
477
- 'ready/',
478
- 'alive/',
479
- ]
480
- '''
481
-
482
- settings_template_path = Path('settings_template.py')
483
- if not settings_template_path.exists():
484
- with open(settings_template_path, 'w') as f:
485
- f.write(settings_template_content)
486
- self.stdout.write(f' 📄 Created {settings_template_path}')
@@ -1,55 +0,0 @@
1
- """
2
- Static files no-cache middleware for django-cfg.
3
-
4
- Automatically disables caching for static files in development environments
5
- to prevent browser caching issues during development.
6
- """
7
-
8
- from django.conf import settings
9
- from django_cfg.core.config import EnvironmentMode
10
-
11
-
12
- class StaticNoCacheMiddleware:
13
- """
14
- Middleware to disable caching for static files in development.
15
-
16
- This ensures that JavaScript and CSS files are always fresh during development,
17
- preventing browser caching issues when files are updated.
18
-
19
- Automatically detects development mode based on:
20
- - DEBUG setting
21
- - ENV_MODE environment variable
22
- """
23
-
24
- def __init__(self, get_response):
25
- self.get_response = get_response
26
-
27
- # Determine if we should disable caching
28
- self.should_disable_cache = self._should_disable_cache()
29
-
30
- def _should_disable_cache(self):
31
- """Determine if caching should be disabled based on environment."""
32
- # Always disable in DEBUG mode
33
- if settings.DEBUG:
34
- return True
35
-
36
- # Check ENV_MODE if available
37
- env_mode = getattr(settings, 'ENV_MODE', None)
38
- if env_mode == EnvironmentMode.DEVELOPMENT or env_mode == EnvironmentMode.TEST:
39
- return True
40
-
41
- return False
42
-
43
- def __call__(self, request):
44
- response = self.get_response(request)
45
-
46
- # Apply no-cache headers for static files in development
47
- if self.should_disable_cache and request.path.startswith('/static/'):
48
- response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
49
- response['Pragma'] = 'no-cache'
50
- response['Expires'] = '0'
51
- # Add ETag removal to prevent conditional requests
52
- if 'ETag' in response:
53
- del response['ETag']
54
-
55
- return response
@@ -1,157 +0,0 @@
1
- import logging
2
- import requests
3
- import time
4
- from datetime import datetime
5
- from typing import Dict, Set, Optional
6
- from cachetools import TTLCache
7
-
8
- from ..core.models import Rate, YahooFinanceResponse
9
- from ..core.exceptions import RateFetchError
10
-
11
- logger = logging.getLogger(__name__)
12
-
13
-
14
- class YahooFinanceClient:
15
- """Simple Yahoo Finance client without yfinance dependency."""
16
-
17
- BASE_URL = "https://query1.finance.yahoo.com/v8/finance/chart"
18
-
19
- def __init__(self, cache_ttl: int = 3600):
20
- """Initialize Yahoo Finance client with TTL cache."""
21
- self._rate_cache = TTLCache(maxsize=500, ttl=cache_ttl)
22
- self._session = requests.Session()
23
- self._session.headers.update({
24
- 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
25
- })
26
- self._last_request_time = 0
27
- self._rate_limit_delay = 1.0 # 1 second between requests
28
-
29
- def _get_yahoo_symbol(self, base: str, quote: str) -> str:
30
- """Convert currency pair to Yahoo Finance symbol format."""
31
- # Yahoo uses format like EURUSD=X for forex pairs
32
- return f"{base}{quote}=X"
33
-
34
- def fetch_rate(self, base: str, quote: str) -> Rate:
35
- """
36
- Fetch forex rate from Yahoo Finance with caching.
37
-
38
- Args:
39
- base: Base currency code (e.g., EUR)
40
- quote: Quote currency code (e.g., USD)
41
-
42
- Returns:
43
- Rate object with exchange rate data
44
-
45
- Raises:
46
- RateFetchError: If rate fetch fails
47
- """
48
- base = base.upper()
49
- quote = quote.upper()
50
- cache_key = f"{base}_{quote}"
51
-
52
- # Try cache first
53
- if cache_key in self._rate_cache:
54
- logger.debug(f"Retrieved rate {base}/{quote} from Yahoo cache")
55
- return self._rate_cache[cache_key]
56
-
57
- symbol = self._get_yahoo_symbol(base, quote)
58
-
59
- # Rate limiting
60
- current_time = time.time()
61
- time_since_last_request = current_time - self._last_request_time
62
- if time_since_last_request < self._rate_limit_delay:
63
- sleep_time = self._rate_limit_delay - time_since_last_request
64
- logger.debug(f"Rate limiting: sleeping for {sleep_time:.2f}s")
65
- time.sleep(sleep_time)
66
-
67
- try:
68
- response = self._session.get(f"{self.BASE_URL}/{symbol}")
69
- self._last_request_time = time.time()
70
- response.raise_for_status()
71
-
72
- raw_data = response.json()
73
-
74
- # Validate response using Pydantic model
75
- try:
76
- yahoo_response = YahooFinanceResponse(**raw_data)
77
- except Exception as e:
78
- raise RateFetchError(f"Invalid Yahoo Finance response format: {e}")
79
-
80
- if not yahoo_response.chart.result:
81
- raise RateFetchError(f"No data returned for {symbol}")
82
-
83
- meta = yahoo_response.chart.result[0].meta
84
- rate_value = meta.regularMarketPrice
85
- timestamp = datetime.fromtimestamp(meta.regularMarketTime)
86
-
87
- rate = Rate(
88
- source="yahoo",
89
- base_currency=base,
90
- quote_currency=quote,
91
- rate=float(rate_value),
92
- timestamp=timestamp
93
- )
94
-
95
- self._rate_cache[cache_key] = rate
96
- logger.info(f"Fetched rate {base}/{quote} = {rate_value} from Yahoo Finance")
97
- return rate
98
-
99
- except requests.exceptions.RequestException as e:
100
- logger.error(f"Failed to fetch rate from Yahoo Finance: {e}")
101
- raise RateFetchError(f"Yahoo Finance API error: {e}")
102
- except (KeyError, TypeError, ValueError) as e:
103
- logger.error(f"Failed to parse Yahoo Finance response: {e}")
104
- raise RateFetchError(f"Invalid response format: {e}")
105
- except Exception as e:
106
- logger.error(f"Unexpected error fetching from Yahoo Finance: {e}")
107
- raise RateFetchError(f"Yahoo Finance fetch failed: {e}")
108
-
109
- def supports_pair(self, base: str, quote: str) -> bool:
110
- """
111
- Check if Yahoo Finance supports the given currency pair.
112
-
113
- Yahoo Finance primarily supports major forex pairs.
114
- """
115
- base = base.upper()
116
- quote = quote.upper()
117
-
118
- # Major currencies supported by Yahoo Finance
119
- major_currencies = {
120
- 'USD', 'EUR', 'GBP', 'JPY', 'CHF', 'CAD', 'AUD', 'NZD',
121
- 'SEK', 'NOK', 'DKK', 'PLN', 'CZK', 'HUF', 'RUB', 'CNY',
122
- 'INR', 'KRW', 'SGD', 'HKD', 'THB', 'MXN', 'BRL', 'ZAR',
123
- 'TRY', 'ILS'
124
- }
125
-
126
- return base in major_currencies and quote in major_currencies
127
-
128
- def get_all_supported_currencies(self) -> Dict[str, str]:
129
- """Get all major currencies supported by Yahoo Finance."""
130
- return {
131
- 'USD': 'US Dollar',
132
- 'EUR': 'Euro',
133
- 'GBP': 'British Pound',
134
- 'JPY': 'Japanese Yen',
135
- 'CHF': 'Swiss Franc',
136
- 'CAD': 'Canadian Dollar',
137
- 'AUD': 'Australian Dollar',
138
- 'NZD': 'New Zealand Dollar',
139
- 'SEK': 'Swedish Krona',
140
- 'NOK': 'Norwegian Krone',
141
- 'DKK': 'Danish Krone',
142
- 'PLN': 'Polish Zloty',
143
- 'CZK': 'Czech Koruna',
144
- 'HUF': 'Hungarian Forint',
145
- 'RUB': 'Russian Ruble',
146
- 'CNY': 'Chinese Yuan',
147
- 'INR': 'Indian Rupee',
148
- 'KRW': 'South Korean Won',
149
- 'SGD': 'Singapore Dollar',
150
- 'HKD': 'Hong Kong Dollar',
151
- 'THB': 'Thai Baht',
152
- 'MXN': 'Mexican Peso',
153
- 'BRL': 'Brazilian Real',
154
- 'ZAR': 'South African Rand',
155
- 'TRY': 'Turkish Lira',
156
- 'ILS': 'Israeli Shekel'
157
- }