createsonline 0.1.26__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 (152) hide show
  1. createsonline/__init__.py +46 -0
  2. createsonline/admin/__init__.py +7 -0
  3. createsonline/admin/content.py +526 -0
  4. createsonline/admin/crud.py +805 -0
  5. createsonline/admin/field_builder.py +559 -0
  6. createsonline/admin/integration.py +482 -0
  7. createsonline/admin/interface.py +2562 -0
  8. createsonline/admin/model_creator.py +513 -0
  9. createsonline/admin/model_manager.py +388 -0
  10. createsonline/admin/modern_dashboard.py +498 -0
  11. createsonline/admin/permissions.py +264 -0
  12. createsonline/admin/user_forms.py +594 -0
  13. createsonline/ai/__init__.py +202 -0
  14. createsonline/ai/fields.py +1226 -0
  15. createsonline/ai/orm.py +325 -0
  16. createsonline/ai/services.py +1244 -0
  17. createsonline/app.py +506 -0
  18. createsonline/auth/__init__.py +8 -0
  19. createsonline/auth/management.py +228 -0
  20. createsonline/auth/models.py +552 -0
  21. createsonline/cli/__init__.py +5 -0
  22. createsonline/cli/commands/__init__.py +122 -0
  23. createsonline/cli/commands/database.py +416 -0
  24. createsonline/cli/commands/info.py +173 -0
  25. createsonline/cli/commands/initdb.py +218 -0
  26. createsonline/cli/commands/project.py +545 -0
  27. createsonline/cli/commands/serve.py +173 -0
  28. createsonline/cli/commands/shell.py +93 -0
  29. createsonline/cli/commands/users.py +148 -0
  30. createsonline/cli/main.py +2041 -0
  31. createsonline/cli/manage.py +274 -0
  32. createsonline/config/__init__.py +9 -0
  33. createsonline/config/app.py +2577 -0
  34. createsonline/config/database.py +179 -0
  35. createsonline/config/docs.py +384 -0
  36. createsonline/config/errors.py +160 -0
  37. createsonline/config/orm.py +43 -0
  38. createsonline/config/request.py +93 -0
  39. createsonline/config/settings.py +176 -0
  40. createsonline/data/__init__.py +23 -0
  41. createsonline/data/dataframe.py +925 -0
  42. createsonline/data/io.py +453 -0
  43. createsonline/data/series.py +557 -0
  44. createsonline/database/__init__.py +60 -0
  45. createsonline/database/abstraction.py +440 -0
  46. createsonline/database/assistant.py +585 -0
  47. createsonline/database/fields.py +442 -0
  48. createsonline/database/migrations.py +132 -0
  49. createsonline/database/models.py +604 -0
  50. createsonline/database.py +438 -0
  51. createsonline/http/__init__.py +28 -0
  52. createsonline/http/client.py +535 -0
  53. createsonline/ml/__init__.py +55 -0
  54. createsonline/ml/classification.py +552 -0
  55. createsonline/ml/clustering.py +680 -0
  56. createsonline/ml/metrics.py +542 -0
  57. createsonline/ml/neural.py +560 -0
  58. createsonline/ml/preprocessing.py +784 -0
  59. createsonline/ml/regression.py +501 -0
  60. createsonline/performance/__init__.py +19 -0
  61. createsonline/performance/cache.py +444 -0
  62. createsonline/performance/compression.py +335 -0
  63. createsonline/performance/core.py +419 -0
  64. createsonline/project_init.py +789 -0
  65. createsonline/routing.py +528 -0
  66. createsonline/security/__init__.py +34 -0
  67. createsonline/security/core.py +811 -0
  68. createsonline/security/encryption.py +349 -0
  69. createsonline/server.py +295 -0
  70. createsonline/static/css/admin.css +263 -0
  71. createsonline/static/css/common.css +358 -0
  72. createsonline/static/css/dashboard.css +89 -0
  73. createsonline/static/favicon.ico +0 -0
  74. createsonline/static/icons/icon-128x128.png +0 -0
  75. createsonline/static/icons/icon-128x128.webp +0 -0
  76. createsonline/static/icons/icon-16x16.png +0 -0
  77. createsonline/static/icons/icon-16x16.webp +0 -0
  78. createsonline/static/icons/icon-180x180.png +0 -0
  79. createsonline/static/icons/icon-180x180.webp +0 -0
  80. createsonline/static/icons/icon-192x192.png +0 -0
  81. createsonline/static/icons/icon-192x192.webp +0 -0
  82. createsonline/static/icons/icon-256x256.png +0 -0
  83. createsonline/static/icons/icon-256x256.webp +0 -0
  84. createsonline/static/icons/icon-32x32.png +0 -0
  85. createsonline/static/icons/icon-32x32.webp +0 -0
  86. createsonline/static/icons/icon-384x384.png +0 -0
  87. createsonline/static/icons/icon-384x384.webp +0 -0
  88. createsonline/static/icons/icon-48x48.png +0 -0
  89. createsonline/static/icons/icon-48x48.webp +0 -0
  90. createsonline/static/icons/icon-512x512.png +0 -0
  91. createsonline/static/icons/icon-512x512.webp +0 -0
  92. createsonline/static/icons/icon-64x64.png +0 -0
  93. createsonline/static/icons/icon-64x64.webp +0 -0
  94. createsonline/static/image/android-chrome-192x192.png +0 -0
  95. createsonline/static/image/android-chrome-512x512.png +0 -0
  96. createsonline/static/image/apple-touch-icon.png +0 -0
  97. createsonline/static/image/favicon-16x16.png +0 -0
  98. createsonline/static/image/favicon-32x32.png +0 -0
  99. createsonline/static/image/favicon.ico +0 -0
  100. createsonline/static/image/favicon.svg +17 -0
  101. createsonline/static/image/icon-128x128.png +0 -0
  102. createsonline/static/image/icon-128x128.webp +0 -0
  103. createsonline/static/image/icon-16x16.png +0 -0
  104. createsonline/static/image/icon-16x16.webp +0 -0
  105. createsonline/static/image/icon-180x180.png +0 -0
  106. createsonline/static/image/icon-180x180.webp +0 -0
  107. createsonline/static/image/icon-192x192.png +0 -0
  108. createsonline/static/image/icon-192x192.webp +0 -0
  109. createsonline/static/image/icon-256x256.png +0 -0
  110. createsonline/static/image/icon-256x256.webp +0 -0
  111. createsonline/static/image/icon-32x32.png +0 -0
  112. createsonline/static/image/icon-32x32.webp +0 -0
  113. createsonline/static/image/icon-384x384.png +0 -0
  114. createsonline/static/image/icon-384x384.webp +0 -0
  115. createsonline/static/image/icon-48x48.png +0 -0
  116. createsonline/static/image/icon-48x48.webp +0 -0
  117. createsonline/static/image/icon-512x512.png +0 -0
  118. createsonline/static/image/icon-512x512.webp +0 -0
  119. createsonline/static/image/icon-64x64.png +0 -0
  120. createsonline/static/image/icon-64x64.webp +0 -0
  121. createsonline/static/image/logo-header-h100.png +0 -0
  122. createsonline/static/image/logo-header-h100.webp +0 -0
  123. createsonline/static/image/logo-header-h200@2x.png +0 -0
  124. createsonline/static/image/logo-header-h200@2x.webp +0 -0
  125. createsonline/static/image/logo.png +0 -0
  126. createsonline/static/js/admin.js +274 -0
  127. createsonline/static/site.webmanifest +35 -0
  128. createsonline/static/templates/admin/base.html +87 -0
  129. createsonline/static/templates/admin/dashboard.html +217 -0
  130. createsonline/static/templates/admin/model_form.html +270 -0
  131. createsonline/static/templates/admin/model_list.html +202 -0
  132. createsonline/static/test_script.js +15 -0
  133. createsonline/static/test_styles.css +59 -0
  134. createsonline/static_files.py +365 -0
  135. createsonline/templates/404.html +100 -0
  136. createsonline/templates/admin_login.html +169 -0
  137. createsonline/templates/base.html +102 -0
  138. createsonline/templates/index.html +151 -0
  139. createsonline/templates.py +205 -0
  140. createsonline/testing.py +322 -0
  141. createsonline/utils.py +448 -0
  142. createsonline/validation/__init__.py +49 -0
  143. createsonline/validation/fields.py +598 -0
  144. createsonline/validation/models.py +504 -0
  145. createsonline/validation/validators.py +561 -0
  146. createsonline/views.py +184 -0
  147. createsonline-0.1.26.dist-info/METADATA +46 -0
  148. createsonline-0.1.26.dist-info/RECORD +152 -0
  149. createsonline-0.1.26.dist-info/WHEEL +5 -0
  150. createsonline-0.1.26.dist-info/entry_points.txt +2 -0
  151. createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
  152. createsonline-0.1.26.dist-info/top_level.txt +1 -0
