django-cfg 1.3.9__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 (187) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/payments/admin/networks_admin.py +12 -1
  3. django_cfg/apps/payments/admin/payments_admin.py +13 -0
  4. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
  5. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  6. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  7. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  8. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  9. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  10. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  11. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  12. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +33 -3
  13. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  14. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
  15. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  16. django_cfg/apps/payments/config/__init__.py +14 -15
  17. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  18. django_cfg/apps/payments/config/helpers.py +8 -13
  19. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  20. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  21. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  22. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  23. django_cfg/apps/payments/models/payments.py +94 -0
  24. django_cfg/apps/payments/services/core/base.py +4 -4
  25. django_cfg/apps/payments/services/core/payment_service.py +265 -38
  26. django_cfg/apps/payments/services/providers/base.py +209 -3
  27. django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
  28. django_cfg/apps/payments/services/providers/models/base.py +25 -2
  29. django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
  30. django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
  31. django_cfg/apps/payments/services/providers/registry.py +5 -5
  32. django_cfg/apps/payments/services/types/requests.py +19 -7
  33. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  34. django_cfg/apps/payments/static/payments/js/api-client.js +6 -1
  35. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  36. django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
  37. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  38. django_cfg/apps/payments/urls.py +3 -2
  39. django_cfg/apps/payments/views/api/currencies.py +3 -0
  40. django_cfg/apps/payments/views/serializers/currencies.py +18 -5
  41. django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
  42. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  43. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  44. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  45. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  46. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  47. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  48. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  49. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  50. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  51. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  52. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  53. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  54. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  55. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  56. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  57. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  58. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  59. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  60. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  61. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  62. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  63. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  64. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  65. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  66. django_cfg/apps/tasks/urls.py +2 -2
  67. django_cfg/apps/tasks/urls_admin.py +2 -2
  68. django_cfg/apps/tasks/utils/__init__.py +1 -0
  69. django_cfg/apps/tasks/utils/simulator.py +356 -0
  70. django_cfg/apps/tasks/views/__init__.py +16 -0
  71. django_cfg/apps/tasks/views/api.py +569 -0
  72. django_cfg/apps/tasks/views/dashboard.py +58 -0
  73. django_cfg/core/integration/__init__.py +21 -0
  74. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  75. django_cfg/models/constance.py +0 -11
  76. django_cfg/models/payments.py +137 -3
  77. django_cfg/modules/django_tasks.py +54 -21
  78. django_cfg/registry/core.py +4 -9
  79. django_cfg/template_archive/django_sample.zip +0 -0
  80. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -2
  81. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/RECORD +84 -152
  82. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  83. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  84. django_cfg/apps/payments/config/constance/fields.py +0 -69
  85. django_cfg/apps/payments/config/constance/settings.py +0 -160
  86. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
  87. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
  88. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
  89. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  90. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  91. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  92. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  93. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  94. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  95. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  96. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  97. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  98. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  99. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  100. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  101. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  102. django_cfg/apps/tasks/views.py +0 -461
  103. django_cfg/management/commands/app_agent_diagnose.py +0 -470
  104. django_cfg/management/commands/app_agent_generate.py +0 -342
  105. django_cfg/management/commands/app_agent_info.py +0 -308
  106. django_cfg/management/commands/auto_generate.py +0 -486
  107. django_cfg/modules/django_app_agent/__init__.py +0 -87
  108. django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
  109. django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
  110. django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
  111. django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
  112. django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
  113. django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
  114. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
  115. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
  116. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
  117. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
  118. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
  119. django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
  120. django_cfg/modules/django_app_agent/core/__init__.py +0 -33
  121. django_cfg/modules/django_app_agent/core/config.py +0 -300
  122. django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
  123. django_cfg/modules/django_app_agent/models/__init__.py +0 -71
  124. django_cfg/modules/django_app_agent/models/base.py +0 -283
  125. django_cfg/modules/django_app_agent/models/context.py +0 -496
  126. django_cfg/modules/django_app_agent/models/enums.py +0 -481
  127. django_cfg/modules/django_app_agent/models/requests.py +0 -500
  128. django_cfg/modules/django_app_agent/models/responses.py +0 -585
  129. django_cfg/modules/django_app_agent/pytest.ini +0 -6
  130. django_cfg/modules/django_app_agent/services/__init__.py +0 -42
  131. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
  132. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
  133. django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
  134. django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
  135. django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
  136. django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
  137. django_cfg/modules/django_app_agent/services/base.py +0 -437
  138. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
  139. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
  140. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
  141. django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
  142. django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
  143. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
  144. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
  145. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
  146. django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
  147. django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
  148. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
  149. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
  150. django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
  151. django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
  152. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
  153. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
  154. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
  155. django_cfg/modules/django_app_agent/services/report_service.py +0 -332
  156. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
  157. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
  158. django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
  159. django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
  160. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
  161. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
  162. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
  163. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
  164. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
  165. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
  166. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
  167. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
  168. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
  169. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
  170. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
  171. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
  172. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
  173. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
  174. django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
  175. django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
  176. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
  177. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
  178. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
  179. django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
  180. django_cfg/modules/django_app_agent/ui/cli.py +0 -419
  181. django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
  182. django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
  183. django_cfg/modules/django_app_agent/utils/logging.py +0 -360
  184. django_cfg/modules/django_app_agent/utils/validation.py +0 -417
  185. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  186. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  187. {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,236 +0,0 @@
1
- """
2
- Jinja2 Template Engine for Django App Agent.
3
-
4
- This module provides a powerful Jinja2-based template engine
5
- with custom filters and functions for Django code generation.
6
- """
7
-
8
- from typing import Dict, Any, Set, Optional, List
9
- import re
10
- from pathlib import Path
11
-
12
- from jinja2 import Environment, BaseLoader, TemplateNotFound, select_autoescape
13
- from jinja2.exceptions import TemplateError
14
-
15
- from ...core.exceptions import ValidationError
16
-
17
-
18
- class StringTemplateLoader(BaseLoader):
19
- """Custom Jinja2 loader for string-based templates."""
20
-
21
- def __init__(self, templates: Dict[str, str]):
22
- """Initialize with template dictionary."""
23
- self.templates = templates
24
-
25
- def get_source(self, environment: Environment, template: str) -> tuple:
26
- """Get template source."""
27
- if template not in self.templates:
28
- raise TemplateNotFound(template)
29
-
30
- source = self.templates[template]
31
- return source, None, lambda: True
32
-
33
-
34
- class JinjaTemplateEngine:
35
- """Jinja2-based template engine with Django-specific features."""
36
-
37
- def __init__(self):
38
- """Initialize Jinja2 environment with custom filters."""
39
- self.templates: Dict[str, str] = {}
40
- self.env = self._create_environment()
41
-
42
- def _create_environment(self) -> Environment:
43
- """Create Jinja2 environment with custom filters and functions."""
44
- env = Environment(
45
- loader=StringTemplateLoader(self.templates),
46
- autoescape=select_autoescape(['html', 'xml']),
47
- trim_blocks=True,
48
- lstrip_blocks=True
49
- )
50
-
51
- # Add custom filters
52
- env.filters.update({
53
- 'snake_case': self._snake_case,
54
- 'camel_case': self._camel_case,
55
- 'pascal_case': self._pascal_case,
56
- 'kebab_case': self._kebab_case,
57
- 'title_case': self._title_case,
58
- 'plural': self._pluralize,
59
- 'singular': self._singularize,
60
- 'django_field': self._django_field_repr,
61
- 'python_repr': self._python_repr,
62
- 'indent': self._indent,
63
- 'comment_block': self._comment_block
64
- })
65
-
66
- # Add custom functions
67
- env.globals.update({
68
- 'now': self._now,
69
- 'uuid4': self._uuid4,
70
- 'range': range,
71
- 'enumerate': enumerate,
72
- 'zip': zip
73
- })
74
-
75
- return env
76
-
77
- def add_template(self, name: str, content: str) -> None:
78
- """Add a template to the engine."""
79
- self.templates[name] = content
80
- # Recreate environment to update loader
81
- self.env = self._create_environment()
82
-
83
- def add_templates(self, templates: Dict[str, str]) -> None:
84
- """Add multiple templates to the engine."""
85
- self.templates.update(templates)
86
- # Recreate environment to update loader
87
- self.env = self._create_environment()
88
-
89
- def render(
90
- self,
91
- template_name: str,
92
- variables: Dict[str, Any]
93
- ) -> tuple[str, Set[str], Set[str]]:
94
- """
95
- Render template with variables.
96
-
97
- Returns:
98
- tuple: (rendered_content, variables_used, missing_variables)
99
- """
100
- try:
101
- template = self.env.get_template(template_name)
102
-
103
- # Get template variables (simplified approach - read template source from file)
104
- template_vars = set()
105
- try:
106
- # Get template source from the loader
107
- source, _ = self.env.loader.get_source(self.env, template_name)
108
- ast = self.env.parse(source)
109
- for node in ast.find_all('Name'):
110
- if node.ctx == 'load':
111
- template_vars.add(node.name)
112
- except Exception:
113
- # Fallback: assume all provided variables are used
114
- template_vars = set(variables.keys())
115
-
116
- # Remove Jinja2 built-ins and our custom functions
117
- builtin_vars = {
118
- 'range', 'enumerate', 'zip', 'now', 'uuid4',
119
- 'loop', 'super', 'self', 'varargs', 'kwargs'
120
- }
121
- template_vars = template_vars - builtin_vars
122
-
123
- # Check for missing variables
124
- missing_vars = template_vars - set(variables.keys())
125
- variables_used = template_vars - missing_vars
126
-
127
- # Render template
128
- rendered = template.render(**variables)
129
-
130
- return rendered, variables_used, missing_vars
131
-
132
- except TemplateNotFound:
133
- raise ValidationError(
134
- f"Template '{template_name}' not found",
135
- validation_type="template_not_found"
136
- )
137
- except TemplateError as e:
138
- raise ValidationError(
139
- f"Template rendering failed: {e}",
140
- validation_type="template_rendering"
141
- )
142
-
143
- # Custom filters
144
- def _snake_case(self, text: str) -> str:
145
- """Convert text to snake_case."""
146
- # Handle camelCase and PascalCase
147
- s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', text)
148
- s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1)
149
- return s2.lower().replace(' ', '_').replace('-', '_')
150
-
151
- def _camel_case(self, text: str) -> str:
152
- """Convert text to camelCase."""
153
- components = re.split(r'[_\s-]+', text.lower())
154
- return components[0] + ''.join(word.capitalize() for word in components[1:])
155
-
156
- def _pascal_case(self, text: str) -> str:
157
- """Convert text to PascalCase."""
158
- components = re.split(r'[_\s-]+', text.lower())
159
- return ''.join(word.capitalize() for word in components)
160
-
161
- def _kebab_case(self, text: str) -> str:
162
- """Convert text to kebab-case."""
163
- return self._snake_case(text).replace('_', '-')
164
-
165
- def _title_case(self, text: str) -> str:
166
- """Convert text to Title Case."""
167
- return text.replace('_', ' ').replace('-', ' ').title()
168
-
169
- def _pluralize(self, text: str) -> str:
170
- """Simple pluralization."""
171
- if text.endswith('y'):
172
- return text[:-1] + 'ies'
173
- elif text.endswith(('s', 'sh', 'ch', 'x', 'z')):
174
- return text + 'es'
175
- else:
176
- return text + 's'
177
-
178
- def _singularize(self, text: str) -> str:
179
- """Simple singularization."""
180
- if text.endswith('ies'):
181
- return text[:-3] + 'y'
182
- elif text.endswith('es'):
183
- return text[:-2]
184
- elif text.endswith('s') and not text.endswith('ss'):
185
- return text[:-1]
186
- else:
187
- return text
188
-
189
- def _django_field_repr(self, field_type: str, **kwargs) -> str:
190
- """Generate Django field representation."""
191
- args = []
192
- for key, value in kwargs.items():
193
- if isinstance(value, str):
194
- args.append(f"{key}='{value}'")
195
- else:
196
- args.append(f"{key}={value}")
197
-
198
- if args:
199
- return f"models.{field_type}({', '.join(args)})"
200
- else:
201
- return f"models.{field_type}()"
202
-
203
- def _python_repr(self, value: Any) -> str:
204
- """Python representation of value."""
205
- return repr(value)
206
-
207
- def _indent(self, text: str, width: int = 4, first: bool = False) -> str:
208
- """Indent text by specified width."""
209
- lines = text.split('\n')
210
- indent_str = ' ' * width
211
-
212
- if first:
213
- return '\n'.join(indent_str + line for line in lines)
214
- else:
215
- return lines[0] + '\n' + '\n'.join(indent_str + line for line in lines[1:])
216
-
217
- def _comment_block(self, text: str, style: str = 'python') -> str:
218
- """Create comment block in specified style."""
219
- if style == 'python':
220
- lines = text.split('\n')
221
- return '\n'.join(f'# {line}' for line in lines)
222
- elif style == 'docstring':
223
- return f'"""\n{text}\n"""'
224
- else:
225
- return text
226
-
227
- # Custom functions
228
- def _now(self) -> str:
229
- """Current timestamp."""
230
- from datetime import datetime
231
- return datetime.now().isoformat()
232
-
233
- def _uuid4(self) -> str:
234
- """Generate UUID4."""
235
- import uuid
236
- return str(uuid.uuid4())
@@ -1,159 +0,0 @@
1
- """
2
- Template Manager Service for Django App Agent Module.
3
-
4
- This service provides sophisticated Jinja2-based template rendering
5
- with feature-driven code generation capabilities.
6
- """
7
-
8
- from typing import Dict, Any, Set, Optional, List
9
- from pathlib import Path
10
-
11
- from pydantic import BaseModel, Field
12
-
13
- from ...core.config import AgentConfig
14
- from ...core.exceptions import ValidationError
15
- from ...models.enums import AppType, AppFeature
16
- from ...models.requests import TemplateRequest
17
- from ...models.responses import TemplateResult
18
- from ..base import BaseService, ServiceDependencies
19
- from .jinja_engine import JinjaTemplateEngine
20
- from .template_loader import TemplateLoader
21
- from .variable_processor import VariableProcessor
22
-
23
-
24
- class TemplateManagerService(BaseService[TemplateRequest, TemplateResult]):
25
- """
26
- Advanced template management service with Jinja2 support.
27
-
28
- Features:
29
- - Jinja2 template engine with custom filters
30
- - File-based template loading
31
- - Feature-driven template selection
32
- - Variable processing and validation
33
- - Template caching and optimization
34
- """
35
-
36
- def __init__(self, config: AgentConfig):
37
- """Initialize template manager service."""
38
- super().__init__("template_manager", config)
39
- self.config = config
40
-
41
- # Initialize components
42
- self.template_loader = TemplateLoader()
43
- self.jinja_engine = JinjaTemplateEngine()
44
- self.variable_processor = VariableProcessor()
45
-
46
- # Load all templates into engine
47
- self._load_templates()
48
-
49
- async def process(
50
- self,
51
- request: TemplateRequest,
52
- dependencies: ServiceDependencies
53
- ) -> TemplateResult:
54
- """
55
- Process template rendering request.
56
-
57
- Args:
58
- request: Template processing request
59
- dependencies: Service dependencies
60
-
61
- Returns:
62
- TemplateResult with rendered content
63
- """
64
- dependencies.log_operation(
65
- f"Processing template '{request.template_name}'",
66
- app_type=request.app_type if isinstance(request.app_type, str) else request.app_type.value,
67
- features_count=len(request.features),
68
- variables_count=len(request.variables)
69
- )
70
-
71
- try:
72
- # Determine template name
73
- template_name = self._resolve_template_name(request, dependencies)
74
-
75
- # Process variables
76
- processed_variables = await self.variable_processor.process_variables(
77
- request, dependencies
78
- )
79
-
80
- # Render template
81
- rendered_content, variables_used, missing_vars = self.jinja_engine.render(
82
- template_name, processed_variables
83
- )
84
-
85
- # Create result
86
- result = TemplateResult(
87
- rendered_content=rendered_content,
88
- template_name=template_name,
89
- variables_used=list(variables_used),
90
- missing_variables=list(missing_vars),
91
- template_metadata={
92
- "app_type": request.app_type if isinstance(request.app_type, str) else request.app_type.value,
93
- "features": [(f.value if hasattr(f, 'value') else f) for f in request.features],
94
- "template_engine": "jinja2",
95
- "rendered_size": len(rendered_content),
96
- "variables_processed": len(processed_variables)
97
- }
98
- )
99
-
100
- dependencies.log_operation(
101
- "Template processing completed successfully",
102
- template_name=template_name,
103
- rendered_size=len(rendered_content),
104
- variables_used=len(variables_used),
105
- missing_variables=len(missing_vars)
106
- )
107
-
108
- return result
109
-
110
- except Exception as e:
111
- dependencies.log_error("Template processing failed", e)
112
- raise
113
-
114
- def _load_templates(self) -> None:
115
- """Load all templates into the Jinja2 engine."""
116
- templates = self.template_loader.load_all_templates()
117
- self.jinja_engine.add_templates(templates)
118
-
119
- def _resolve_template_name(
120
- self,
121
- request: TemplateRequest,
122
- dependencies: ServiceDependencies
123
- ) -> str:
124
- """Resolve the actual template name to use."""
125
- template_name = request.template_name
126
-
127
- # If template_name doesn't end with .j2, add it
128
- if not template_name.endswith('.j2'):
129
- template_name = f"{template_name}.j2"
130
-
131
- # Check if template exists
132
- available_templates = self.template_loader.get_available_templates()
133
-
134
- if template_name not in available_templates:
135
- # Try app-type specific template
136
- app_type_str = request.app_type if isinstance(request.app_type, str) else request.app_type.value
137
- app_specific_name = f"{app_type_str}_{template_name}"
138
- if app_specific_name in available_templates:
139
- template_name = app_specific_name
140
- else:
141
- raise ValidationError(
142
- f"Template '{template_name}' not found. Available templates: {available_templates}",
143
- validation_type="template_not_found"
144
- )
145
-
146
- return template_name
147
-
148
- def reload_templates(self) -> None:
149
- """Reload all templates from disk."""
150
- self.template_loader.clear_cache()
151
- self._load_templates()
152
-
153
- def get_available_templates(self) -> List[str]:
154
- """Get list of available template names."""
155
- return self.template_loader.get_available_templates()
156
-
157
- def add_custom_template(self, name: str, content: str) -> None:
158
- """Add a custom template at runtime."""
159
- self.jinja_engine.add_template(name, content)
@@ -1,36 +0,0 @@
1
- """
2
- Data Models for Template Manager Service.
3
-
4
- This module contains Pydantic models for template processing
5
- requests, results, and related data structures.
6
- """
7
-
8
- from typing import Dict, Any, Optional, List, Set
9
-
10
- from pydantic import BaseModel, Field, ConfigDict
11
-
12
- from ...models.enums import AppType, AppFeature
13
-
14
-
15
- class TemplateRequest(BaseModel):
16
- """Request for template processing."""
17
-
18
- model_config = ConfigDict(extra='forbid', validate_assignment=True)
19
-
20
- template_name: str = Field(description="Name of the template to process")
21
- app_type: AppType = Field(description="Type of application")
22
- variables: Dict[str, Any] = Field(default_factory=dict, description="Template variables")
23
- features: List[AppFeature] = Field(default_factory=list, description="Requested features")
24
- custom_templates: Dict[str, str] = Field(default_factory=dict, description="Custom template overrides")
25
-
26
-
27
- class TemplateResult(BaseModel):
28
- """Result of template processing."""
29
-
30
- model_config = ConfigDict(extra='forbid', validate_assignment=True)
31
-
32
- rendered_content: str = Field(description="Rendered template content")
33
- template_name: str = Field(description="Name of the processed template")
34
- variables_used: Set[str] = Field(default_factory=set, description="Variables that were used in rendering")
35
- missing_variables: Set[str] = Field(default_factory=set, description="Variables that were missing")
36
- template_metadata: Dict[str, Any] = Field(default_factory=dict, description="Template processing metadata")
@@ -1,100 +0,0 @@
1
- """
2
- Template Loader for Django App Agent.
3
-
4
- This module handles loading Jinja2 templates from files and
5
- providing them to the template engine.
6
- """
7
-
8
- from typing import Dict, Optional
9
- from pathlib import Path
10
-
11
- from pydantic import BaseModel, Field
12
-
13
- from ...core.exceptions import ValidationError
14
-
15
-
16
- class TemplateLoader(BaseModel):
17
- """Loads Jinja2 templates from the templates directory."""
18
-
19
- templates_dir: Path = Field(description="Directory containing template files")
20
- template_cache: Dict[str, str] = Field(default_factory=dict, description="Template cache")
21
-
22
- def __init__(self, **data):
23
- """Initialize template loader."""
24
- if 'templates_dir' not in data:
25
- # Default to templates directory relative to this file
26
- current_dir = Path(__file__).parent
27
- data['templates_dir'] = current_dir / "templates"
28
-
29
- super().__init__(**data)
30
-
31
- # Validate templates directory exists
32
- if not self.templates_dir.exists():
33
- raise ValidationError(
34
- f"Templates directory does not exist: {self.templates_dir}",
35
- validation_type="template_directory"
36
- )
37
-
38
- def load_template(self, template_name: str) -> str:
39
- """Load a template by name."""
40
- # Check cache first
41
- if template_name in self.template_cache:
42
- return self.template_cache[template_name]
43
-
44
- # Try to load from file
45
- template_path = self.templates_dir / template_name
46
-
47
- if not template_path.exists():
48
- # Try with .j2 extension if not provided
49
- if not template_name.endswith('.j2'):
50
- template_path = self.templates_dir / f"{template_name}.j2"
51
-
52
- if not template_path.exists():
53
- raise ValidationError(
54
- f"Template file not found: {template_name}",
55
- validation_type="template_not_found"
56
- )
57
-
58
- try:
59
- content = template_path.read_text(encoding='utf-8')
60
- # Cache the template
61
- self.template_cache[template_name] = content
62
- return content
63
-
64
- except Exception as e:
65
- raise ValidationError(
66
- f"Failed to read template file {template_name}: {e}",
67
- validation_type="template_read_error"
68
- )
69
-
70
- def load_all_templates(self) -> Dict[str, str]:
71
- """Load all templates from the templates directory."""
72
- templates = {}
73
-
74
- for template_path in self.templates_dir.glob("*.j2"):
75
- template_name = template_path.name
76
- try:
77
- content = self.load_template(template_name)
78
- templates[template_name] = content
79
- except ValidationError:
80
- # Skip templates that can't be loaded
81
- continue
82
-
83
- return templates
84
-
85
- def get_available_templates(self) -> list[str]:
86
- """Get list of available template names."""
87
- return [p.name for p in self.templates_dir.glob("*.j2")]
88
-
89
- def clear_cache(self) -> None:
90
- """Clear the template cache."""
91
- self.template_cache.clear()
92
-
93
- def reload_template(self, template_name: str) -> str:
94
- """Reload a template, bypassing cache."""
95
- # Remove from cache if present
96
- if template_name in self.template_cache:
97
- del self.template_cache[template_name]
98
-
99
- # Load fresh copy
100
- return self.load_template(template_name)
@@ -1,105 +0,0 @@
1
- """
2
- Admin configuration for {{ app_name }} application.
3
-
4
- {{ description }}
5
- """
6
-
7
- from django.contrib import admin
8
- {% if features.advanced_admin %}
9
- from django.utils.html import format_html
10
- from django.urls import reverse
11
- from django.utils.safestring import mark_safe
12
- {% endif %}
13
- from .models import {{ app_name|pascal_case }}Model
14
- {% if features.related_models %}
15
- from .models import {{ app_name|pascal_case }}Category, {{ app_name|pascal_case }}Tag
16
- {% endif %}
17
-
18
-
19
- @admin.register({{ app_name|pascal_case }}Model)
20
- class {{ app_name|pascal_case }}Admin(admin.ModelAdmin):
21
- """Admin interface for {{ app_name }} model."""
22
-
23
- list_display = [
24
- 'name',
25
- {% if features.status_tracking %}'status', {% endif %}
26
- {% if features.user_relations %}'owner', {% endif %}
27
- 'created_at',
28
- 'updated_at'
29
- ]
30
-
31
- list_filter = [
32
- {% if features.status_tracking %}'status', {% endif %}
33
- 'created_at',
34
- {% if features.user_relations %}'owner', {% endif %}
35
- ]
36
-
37
- search_fields = ['name', 'description']
38
-
39
- {% if features.status_tracking %}
40
- list_editable = ['status']
41
- {% endif %}
42
-
43
- readonly_fields = ['created_at', 'updated_at']
44
-
45
- {% if features.advanced_admin %}
46
- fieldsets = (
47
- ('Basic Information', {
48
- 'fields': ('name', 'description')
49
- }),
50
- {% if features.status_tracking %}
51
- ('Status', {
52
- 'fields': ('status',)
53
- }),
54
- {% endif %}
55
- {% if features.user_relations %}
56
- ('Ownership', {
57
- 'fields': ('owner',)
58
- }),
59
- {% endif %}
60
- ('Timestamps', {
61
- 'fields': ('created_at', 'updated_at'),
62
- 'classes': ('collapse',)
63
- }),
64
- )
65
- {% endif %}
66
-
67
- {% if features.user_relations %}
68
- def save_model(self, request, obj, form, change):
69
- if not change: # Creating new object
70
- obj.owner = request.user
71
- super().save_model(request, obj, form, change)
72
-
73
- def get_queryset(self, request):
74
- qs = super().get_queryset(request)
75
- if request.user.is_superuser:
76
- return qs
77
- return qs.filter(owner=request.user)
78
- {% endif %}
79
-
80
- {% if features.advanced_admin %}
81
- def get_readonly_fields(self, request, obj=None):
82
- if obj: # Editing existing object
83
- return self.readonly_fields + ['name']
84
- return self.readonly_fields
85
- {% endif %}
86
-
87
-
88
- {% if features.related_models %}
89
- @admin.register({{ app_name|pascal_case }}Category)
90
- class {{ app_name|pascal_case }}CategoryAdmin(admin.ModelAdmin):
91
- """Admin interface for {{ app_name }} categories."""
92
-
93
- list_display = ['name', 'slug', 'description']
94
- search_fields = ['name', 'description']
95
- prepopulated_fields = {'slug': ('name',)}
96
-
97
-
98
- @admin.register({{ app_name|pascal_case }}Tag)
99
- class {{ app_name|pascal_case }}TagAdmin(admin.ModelAdmin):
100
- """Admin interface for {{ app_name }} tags."""
101
-
102
- list_display = ['name', 'color']
103
- search_fields = ['name']
104
- list_editable = ['color']
105
- {% endif %}
@@ -1,31 +0,0 @@
1
- """
2
- App configuration for {{ app_name }}.
3
-
4
- {{ description }}
5
- """
6
-
7
- from django.apps import AppConfig
8
- {% if app_type == 'django_cfg' %}
9
- from django_cfg.apps import BaseCfgAppConfig
10
- {% endif %}
11
-
12
-
13
- {% if app_type == 'django_cfg' %}
14
- class {{ app_name|pascal_case }}Config(BaseCfgAppConfig):
15
- {% else %}
16
- class {{ app_name|pascal_case }}Config(AppConfig):
17
- {% endif %}
18
- """Configuration for {{ app_name }} application."""
19
-
20
- default_auto_field = 'django.db.models.BigAutoField'
21
- name = '{{ app_name }}'
22
- verbose_name = '{{ app_name|title_case }}'
23
-
24
- {% if features.signals %}
25
- def ready(self):
26
- """Import signals when app is ready."""
27
- try:
28
- import {{ app_name }}.signals # noqa F401
29
- except ImportError:
30
- pass
31
- {% endif %}