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.
- createsonline/__init__.py +46 -0
- createsonline/admin/__init__.py +7 -0
- createsonline/admin/content.py +526 -0
- createsonline/admin/crud.py +805 -0
- createsonline/admin/field_builder.py +559 -0
- createsonline/admin/integration.py +482 -0
- createsonline/admin/interface.py +2562 -0
- createsonline/admin/model_creator.py +513 -0
- createsonline/admin/model_manager.py +388 -0
- createsonline/admin/modern_dashboard.py +498 -0
- createsonline/admin/permissions.py +264 -0
- createsonline/admin/user_forms.py +594 -0
- createsonline/ai/__init__.py +202 -0
- createsonline/ai/fields.py +1226 -0
- createsonline/ai/orm.py +325 -0
- createsonline/ai/services.py +1244 -0
- createsonline/app.py +506 -0
- createsonline/auth/__init__.py +8 -0
- createsonline/auth/management.py +228 -0
- createsonline/auth/models.py +552 -0
- createsonline/cli/__init__.py +5 -0
- createsonline/cli/commands/__init__.py +122 -0
- createsonline/cli/commands/database.py +416 -0
- createsonline/cli/commands/info.py +173 -0
- createsonline/cli/commands/initdb.py +218 -0
- createsonline/cli/commands/project.py +545 -0
- createsonline/cli/commands/serve.py +173 -0
- createsonline/cli/commands/shell.py +93 -0
- createsonline/cli/commands/users.py +148 -0
- createsonline/cli/main.py +2041 -0
- createsonline/cli/manage.py +274 -0
- createsonline/config/__init__.py +9 -0
- createsonline/config/app.py +2577 -0
- createsonline/config/database.py +179 -0
- createsonline/config/docs.py +384 -0
- createsonline/config/errors.py +160 -0
- createsonline/config/orm.py +43 -0
- createsonline/config/request.py +93 -0
- createsonline/config/settings.py +176 -0
- createsonline/data/__init__.py +23 -0
- createsonline/data/dataframe.py +925 -0
- createsonline/data/io.py +453 -0
- createsonline/data/series.py +557 -0
- createsonline/database/__init__.py +60 -0
- createsonline/database/abstraction.py +440 -0
- createsonline/database/assistant.py +585 -0
- createsonline/database/fields.py +442 -0
- createsonline/database/migrations.py +132 -0
- createsonline/database/models.py +604 -0
- createsonline/database.py +438 -0
- createsonline/http/__init__.py +28 -0
- createsonline/http/client.py +535 -0
- createsonline/ml/__init__.py +55 -0
- createsonline/ml/classification.py +552 -0
- createsonline/ml/clustering.py +680 -0
- createsonline/ml/metrics.py +542 -0
- createsonline/ml/neural.py +560 -0
- createsonline/ml/preprocessing.py +784 -0
- createsonline/ml/regression.py +501 -0
- createsonline/performance/__init__.py +19 -0
- createsonline/performance/cache.py +444 -0
- createsonline/performance/compression.py +335 -0
- createsonline/performance/core.py +419 -0
- createsonline/project_init.py +789 -0
- createsonline/routing.py +528 -0
- createsonline/security/__init__.py +34 -0
- createsonline/security/core.py +811 -0
- createsonline/security/encryption.py +349 -0
- createsonline/server.py +295 -0
- createsonline/static/css/admin.css +263 -0
- createsonline/static/css/common.css +358 -0
- createsonline/static/css/dashboard.css +89 -0
- createsonline/static/favicon.ico +0 -0
- createsonline/static/icons/icon-128x128.png +0 -0
- createsonline/static/icons/icon-128x128.webp +0 -0
- createsonline/static/icons/icon-16x16.png +0 -0
- createsonline/static/icons/icon-16x16.webp +0 -0
- createsonline/static/icons/icon-180x180.png +0 -0
- createsonline/static/icons/icon-180x180.webp +0 -0
- createsonline/static/icons/icon-192x192.png +0 -0
- createsonline/static/icons/icon-192x192.webp +0 -0
- createsonline/static/icons/icon-256x256.png +0 -0
- createsonline/static/icons/icon-256x256.webp +0 -0
- createsonline/static/icons/icon-32x32.png +0 -0
- createsonline/static/icons/icon-32x32.webp +0 -0
- createsonline/static/icons/icon-384x384.png +0 -0
- createsonline/static/icons/icon-384x384.webp +0 -0
- createsonline/static/icons/icon-48x48.png +0 -0
- createsonline/static/icons/icon-48x48.webp +0 -0
- createsonline/static/icons/icon-512x512.png +0 -0
- createsonline/static/icons/icon-512x512.webp +0 -0
- createsonline/static/icons/icon-64x64.png +0 -0
- createsonline/static/icons/icon-64x64.webp +0 -0
- createsonline/static/image/android-chrome-192x192.png +0 -0
- createsonline/static/image/android-chrome-512x512.png +0 -0
- createsonline/static/image/apple-touch-icon.png +0 -0
- createsonline/static/image/favicon-16x16.png +0 -0
- createsonline/static/image/favicon-32x32.png +0 -0
- createsonline/static/image/favicon.ico +0 -0
- createsonline/static/image/favicon.svg +17 -0
- createsonline/static/image/icon-128x128.png +0 -0
- createsonline/static/image/icon-128x128.webp +0 -0
- createsonline/static/image/icon-16x16.png +0 -0
- createsonline/static/image/icon-16x16.webp +0 -0
- createsonline/static/image/icon-180x180.png +0 -0
- createsonline/static/image/icon-180x180.webp +0 -0
- createsonline/static/image/icon-192x192.png +0 -0
- createsonline/static/image/icon-192x192.webp +0 -0
- createsonline/static/image/icon-256x256.png +0 -0
- createsonline/static/image/icon-256x256.webp +0 -0
- createsonline/static/image/icon-32x32.png +0 -0
- createsonline/static/image/icon-32x32.webp +0 -0
- createsonline/static/image/icon-384x384.png +0 -0
- createsonline/static/image/icon-384x384.webp +0 -0
- createsonline/static/image/icon-48x48.png +0 -0
- createsonline/static/image/icon-48x48.webp +0 -0
- createsonline/static/image/icon-512x512.png +0 -0
- createsonline/static/image/icon-512x512.webp +0 -0
- createsonline/static/image/icon-64x64.png +0 -0
- createsonline/static/image/icon-64x64.webp +0 -0
- createsonline/static/image/logo-header-h100.png +0 -0
- createsonline/static/image/logo-header-h100.webp +0 -0
- createsonline/static/image/logo-header-h200@2x.png +0 -0
- createsonline/static/image/logo-header-h200@2x.webp +0 -0
- createsonline/static/image/logo.png +0 -0
- createsonline/static/js/admin.js +274 -0
- createsonline/static/site.webmanifest +35 -0
- createsonline/static/templates/admin/base.html +87 -0
- createsonline/static/templates/admin/dashboard.html +217 -0
- createsonline/static/templates/admin/model_form.html +270 -0
- createsonline/static/templates/admin/model_list.html +202 -0
- createsonline/static/test_script.js +15 -0
- createsonline/static/test_styles.css +59 -0
- createsonline/static_files.py +365 -0
- createsonline/templates/404.html +100 -0
- createsonline/templates/admin_login.html +169 -0
- createsonline/templates/base.html +102 -0
- createsonline/templates/index.html +151 -0
- createsonline/templates.py +205 -0
- createsonline/testing.py +322 -0
- createsonline/utils.py +448 -0
- createsonline/validation/__init__.py +49 -0
- createsonline/validation/fields.py +598 -0
- createsonline/validation/models.py +504 -0
- createsonline/validation/validators.py +561 -0
- createsonline/views.py +184 -0
- createsonline-0.1.26.dist-info/METADATA +46 -0
- createsonline-0.1.26.dist-info/RECORD +152 -0
- createsonline-0.1.26.dist-info/WHEEL +5 -0
- createsonline-0.1.26.dist-info/entry_points.txt +2 -0
- createsonline-0.1.26.dist-info/licenses/LICENSE +21 -0
- createsonline-0.1.26.dist-info/top_level.txt +1 -0
createsonline/routing.py
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# createsonline/routing.py
|
|
2
|
+
"""
|
|
3
|
+
CREATESONLINE Unique Routing System
|
|
4
|
+
|
|
5
|
+
A completely different approach to routing.
|
|
6
|
+
Uses a declarative, intelligence-based routing system.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Dict, Any, List, Callable
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
|
|
14
|
+
# Setup logging
|
|
15
|
+
logger = logging.getLogger("createsonline.routing")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CreatesonlineRoute:
|
|
19
|
+
"""
|
|
20
|
+
Individual route definition with AI-enhanced capabilities.
|
|
21
|
+
This uses a declarative approach.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
path: str,
|
|
27
|
+
handler: Callable,
|
|
28
|
+
methods: List[str] = ["GET"],
|
|
29
|
+
name: str = None,
|
|
30
|
+
description: str = None,
|
|
31
|
+
tags: List[str] = None,
|
|
32
|
+
ai_enhanced: bool = False
|
|
33
|
+
):
|
|
34
|
+
self.path = path
|
|
35
|
+
self.handler = handler
|
|
36
|
+
self.methods = [m.upper() for m in methods]
|
|
37
|
+
self.name = name or f"{path.replace('/', '_').strip('_')}"
|
|
38
|
+
self.description = description
|
|
39
|
+
self.tags = tags or []
|
|
40
|
+
self.ai_enhanced = ai_enhanced
|
|
41
|
+
self.stats = {
|
|
42
|
+
'requests': 0,
|
|
43
|
+
'errors': 0,
|
|
44
|
+
'avg_response_time': 0,
|
|
45
|
+
'last_called': None
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def matches_path(self, path: str) -> Dict[str, str]:
|
|
49
|
+
"""Check if route matches path and extract parameters"""
|
|
50
|
+
# Handle wildcard paths like /static/*, /css/*, /js/*
|
|
51
|
+
if self.path.endswith('/*') or self.path.endswith('/{path:path}'):
|
|
52
|
+
route_prefix = self.path.replace('/*', '').replace('/{path:path}', '')
|
|
53
|
+
if path.startswith(route_prefix):
|
|
54
|
+
remaining = path[len(route_prefix):].lstrip('/')
|
|
55
|
+
return {'wildcard': remaining, 'path': remaining}
|
|
56
|
+
|
|
57
|
+
# Handle path parameters {param}
|
|
58
|
+
if '{' in self.path:
|
|
59
|
+
path_parts = self.path.split('/')
|
|
60
|
+
url_parts = path.split('/')
|
|
61
|
+
|
|
62
|
+
if len(path_parts) == len(url_parts):
|
|
63
|
+
params = {}
|
|
64
|
+
for i, part in enumerate(path_parts):
|
|
65
|
+
if part.startswith('{') and part.endswith('}'):
|
|
66
|
+
param_name = part[1:-1].split(':')[0] # Handle {name:type}
|
|
67
|
+
params[param_name] = url_parts[i]
|
|
68
|
+
elif part != url_parts[i]:
|
|
69
|
+
return None
|
|
70
|
+
return params
|
|
71
|
+
|
|
72
|
+
# Simple exact match
|
|
73
|
+
if self.path == path:
|
|
74
|
+
return {}
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
async def execute(self, request: Dict[str, Any]) -> Any:
|
|
78
|
+
"""Execute the route handler with timing and error tracking"""
|
|
79
|
+
start_time = datetime.utcnow()
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
self.stats['requests'] += 1
|
|
83
|
+
|
|
84
|
+
# Execute handler (sync or async)
|
|
85
|
+
if asyncio.iscoroutinefunction(self.handler):
|
|
86
|
+
result = await self.handler(request)
|
|
87
|
+
else:
|
|
88
|
+
result = self.handler(request)
|
|
89
|
+
|
|
90
|
+
# Update timing stats
|
|
91
|
+
end_time = datetime.utcnow()
|
|
92
|
+
response_time = (end_time - start_time).total_seconds() * 1000
|
|
93
|
+
self.stats['avg_response_time'] = (
|
|
94
|
+
(self.stats['avg_response_time'] * (self.stats['requests'] - 1) + response_time)
|
|
95
|
+
/ self.stats['requests']
|
|
96
|
+
)
|
|
97
|
+
self.stats['last_called'] = end_time.isoformat()
|
|
98
|
+
|
|
99
|
+
return result
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
self.stats['errors'] += 1
|
|
103
|
+
raise e
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class CreatesonlineRouter:
|
|
107
|
+
"""
|
|
108
|
+
CREATESONLINE's unique routing system.
|
|
109
|
+
|
|
110
|
+
This uses a unique approach to routing.
|
|
111
|
+
this uses an intelligent registry system with built-in analytics.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(self):
|
|
115
|
+
self.routes: List[CreatesonlineRoute] = []
|
|
116
|
+
self.middleware: List[Callable] = []
|
|
117
|
+
self.global_stats = {
|
|
118
|
+
'total_requests': 0,
|
|
119
|
+
'total_errors': 0,
|
|
120
|
+
'start_time': datetime.utcnow()
|
|
121
|
+
}
|
|
122
|
+
self.static_file_handler = None # Will be set later
|
|
123
|
+
|
|
124
|
+
def register(
|
|
125
|
+
self,
|
|
126
|
+
path: str,
|
|
127
|
+
handler: Callable,
|
|
128
|
+
methods: List[str] = ["GET"],
|
|
129
|
+
**kwargs
|
|
130
|
+
) -> CreatesonlineRoute:
|
|
131
|
+
"""Register a new route with the router"""
|
|
132
|
+
route = CreatesonlineRoute(path, handler, methods, **kwargs)
|
|
133
|
+
self.routes.append(route)
|
|
134
|
+
return route
|
|
135
|
+
|
|
136
|
+
def GET(self, path: str, **kwargs):
|
|
137
|
+
"""Shorthand for GET route registration"""
|
|
138
|
+
def decorator(handler):
|
|
139
|
+
return self.register(path, handler, ["GET"], **kwargs)
|
|
140
|
+
return decorator
|
|
141
|
+
|
|
142
|
+
def POST(self, path: str, **kwargs):
|
|
143
|
+
"""Shorthand for POST route registration"""
|
|
144
|
+
def decorator(handler):
|
|
145
|
+
return self.register(path, handler, ["POST"], **kwargs)
|
|
146
|
+
return decorator
|
|
147
|
+
|
|
148
|
+
def PUT(self, path: str, **kwargs):
|
|
149
|
+
"""Shorthand for PUT route registration"""
|
|
150
|
+
def decorator(handler):
|
|
151
|
+
return self.register(path, handler, ["PUT"], **kwargs)
|
|
152
|
+
return decorator
|
|
153
|
+
|
|
154
|
+
def DELETE(self, path: str, **kwargs):
|
|
155
|
+
"""Shorthand for DELETE route registration"""
|
|
156
|
+
def decorator(handler):
|
|
157
|
+
return self.register(path, handler, ["DELETE"], **kwargs)
|
|
158
|
+
return decorator
|
|
159
|
+
|
|
160
|
+
def AI(self, path: str, methods: List[str] = ["GET"], **kwargs):
|
|
161
|
+
"""Register an AI-enhanced route"""
|
|
162
|
+
def decorator(handler):
|
|
163
|
+
kwargs['ai_enhanced'] = True
|
|
164
|
+
kwargs['tags'] = kwargs.get('tags', []) + ['ai']
|
|
165
|
+
return self.register(path, handler, methods, **kwargs)
|
|
166
|
+
return decorator
|
|
167
|
+
|
|
168
|
+
def add_middleware(self, middleware: Callable):
|
|
169
|
+
"""Add middleware to the router"""
|
|
170
|
+
self.middleware.append(middleware)
|
|
171
|
+
|
|
172
|
+
def _is_static_file(self, path: str) -> bool:
|
|
173
|
+
"""Check if path looks like a static file"""
|
|
174
|
+
static_extensions = {
|
|
175
|
+
'.html', '.htm', '.css', '.js', '.json', '.xml',
|
|
176
|
+
'.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp',
|
|
177
|
+
'.woff', '.woff2', '.ttf', '.eot',
|
|
178
|
+
'.pdf', '.txt', '.md',
|
|
179
|
+
'.mp4', '.webm', '.mp3', '.wav'
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Check if path has a static extension
|
|
183
|
+
for ext in static_extensions:
|
|
184
|
+
if path.endswith(ext):
|
|
185
|
+
return True
|
|
186
|
+
|
|
187
|
+
# Check if path starts with common static prefixes
|
|
188
|
+
static_prefixes = ['/static/', '/css/', '/js/', '/images/', '/img/', '/assets/', '/media/', '/files/']
|
|
189
|
+
for prefix in static_prefixes:
|
|
190
|
+
if path.startswith(prefix):
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
return False
|
|
194
|
+
|
|
195
|
+
async def _serve_static_file(self, path: str) -> Any:
|
|
196
|
+
"""Serve a static file dynamically"""
|
|
197
|
+
try:
|
|
198
|
+
# Initialize static handler if not already done
|
|
199
|
+
if self.static_file_handler is None:
|
|
200
|
+
from createsonline.static_files import static_handler
|
|
201
|
+
self.static_file_handler = static_handler
|
|
202
|
+
|
|
203
|
+
# Serve the file
|
|
204
|
+
content, status_code, headers = self.static_file_handler.serve_file(path)
|
|
205
|
+
|
|
206
|
+
return content, status_code, headers
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
logger.error(f"Error serving static file {path}: {e}")
|
|
210
|
+
return {"error": f"Failed to serve file: {str(e)}"}, 500
|
|
211
|
+
|
|
212
|
+
async def route(self, request: Dict[str, Any]) -> Any:
|
|
213
|
+
"""
|
|
214
|
+
Main routing logic
|
|
215
|
+
Uses intelligent matching and built-in analytics.
|
|
216
|
+
"""
|
|
217
|
+
path = request.get('path', '/')
|
|
218
|
+
method = request.get('method', 'GET').upper()
|
|
219
|
+
|
|
220
|
+
# Update global stats
|
|
221
|
+
self.global_stats['total_requests'] += 1
|
|
222
|
+
|
|
223
|
+
# Auto-detect and serve static files (HTML, CSS, JS, images, etc.)
|
|
224
|
+
if self._is_static_file(path):
|
|
225
|
+
return await self._serve_static_file(path)
|
|
226
|
+
|
|
227
|
+
# Find matching route
|
|
228
|
+
matching_route = None
|
|
229
|
+
path_params = {}
|
|
230
|
+
for route in self.routes:
|
|
231
|
+
params = route.matches_path(path)
|
|
232
|
+
if params is not None and method in route.methods:
|
|
233
|
+
matching_route = route
|
|
234
|
+
path_params = params
|
|
235
|
+
break
|
|
236
|
+
|
|
237
|
+
if not matching_route:
|
|
238
|
+
self.global_stats['total_errors'] += 1
|
|
239
|
+
return {
|
|
240
|
+
'error': 'Route not found',
|
|
241
|
+
'path': path,
|
|
242
|
+
'method': method,
|
|
243
|
+
'available_routes': [
|
|
244
|
+
{
|
|
245
|
+
'path': r.path,
|
|
246
|
+
'methods': r.methods,
|
|
247
|
+
'name': r.name
|
|
248
|
+
} for r in self.routes
|
|
249
|
+
]
|
|
250
|
+
}, 404
|
|
251
|
+
|
|
252
|
+
# Apply middleware
|
|
253
|
+
for middleware in self.middleware:
|
|
254
|
+
try:
|
|
255
|
+
if asyncio.iscoroutinefunction(middleware):
|
|
256
|
+
modified_request = await middleware(request)
|
|
257
|
+
else:
|
|
258
|
+
modified_request = middleware(request)
|
|
259
|
+
|
|
260
|
+
# Support early exit from middleware
|
|
261
|
+
if modified_request is None:
|
|
262
|
+
# Middleware wants to short-circuit
|
|
263
|
+
return {"error": "Request blocked by middleware"}, 403
|
|
264
|
+
|
|
265
|
+
request = modified_request
|
|
266
|
+
except Exception as e:
|
|
267
|
+
logger.exception(f"Middleware error: {e}")
|
|
268
|
+
return {"error": "Middleware processing failed"}, 500
|
|
269
|
+
|
|
270
|
+
# Add path parameters to request
|
|
271
|
+
if path_params:
|
|
272
|
+
request['path_params'] = path_params
|
|
273
|
+
|
|
274
|
+
# Execute route
|
|
275
|
+
try:
|
|
276
|
+
result = await matching_route.execute(request)
|
|
277
|
+
|
|
278
|
+
# Apply security headers if they were set by middleware
|
|
279
|
+
if 'security_headers' in request:
|
|
280
|
+
if isinstance(result, tuple) and len(result) >= 2:
|
|
281
|
+
# Result is (data, status_code, headers)
|
|
282
|
+
data, status_code = result[0], result[1]
|
|
283
|
+
existing_headers = result[2] if len(result) > 2 else {}
|
|
284
|
+
# Merge security headers with existing headers
|
|
285
|
+
merged_headers = {**request['security_headers'], **existing_headers}
|
|
286
|
+
return data, status_code, merged_headers
|
|
287
|
+
else:
|
|
288
|
+
# Result is just data, add security headers
|
|
289
|
+
return result, 200, request['security_headers']
|
|
290
|
+
|
|
291
|
+
# Return result as-is if it's a tuple, or default to 200 status
|
|
292
|
+
if isinstance(result, tuple):
|
|
293
|
+
return result
|
|
294
|
+
return result, 200
|
|
295
|
+
except Exception as e:
|
|
296
|
+
self.global_stats['total_errors'] += 1
|
|
297
|
+
return {
|
|
298
|
+
'error': str(e),
|
|
299
|
+
'route': matching_route.name,
|
|
300
|
+
'path': path
|
|
301
|
+
}, 500
|
|
302
|
+
|
|
303
|
+
def get_route_stats(self) -> Dict[str, Any]:
|
|
304
|
+
"""Get detailed routing statistics"""
|
|
305
|
+
route_stats = []
|
|
306
|
+
for route in self.routes:
|
|
307
|
+
route_stats.append({
|
|
308
|
+
'path': route.path,
|
|
309
|
+
'name': route.name,
|
|
310
|
+
'methods': route.methods,
|
|
311
|
+
'stats': route.stats,
|
|
312
|
+
'ai_enhanced': route.ai_enhanced,
|
|
313
|
+
'tags': route.tags
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
uptime = (datetime.utcnow() - self.global_stats['start_time']).total_seconds()
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
'global_stats': {
|
|
320
|
+
**self.global_stats,
|
|
321
|
+
'uptime_seconds': uptime,
|
|
322
|
+
'error_rate': (
|
|
323
|
+
self.global_stats['total_errors'] /
|
|
324
|
+
max(self.global_stats['total_requests'], 1)
|
|
325
|
+
) * 100
|
|
326
|
+
},
|
|
327
|
+
'route_stats': route_stats,
|
|
328
|
+
'total_routes': len(self.routes),
|
|
329
|
+
'ai_routes': len([r for r in self.routes if r.ai_enhanced])
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
def generate_api_spec(self) -> Dict[str, Any]:
|
|
333
|
+
"""Generate OpenAPI-like specification"""
|
|
334
|
+
paths = {}
|
|
335
|
+
|
|
336
|
+
for route in self.routes:
|
|
337
|
+
if route.path not in paths:
|
|
338
|
+
paths[route.path] = {}
|
|
339
|
+
|
|
340
|
+
for method in route.methods:
|
|
341
|
+
# Basic response definition
|
|
342
|
+
response_def = {
|
|
343
|
+
'description': 'Successful response',
|
|
344
|
+
'content': {
|
|
345
|
+
'application/json': {
|
|
346
|
+
'schema': {'type': 'object'}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
# Include common security headers that may be added by middleware
|
|
352
|
+
# Note: These are added by security middleware, not per-route
|
|
353
|
+
response_def['headers'] = {
|
|
354
|
+
'X-Content-Type-Options': {
|
|
355
|
+
'description': 'MIME type sniffing prevention (added by security middleware)',
|
|
356
|
+
'schema': {'type': 'string', 'example': 'nosniff'}
|
|
357
|
+
},
|
|
358
|
+
'X-Frame-Options': {
|
|
359
|
+
'description': 'Clickjacking protection (added by security middleware)',
|
|
360
|
+
'schema': {'type': 'string', 'example': 'DENY'}
|
|
361
|
+
},
|
|
362
|
+
'X-XSS-Protection': {
|
|
363
|
+
'description': 'XSS protection (added by security middleware)',
|
|
364
|
+
'schema': {'type': 'string', 'example': '1; mode=block'}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
paths[route.path][method.lower()] = {
|
|
369
|
+
'summary': route.name.replace('_', ' ').title(),
|
|
370
|
+
'description': route.description or f"{method} {route.path}",
|
|
371
|
+
'tags': route.tags,
|
|
372
|
+
'x-ai-enhanced': route.ai_enhanced,
|
|
373
|
+
'responses': {
|
|
374
|
+
'200': response_def
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
from . import __version__
|
|
379
|
+
return {
|
|
380
|
+
'openapi': '3.0.0',
|
|
381
|
+
'info': {
|
|
382
|
+
'title': 'CREATESONLINE API',
|
|
383
|
+
'version': __version__,
|
|
384
|
+
'description': 'AI-Native Web Framework API with Intelligent Routing',
|
|
385
|
+
'x-framework': 'CREATESONLINE',
|
|
386
|
+
'x-routing-system': 'Intelligence-Based'
|
|
387
|
+
},
|
|
388
|
+
'paths': paths,
|
|
389
|
+
'x-route-stats': self.get_route_stats()
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
class IntelligentMiddleware:
|
|
394
|
+
"""
|
|
395
|
+
Middleware system that's different from typical frameworks.
|
|
396
|
+
Uses AI-like decision making for request processing.
|
|
397
|
+
"""
|
|
398
|
+
|
|
399
|
+
@staticmethod
|
|
400
|
+
def request_logger(request: Dict[str, Any]) -> Dict[str, Any]:
|
|
401
|
+
"""Log requests with intelligent filtering"""
|
|
402
|
+
# Skip logging for health checks and static files
|
|
403
|
+
path = request.get('path', '')
|
|
404
|
+
if path in ['/health', '/favicon.ico'] or path.startswith('/static/'):
|
|
405
|
+
return request
|
|
406
|
+
|
|
407
|
+
logger.info(f"{request.get('method', 'GET')} {path}")
|
|
408
|
+
return request
|
|
409
|
+
|
|
410
|
+
@staticmethod
|
|
411
|
+
def security_headers(request: Dict[str, Any]) -> Dict[str, Any]:
|
|
412
|
+
"""Add security headers intelligently"""
|
|
413
|
+
request['security_headers'] = {
|
|
414
|
+
'X-Content-Type-Options': 'nosniff',
|
|
415
|
+
'X-Frame-Options': 'DENY',
|
|
416
|
+
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';",
|
|
417
|
+
'X-Framework': 'CREATESONLINE-AI'
|
|
418
|
+
}
|
|
419
|
+
return request
|
|
420
|
+
|
|
421
|
+
@staticmethod
|
|
422
|
+
async def ai_request_analyzer(request: Dict[str, Any]) -> Dict[str, Any]:
|
|
423
|
+
"""Analyze requests using AI-like logic"""
|
|
424
|
+
path = request.get('path', '')
|
|
425
|
+
|
|
426
|
+
# Detect API endpoints
|
|
427
|
+
if path.startswith('/api/') or path.endswith('.json'):
|
|
428
|
+
request['content_type'] = 'application/json'
|
|
429
|
+
|
|
430
|
+
# Detect admin requests
|
|
431
|
+
if path.startswith('/admin/'):
|
|
432
|
+
request['requires_auth'] = True
|
|
433
|
+
|
|
434
|
+
# Add intelligent suggestions
|
|
435
|
+
if path == '/documentation' or path == '/docs':
|
|
436
|
+
request['suggested_redirect'] = '/docs'
|
|
437
|
+
|
|
438
|
+
return request
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
# Global router instance
|
|
442
|
+
router = CreatesonlineRouter()
|
|
443
|
+
|
|
444
|
+
# Add default middleware
|
|
445
|
+
router.add_middleware(IntelligentMiddleware.request_logger)
|
|
446
|
+
router.add_middleware(IntelligentMiddleware.security_headers)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
# Helper functions for easy routing
|
|
450
|
+
def path(route: str, view, methods: List[str] = None, name: str = None):
|
|
451
|
+
"""
|
|
452
|
+
Django-style path() helper for defining routes
|
|
453
|
+
|
|
454
|
+
Usage:
|
|
455
|
+
from createsonline.routing import path
|
|
456
|
+
from myapp import views
|
|
457
|
+
|
|
458
|
+
urlpatterns = [
|
|
459
|
+
path('/', views.home),
|
|
460
|
+
path('/api/users', views.UserListView.as_view()),
|
|
461
|
+
path('/api/users/{id}', views.UserDetailView.as_view(), name='user-detail'),
|
|
462
|
+
]
|
|
463
|
+
"""
|
|
464
|
+
methods = methods or ['GET']
|
|
465
|
+
|
|
466
|
+
# Handle class-based views
|
|
467
|
+
if hasattr(view, 'as_view'):
|
|
468
|
+
view = view.as_view()
|
|
469
|
+
|
|
470
|
+
return CreatesonlineRoute(
|
|
471
|
+
path=route,
|
|
472
|
+
handler=view,
|
|
473
|
+
methods=methods,
|
|
474
|
+
name=name
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def include(module_path: str):
|
|
479
|
+
"""
|
|
480
|
+
Include routes from another module
|
|
481
|
+
|
|
482
|
+
Usage:
|
|
483
|
+
from createsonline.routing import path, include
|
|
484
|
+
|
|
485
|
+
urlpatterns = [
|
|
486
|
+
path('/api/', include('myapp.api.routes')),
|
|
487
|
+
path('/admin/', include('myapp.admin.routes')),
|
|
488
|
+
]
|
|
489
|
+
"""
|
|
490
|
+
import importlib
|
|
491
|
+
module = importlib.import_module(module_path)
|
|
492
|
+
return getattr(module, 'urlpatterns', [])
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def register_routes(app, urlpatterns: List[CreatesonlineRoute]):
|
|
496
|
+
"""
|
|
497
|
+
Register a list of URL patterns with the app
|
|
498
|
+
|
|
499
|
+
Usage:
|
|
500
|
+
from createsonline import create_app
|
|
501
|
+
from createsonline.routing import register_routes
|
|
502
|
+
from . import routes
|
|
503
|
+
|
|
504
|
+
app = create_app()
|
|
505
|
+
register_routes(app, routes.urlpatterns)
|
|
506
|
+
"""
|
|
507
|
+
for route in urlpatterns:
|
|
508
|
+
if isinstance(route, list):
|
|
509
|
+
# Handle included routes
|
|
510
|
+
register_routes(app, route)
|
|
511
|
+
elif isinstance(route, CreatesonlineRoute):
|
|
512
|
+
# Register the route
|
|
513
|
+
for method in route.methods:
|
|
514
|
+
if hasattr(app, method.lower()):
|
|
515
|
+
decorator = getattr(app, method.lower())
|
|
516
|
+
decorator(route.path)(route.handler)
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
# Export main components
|
|
520
|
+
__all__ = [
|
|
521
|
+
'CreatesonlineRoute',
|
|
522
|
+
'CreatesonlineRouter',
|
|
523
|
+
'IntelligentMiddleware',
|
|
524
|
+
'router',
|
|
525
|
+
'path',
|
|
526
|
+
'include',
|
|
527
|
+
'register_routes'
|
|
528
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# createsonline/security/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
CREATESONLINE Security Module
|
|
4
|
+
|
|
5
|
+
Ultra-high security implementations that prevent vulnerabilities:
|
|
6
|
+
- SQL injection protection
|
|
7
|
+
- XSS prevention
|
|
8
|
+
- CSRF protection
|
|
9
|
+
- Rate limiting
|
|
10
|
+
- Input validation
|
|
11
|
+
- Authentication & authorization
|
|
12
|
+
- Encryption utilities
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
'SecurityManager',
|
|
17
|
+
'InputValidator',
|
|
18
|
+
'RateLimiter',
|
|
19
|
+
'CSRFProtection',
|
|
20
|
+
'XSSProtection',
|
|
21
|
+
'SQLInjectionProtection',
|
|
22
|
+
'encrypt_password',
|
|
23
|
+
'verify_password',
|
|
24
|
+
'generate_secure_token',
|
|
25
|
+
'secure_middleware'
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
from .core import SecurityManager, secure_middleware
|
|
29
|
+
from .validation import InputValidator
|
|
30
|
+
from .rate_limiting import RateLimiter
|
|
31
|
+
from .csrf import CSRFProtection
|
|
32
|
+
from .xss import XSSProtection
|
|
33
|
+
from .encryption import encrypt_password, verify_password, generate_secure_token
|
|
34
|
+
from .sql_protection import SQLInjectionProtection
|