@@ -0,0 +1,789 @@
1
+ # createsonline/project_init.py
2
+ """
3
+ Automatic Project Initialization
4
+
5
+ This module automatically creates the project structure when a user
6
+ runs their application for the first time. It protects existing files
7
+ and only creates missing ones.
8
+ """
9
+
10
+ import os
11
+ from pathlib import Path
12
+ import shutil
13
+
14
+
15
+ class ProjectInitializer:
16
+ """Automatically initialize project structure without overwriting user files"""
17
+
18
+ def __init__(self, project_root: Path = None):
19
+ self.project_root = project_root or Path.cwd()
20
+ self.framework_dir = Path(__file__).parent
21
+ self.user_files_created = []
22
+ self.user_files_skipped = []
23
+ self.verbose = False # Control print statements
24
+
25
+ def initialize(self, force: bool = False, verbose: bool = False) -> dict:
26
+ """
27
+ Initialize project structure automatically.
28
+
29
+ Args:
30
+ force: If True, overwrites existing files (dangerous!)
31
+ verbose: If True, print progress messages
32
+
33
+ Returns:
34
+ dict with status of created/skipped files
35
+ """
36
+ self.verbose = verbose
37
+ if verbose:
38
+ print(f"\nInitializing CREATESONLINE project structure...")
39
+ print(f"Project root: {self.project_root}")
40
+
41
+ # Create directories
42
+ self._create_directories()
43
+
44
+ # Create/update user files (ONLY if they don't exist)
45
+ self._ensure_main_py()
46
+ self._ensure_routes_py()
47
+ self._ensure_user_config_py()
48
+ self._ensure_templates()
49
+ self._ensure_static_files()
50
+ self._ensure_documentation()
51
+
52
+ # Summary (only if verbose)
53
+ if verbose:
54
+ print(f"\nInitialization complete!")
55
+ if self.user_files_created:
56
+ print(f"Created {len(self.user_files_created)} new files:")
57
+ for f in self.user_files_created:
58
+ print(f" * {f}")
59
+ if self.user_files_skipped:
60
+ print(f"Skipped {len(self.user_files_skipped)} existing files (protected):")
61
+ for f in self.user_files_skipped:
62
+ print(f" - {f}")
63
+ print(f" ⊗ {f}")
64
+
65
+ return {
66
+ "created": self.user_files_created,
67
+ "skipped": self.user_files_skipped,
68
+ "success": True
69
+ }
70
+
71
+ def _create_directories(self):
72
+ """Create necessary directories"""
73
+ dirs = [
74
+ self.project_root / "templates",
75
+ self.project_root / "static",
76
+ self.project_root / "static" / "css",
77
+ self.project_root / "static" / "js",
78
+ self.project_root / "static" / "images",
79
+ ]
80
+
81
+ for directory in dirs:
82
+ if not directory.exists():
83
+ directory.mkdir(parents=True, exist_ok=True)
84
+ if self.verbose:
85
+ print(f" Created directory: {directory.relative_to(self.project_root)}")
86
+
87
+ def _create_file(self, filepath: Path, content: str, description: str = None):
88
+ """Create a file only if it doesn't exist"""
89
+ rel_path = filepath.relative_to(self.project_root)
90
+
91
+ if filepath.exists():
92
+ self.user_files_skipped.append(str(rel_path))
93
+ return False
94
+
95
+ filepath.parent.mkdir(parents=True, exist_ok=True)
96
+ filepath.write_text(content, encoding='utf-8')
97
+ self.user_files_created.append(str(rel_path))
98
+ if description and self.verbose:
99
+ print(f" {description}: {rel_path}")
100
+ return True
101
+
102
+ def _ensure_main_py(self):
103
+ """Create main.py if it doesn't exist"""
104
+ main_py = self.project_root / "main.py"
105
+
106
+ content = '''#!/usr/bin/env python3
107
+ """
108
+ CREATESONLINE Application Bootstrap
109
+
110
+ ⚠️ UPGRADE-SAFE FILE - Your changes persist across framework updates! ⚠️
111
+
112
+ This file is automatically generated but safe to customize.
113
+ """
114
+ from createsonline import create_app
115
+ from createsonline.project_init import auto_discover_routes
116
+
117
+ # Create application
118
+ app = create_app(
119
+ title="My CREATESONLINE App",
120
+ description="AI-Native Web Application",
121
+ version="1.0.0",
122
+ debug=True
123
+ )
124
+
125
+ # Auto-discover and register routes (silent)
126
+ auto_discover_routes(app)
127
+
128
+ if __name__ == "__main__":
129
+ from createsonline.server import run_server
130
+
131
+ # Load environment variables if available
132
+ try:
133
+ from dotenv import load_dotenv
134
+ load_dotenv()
135
+ except ImportError:
136
+ pass
137
+
138
+ import os
139
+ host = os.getenv("HOST", "0.0.0.0")
140
+ port = int(os.getenv("PORT", "8000"))
141
+
142
+ run_server(app, host=host, port=port)
143
+ '''
144
+
145
+ self._create_file(main_py, content, "Created main.py")
146
+
147
+ def _ensure_routes_py(self):
148
+ """Create routes.py if it doesn't exist"""
149
+ routes_py = self.project_root / "routes.py"
150
+
151
+ content = '''# routes.py
152
+ """
153
+ URL Configuration - YOUR CUSTOM ROUTES
154
+
155
+ ⚠️ UPGRADE-SAFE FILE - Your changes persist across framework updates! ⚠️
156
+
157
+ Define your custom URL patterns here.
158
+ """
159
+
160
+ from createsonline.routing import path
161
+ from createsonline import render_template
162
+
163
+ # ============================================================================
164
+ # YOUR CUSTOM VIEW HANDLERS
165
+ # ============================================================================
166
+
167
+ async def home(request):
168
+ """Modern homepage - uses templates/index.html"""
169
+ html = render_template("index.html")
170
+
171
+ from createsonline.server import InternalHTMLResponse
172
+ return InternalHTMLResponse(html)
173
+
174
+
175
+ async def admin_login(request):
176
+ """Admin login page - uses templates/admin_login.html"""
177
+ html = render_template("admin_login.html")
178
+
179
+ from createsonline.server import InternalHTMLResponse
180
+ return InternalHTMLResponse(html)
181
+
182
+
183
+ async def about(request):
184
+ """About page"""
185
+ return {"page": "about", "content": "About our application"}
186
+
187
+
188
+ async def not_found(request):
189
+ """Custom 404 error page - uses templates/404.html"""
190
+ html = render_template("404.html")
191
+
192
+ from createsonline.server import InternalHTMLResponse
193
+ return InternalHTMLResponse(html, status_code=404)
194
+
195
+
196
+ # ============================================================================
197
+ # URL PATTERNS - Add your routes here!
198
+ # ============================================================================
199
+
200
+ urlpatterns = [
201
+ path('/', home, name='home'),
202
+ path('/admin', admin_login, name='admin-login'),
203
+ path('/about', about, name='about'),
204
+ ]
205
+
206
+ # Add more routes below:
207
+ # path('/api/data', get_data, name='api-data'),
208
+ # path('/contact', contact_form, methods=['POST'], name='contact'),
209
+ '''
210
+
211
+ self._create_file(routes_py, content, "Created routes.py")
212
+
213
+ def _ensure_user_config_py(self):
214
+ """Create user_config.py if it doesn't exist"""
215
+ config_py = self.project_root / "user_config.py"
216
+
217
+ content = '''# user_config.py
218
+ """
219
+ User Configuration for CREATESONLINE
220
+
221
+ ⚠️ UPGRADE-SAFE FILE - Your changes persist across framework updates! ⚠️
222
+
223
+ Add your custom settings here.
224
+ """
225
+
226
+ # Application settings
227
+ DEBUG = True
228
+ SECRET_KEY = "change-this-in-production"
229
+
230
+ # Database settings (if needed)
231
+ # DATABASE_URL = "sqlite:///app.db"
232
+ # DATABASE_TIMEOUT = 30
233
+
234
+ # Custom middleware (optional)
235
+ # MIDDLEWARE = [
236
+ # 'myapp.middleware.CustomMiddleware',
237
+ # ]
238
+
239
+ # API Keys (use environment variables in production!)
240
+ # API_KEY = "your-api-key"
241
+
242
+ # Add any custom settings you need below:
243
+ '''
244
+
245
+ self._create_file(config_py, content, "Created user_config.py")
246
+
247
+ def _ensure_templates(self):
248
+ """Copy modern templates from framework if they don't exist"""
249
+ # Try to copy from framework's templates directory first
250
+ framework_templates = self.framework_dir / "templates"
251
+
252
+ template_files = ["base.html", "index.html", "admin_login.html", "404.html"]
253
+
254
+ for template_name in template_files:
255
+ source = framework_templates / template_name
256
+ dest = self.project_root / "templates" / template_name
257
+
258
+ # Skip if template already exists
259
+ if dest.exists():
260
+ self.user_files_skipped.append(f"templates/{template_name}")
261
+ continue
262
+
263
+ # Copy from framework or use fallback
264
+ if source.exists():
265
+ shutil.copy2(source, dest)
266
+ self.user_files_created.append(f"templates/{template_name}")
267
+ if self.verbose:
268
+ print(f" Created template: templates/{template_name}")
269
+ else:
270
+ # Fallback to hardcoded templates
271
+ content = self._get_fallback_template(template_name)
272
+ if content:
273
+ self._create_file(dest, content, f"Created template")
274
+
275
+ def _ensure_static_files(self):
276
+ """Copy default static files if they don't exist"""
277
+ # Copy from framework's static directory if needed
278
+ framework_static = self.framework_dir / "static"
279
+ project_static = self.project_root / "static"
280
+
281
+ # Create favicon files
282
+ self._create_favicon_files()
283
+
284
+ # Create logo image
285
+ self._create_logo_file()
286
+
287
+ # Create site.webmanifest
288
+ self._create_webmanifest()
289
+
290
+ # Create guide.html and examples.html
291
+ self._create_file(
292
+ project_static / "guide.html",
293
+ self._get_guide_html(),
294
+ "Created guide page"
295
+ )
296
+ self._create_file(
297
+ project_static / "examples.html",
298
+ self._get_examples_html(),
299
+ "Created examples page"
300
+ )
301
+
302
+ def _ensure_documentation(self):
303
+ """Create documentation files"""
304
+ self._create_file(
305
+ self.project_root / "README.md",
306
+ self._get_readme_content(),
307
+ "Created README.md"
308
+ )
309
+
310
+ def _create_favicon_files(self):
311
+ """Generate default favicon files (SVG and ICO)"""
312
+ # Create favicon.svg (modern browsers)
313
+ svg_content = '''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
314
+ <rect width="100" height="100" fill="#000000"/>
315
+ <text x="50" y="70" font-family="Arial, sans-serif" font-size="70" font-weight="bold" text-anchor="middle" fill="#ffffff">C</text>
316
+ </svg>'''
317
+ self._create_file(
318
+ self.project_root / "favicon.svg",
319
+ svg_content,
320
+ "Created favicon.svg"
321
+ )
322
+
323
+ # Create basic favicon.ico (16x16 transparent PNG in ICO format)
324
+ # Using minimal valid ICO file structure
325
+ import base64
326
+ # This is a valid 16x16 transparent favicon.ico
327
+ ico_base64 = "AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEA"
328
+
329
+ try:
330
+ ico_bytes = base64.b64decode(ico_base64)
331
+ ico_path = self.project_root / "favicon.ico"
332
+ if not ico_path.exists():
333
+ ico_path.write_bytes(ico_bytes)
334
+ self.user_files_created.append("favicon.ico")
335
+ if self.verbose:
336
+ print(f" Created favicon.ico")
337
+ except Exception as e:
338
+ if self.verbose:
339
+ print(f" Skipped favicon.ico (creation failed: {e})")
340
+
341
+ def _create_logo_file(self):
342
+ """Generate default logo SVG"""
343
+ logo_content = '''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 100">
344
+ <rect width="400" height="100" fill="transparent"/>
345
+ <text x="10" y="70" font-family="Arial, sans-serif" font-size="60" font-weight="bold" fill="#000000">CREATESONLINE</text>
346
+ </svg>'''
347
+ self._create_file(
348
+ self.project_root / "logo.png",
349
+ logo_content,
350
+ "Created logo.svg"
351
+ )
352
+
353
+ # Also create logo.png as SVG (browsers will handle it)
354
+ self._create_file(
355
+ self.project_root / "logo-header-h200@2x.png",
356
+ logo_content,
357
+ "Created logo-header"
358
+ )
359
+
360
+ def _create_webmanifest(self):
361
+ """Create site.webmanifest for PWA support"""
362
+ manifest_content = '''{
363
+ "name": "CREATESONLINE App",
364
+ "short_name": "CREATESONLINE",
365
+ "icons": [
366
+ {
367
+ "src": "/favicon.svg",
368
+ "sizes": "any",
369
+ "type": "image/svg+xml"
370
+ }
371
+ ],
372
+ "theme_color": "#000000",
373
+ "background_color": "#ffffff",
374
+ "display": "standalone"
375
+ }'''
376
+ self._create_file(
377
+ self.project_root / "site.webmanifest",
378
+ manifest_content,
379
+ "Created site.webmanifest"
380
+ )
381
+
382
+ def _get_fallback_template(self, template_name: str) -> str:
383
+ """Get fallback template content when framework templates aren't available"""
384
+ if template_name == "base.html":
385
+ return self._get_base_template()
386
+ elif template_name == "index.html":
387
+ return self._get_index_template()
388
+ elif template_name == "admin_login.html":
389
+ return self._get_admin_login_template()
390
+ elif template_name == "404.html":
391
+ return self._get_404_template()
392
+ return None
393
+
394
+ def _get_base_template(self) -> str:
395
+ return '''<!DOCTYPE html>
396
+ <html lang="en">
397
+ <head>
398
+ <meta charset="UTF-8">
399
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
400
+ <title>{% block title %}CREATESONLINE App{% endblock %}</title>
401
+ <link rel="stylesheet" href="/static/css/base.css">
402
+ {% block extra_css %}{% endblock %}
403
+ </head>
404
+ <body>
405
+ <nav>
406
+ <h1>CREATESONLINE</h1>
407
+ <ul>
408
+ <li><a href="/">Home</a></li>
409
+ <li><a href="/about">About</a></li>
410
+ </ul>
411
+ </nav>
412
+
413
+ <main>
414
+ {% block content %}{% endblock %}
415
+ </main>
416
+
417
+ <footer>
418
+ <p>Powered by CREATESONLINE</p>
419
+ </footer>
420
+
421
+ <script src="/static/js/base.js"></script>
422
+ {% block extra_js %}{% endblock %}
423
+ </body>
424
+ </html>
425
+ '''
426
+
427
+ def _get_index_template(self) -> str:
428
+ return '''{% extends "base.html" %}
429
+
430
+ {% block title %}Home - CREATESONLINE{% endblock %}
431
+
432
+ {% block content %}
433
+ <div class="container">
434
+ <h1>Welcome to CREATESONLINE</h1>
435
+ <p>Your AI-Native Web Framework is ready!</p>
436
+
437
+ <div class="features">
438
+ <div class="feature">
439
+ <h3>🚀 Zero Setup</h3>
440
+ <p>Everything works out of the box</p>
441
+ </div>
442
+ <div class="feature">
443
+ <h3>🤖 AI-First</h3>
444
+ <p>Built for intelligent applications</p>
445
+ </div>
446
+ <div class="feature">
447
+ <h3>⚡ Fast</h3>
448
+ <p>Pure Python async/await</p>
449
+ </div>
450
+ </div>
451
+ </div>
452
+ {% endblock %}
453
+ '''
454
+
455
+ def _get_admin_login_template(self) -> str:
456
+ return '''{% extends "base.html" %}
457
+
458
+ {% block title %}Admin Login - CREATESONLINE{% endblock %}
459
+
460
+ {% block content %}
461
+ <div class="login-container">
462
+ <h1>Admin Login</h1>
463
+ <p class="subtitle">Enter your credentials to access the admin panel</p>
464
+
465
+ <form method="POST" action="/admin/login">
466
+ <div class="form-group">
467
+ <label for="username">Username</label>
468
+ <input type="text" id="username" name="username" required>
469
+ </div>
470
+
471
+ <div class="form-group">
472
+ <label for="password">Password</label>
473
+ <input type="password" id="password" name="password" required>
474
+ </div>
475
+
476
+ <button type="submit">Sign In</button>
477
+ </form>
478
+
479
+ <div class="back-link">
480
+ <a href="/">Back to Home</a>
481
+ </div>
482
+ </div>
483
+ {% endblock %}
484
+ '''
485
+
486
+ def _get_404_template(self) -> str:
487
+ return '''<!DOCTYPE html>
488
+ <html lang="en">
489
+ <head>
490
+ <meta charset="UTF-8">
491
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
492
+ <title>404 - Page Not Found</title>
493
+
494
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
495
+ <link rel="icon" type="image/x-icon" href="/favicon.ico">
496
+
497
+ <style>
498
+ * { margin: 0; padding: 0; box-sizing: border-box; }
499
+ body {
500
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
501
+ background: #0a0a0a; color: #ffffff; min-height: 100vh;
502
+ display: flex; align-items: center; justify-content: center; padding: 20px;
503
+ }
504
+ .container {
505
+ max-width: 600px; width: 100%; text-align: center;
506
+ background: #1a1a1a; padding: 60px 40px; border-radius: 16px; border: 1px solid #2a2a2a;
507
+ }
508
+ .error-code {
509
+ font-size: 8em; font-weight: 700;
510
+ background: linear-gradient(135deg, #ffffff 0%, #666666 100%);
511
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
512
+ margin-bottom: 20px; line-height: 1;
513
+ }
514
+ h1 { font-size: 2em; margin-bottom: 15px; }
515
+ p { color: #999999; font-size: 1.1em; margin-bottom: 40px; line-height: 1.6; }
516
+ .btn {
517
+ display: inline-block; padding: 15px 35px; background: #ffffff;
518
+ color: #000000; text-decoration: none; border-radius: 8px;
519
+ font-weight: 600; transition: all 0.3s ease;
520
+ }
521
+ .btn:hover { background: #f0f0f0; transform: translateY(-2px); }
522
+ </style>
523
+ </head>
524
+ <body>
525
+ <div class="container">
526
+ <div class="error-code">404</div>
527
+ <h1>Page Not Found</h1>
528
+ <p>The page you're looking for doesn't exist or has been moved.</p>
529
+ <a href="/" class="btn">Go Home</a>
530
+ </div>
531
+ </body>
532
+ </html>
533
+ '''
534
+
535
+ def _get_guide_html(self) -> str:
536
+ return '''<!DOCTYPE html>
537
+ <html lang="en">
538
+ <head>
539
+ <meta charset="UTF-8">
540
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
541
+ <title>Quick Start Guide - CREATESONLINE</title>
542
+ <style>
543
+ body { font-family: system-ui; max-width: 900px; margin: 0 auto; padding: 2rem; }
544
+ h1 { color: #2563eb; }
545
+ pre { background: #1e1e1e; color: #d4d4d4; padding: 1rem; border-radius: 8px; overflow-x: auto; }
546
+ code { font-family: 'Courier New', monospace; }
547
+ </style>
548
+ </head>
549
+ <body>
550
+ <h1>Quick Start Guide</h1>
551
+ <p>Welcome to CREATESONLINE! This guide will get you started in 5 minutes.</p>
552
+
553
+ <h2>1. Installation</h2>
554
+ <pre><code>pip install createsonline</code></pre>
555
+
556
+ <h2>2. Create Your App</h2>
557
+ <p>Just run <code>python main.py</code> and everything is automatically set up!</p>
558
+
559
+ <h2>3. Add Custom Routes</h2>
560
+ <p>Edit <code>routes.py</code> to add your own routes:</p>
561
+ <pre><code>async def my_api(request):
562
+ return {"data": "Hello World"}
563
+
564
+ urlpatterns.append(path('/api/data', my_api))</code></pre>
565
+
566
+ <h2>4. Customize</h2>
567
+ <p>All your files are upgrade-safe! Edit freely:</p>
568
+ <ul>
569
+ <li><code>main.py</code> - App configuration</li>
570
+ <li><code>routes.py</code> - URL routes</li>
571
+ <li><code>user_config.py</code> - Settings</li>
572
+ <li><code>templates/</code> - HTML templates</li>
573
+ <li><code>static/</code> - CSS, JS, images</li>
574
+ </ul>
575
+
576
+ <p><a href="/">← Back to Home</a></p>
577
+ </body>
578
+ </html>
579
+ '''
580
+
581
+ def _get_examples_html(self) -> str:
582
+ return '''<!DOCTYPE html>
583
+ <html lang="en">
584
+ <head>
585
+ <meta charset="UTF-8">
586
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
587
+ <title>Code Examples - CREATESONLINE</title>
588
+ <style>
589
+ body { font-family: system-ui; max-width: 1000px; margin: 0 auto; padding: 2rem; }
590
+ h1 { color: #2563eb; }
591
+ .example { background: #f8f9fa; padding: 1.5rem; margin: 1rem 0; border-radius: 8px; }
592
+ pre { background: #1e1e1e; color: #d4d4d4; padding: 1rem; border-radius: 8px; overflow-x: auto; }
593
+ code { font-family: 'Courier New', monospace; }
594
+ </style>
595
+ </head>
596
+ <body>
597
+ <h1>Code Examples</h1>
598
+
599
+ <div class="example">
600
+ <h3>1. Simple API Endpoint</h3>
601
+ <pre><code>async def get_users(request):
602
+ return {"users": ["Alice", "Bob", "Charlie"]}
603
+
604
+ urlpatterns.append(path('/api/users', get_users))</code></pre>
605
+ </div>
606
+
607
+ <div class="example">
608
+ <h3>2. POST Request Handler</h3>
609
+ <pre><code>async def create_user(request):
610
+ data = await request.json()
611
+ return {"created": data, "id": 123}
612
+
613
+ urlpatterns.append(
614
+ path('/api/users', create_user, methods=['POST'])
615
+ )</code></pre>
616
+ </div>
617
+
618
+ <div class="example">
619
+ <h3>3. Serve HTML Template</h3>
620
+ <pre><code>async def about_page(request):
621
+ # Return HTML template
622
+ return render_template('about.html')
623
+
624
+ urlpatterns.append(path('/about', about_page))</code></pre>
625
+ </div>
626
+
627
+ <p><a href="/">← Back to Home</a></p>
628
+ </body>
629
+ </html>
630
+ '''
631
+
632
+ def _get_readme_content(self) -> str:
633
+ return '''# My CREATESONLINE Application
634
+
635
+ > **⚠️ UPGRADE-SAFE PROJECT** - All customizations are preserved during framework upgrades!
636
+
637
+ ## Quick Start
638
+
639
+ ```bash
640
+ # Install
641
+ pip install createsonline
642
+
643
+ # Run
644
+ python main.py
645
+
646
+ # Visit
647
+ http://localhost:8000
648
+ ```
649
+
650
+ ## Project Structure
651
+
652
+ ```
653
+ your-project/
654
+ ├── main.py ✅ Your app bootstrap (SAFE TO EDIT)
655
+ ├── routes.py ✅ Your URL routes (SAFE TO EDIT)
656
+ ├── user_config.py ✅ Your settings (SAFE TO EDIT)
657
+ ├── templates/ ✅ Your HTML templates (SAFE TO EDIT)
658
+ └── static/ ✅ Your CSS/JS/images (SAFE TO EDIT)
659
+ ```
660
+
661
+ ## Add Custom Routes
662
+
663
+ Edit `routes.py`:
664
+
665
+ ```python
666
+ async def my_view(request):
667
+ return {"message": "Hello!"}
668
+
669
+ urlpatterns.append(path('/custom', my_view))
670
+ ```
671
+
672
+ ## Upgrade Framework
673
+
674
+ ```bash
675
+ pip install --upgrade createsonline
676
+ # Your files are automatically preserved! ✨
677
+ ```
678
+
679
+ ## Documentation
680
+
681
+ - Quick Start: `/static/guide.html`
682
+ - Examples: `/static/examples.html`
683
+ - GitHub: https://github.com/meahmedh/createsonline
684
+ '''
685
+
686
+
687
+ def auto_discover_routes(app):
688
+ """
689
+ Automatically discover and register routes from routes.py
690
+
691
+ This function is called by main.py to register all user routes.
692
+ Routes from routes.py OVERRIDE any routes defined elsewhere.
693
+ It protects against errors - silent by default.
694
+ """
695
+ import logging
696
+ logger = logging.getLogger("createsonline")
697
+
698
+ try:
699
+ from routes import urlpatterns
700
+
701
+ registered = 0
702
+ for route in urlpatterns:
703
+ for method in route.methods:
704
+ decorator = getattr(app, method.lower())
705
+ handler = route.handler
706
+
707
+ # Handle class-based views
708
+ if hasattr(handler, 'dispatch'):
709
+ instance = handler() if callable(handler) else handler
710
+ async def view_wrapper(request, instance=instance):
711
+ return await instance.dispatch(request)
712
+ # Force override - routes.py takes priority
713
+ route_key = f"{method}:{route.path}"
714
+ if route_key in app.routes:
715
+ logger.debug(f"Overriding route: {route_key}")
716
+ decorator(route.path)(view_wrapper)
717
+ else:
718
+ # Force override - routes.py takes priority
719
+ route_key = f"{method}:{route.path}"
720
+ if route_key in app.routes:
721
+ logger.debug(f"Overriding route: {route_key}")
722
+ decorator(route.path)(handler)
723
+
724
+ registered += 1
725
+
726
+ # Register custom 404 handler if exists
727
+ try:
728
+ from routes import not_found
729
+ app.routes['not_found'] = not_found
730
+ except ImportError:
731
+ pass
732
+
733
+ # Silent success - routes registered
734
+ logger.debug(f"Auto-discovered {registered} routes from routes.py")
735
+ return True
736
+
737
+ except ImportError:
738
+ # No routes.py found - silent, use defaults
739
+ return False
740
+ except Exception as e:
741
+ # Error loading routes - log but don't crash
742
+ logger.warning(f"Error loading routes: {e}")
743
+ return False
744
+
745
+
746
+ def init_project_if_needed(project_root: Path = None, verbose: bool = False):
747
+ """
748
+ Initialize project structure if needed.
749
+ Called automatically when the app starts.
750
+ Silent by default - only shows messages if verbose=True.
751
+
752
+ Args:
753
+ project_root: Root directory for the project (default: current directory)
754
+ verbose: If True, print progress messages
755
+ """
756
+ project_root = project_root or Path.cwd()
757
+
758
+ # Check if project is already initialized
759
+ main_py = project_root / "main.py"
760
+ routes_py = project_root / "routes.py"
761
+
762
+ # Always create missing static assets (favicon, logo, manifest)
763
+ initializer = ProjectInitializer(project_root)
764
+ initializer.verbose = verbose
765
+ initializer._create_directories()
766
+ initializer._ensure_static_files()
767
+
768
+ # Always ensure routes.py exists (even if main.py exists from old version)
769
+ if not routes_py.exists():
770
+ initializer._ensure_routes_py()
771
+
772
+ # If neither main.py nor routes.py exists, this is a new project
773
+ if not main_py.exists():
774
+ if verbose:
775
+ print("\nWelcome to CREATESONLINE!")
776
+ print("Setting up your project structure...")
777
+
778
+ result = initializer.initialize(verbose=verbose)
779
+
780
+ if verbose:
781
+ print("\nNext steps:")
782
+ print(" 1. Edit routes.py to add your custom routes")
783
+ print(" 2. Customize templates/ and static/ folders")
784
+ print(" 3. Run: python main.py")
785
+ print("\nHappy coding!\n")
786
+
787
+ return result
788
+
789
+ return {"success": True, "already_initialized": True}