tina4-python 0.2.122__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.
- tina4_python/Auth.py +222 -0
- tina4_python/Constant.py +43 -0
- tina4_python/Database.py +591 -0
- tina4_python/DatabaseResult.py +107 -0
- tina4_python/DatabaseTypes.py +15 -0
- tina4_python/Debug.py +126 -0
- tina4_python/Env.py +37 -0
- tina4_python/Localization.py +42 -0
- tina4_python/Messages.py +30 -0
- tina4_python/MiddleWare.py +90 -0
- tina4_python/Migration.py +107 -0
- tina4_python/ORM.py +639 -0
- tina4_python/Queue.py +615 -0
- tina4_python/Request.py +19 -0
- tina4_python/Response.py +121 -0
- tina4_python/Router.py +423 -0
- tina4_python/Session.py +342 -0
- tina4_python/ShellColors.py +20 -0
- tina4_python/Swagger.py +228 -0
- tina4_python/Template.py +107 -0
- tina4_python/Webserver.py +429 -0
- tina4_python/Websocket.py +49 -0
- tina4_python/__init__.py +392 -0
- tina4_python/messages.pot +83 -0
- tina4_python/public/css/readme.md +0 -0
- tina4_python/public/favicon.ico +0 -0
- tina4_python/public/images/403.png +0 -0
- tina4_python/public/images/404.png +0 -0
- tina4_python/public/images/500.png +0 -0
- tina4_python/public/images/logo.png +0 -0
- tina4_python/public/images/readme.md +0 -0
- tina4_python/public/js/readme.md +0 -0
- tina4_python/public/js/reconnecting-websocket.js +365 -0
- tina4_python/public/js/tina4helper.js +397 -0
- tina4_python/public/swagger/index.html +90 -0
- tina4_python/public/swagger/oauth2-redirect.html +63 -0
- tina4_python/templates/errors/403.twig +10 -0
- tina4_python/templates/errors/404.twig +10 -0
- tina4_python/templates/errors/500.twig +11 -0
- tina4_python/templates/readme.md +1 -0
- tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- tina4_python/translations/en/LC_MESSAGES/messages.po +80 -0
- tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- tina4_python/translations/fr/LC_MESSAGES/messages.po +84 -0
- tina4_python-0.2.122.dist-info/METADATA +465 -0
- tina4_python-0.2.122.dist-info/RECORD +47 -0
- tina4_python-0.2.122.dist-info/WHEEL +4 -0
tina4_python/Response.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Tina4 - This is not a 4ramework.
|
|
3
|
+
# Copy-right 2007 - current Tina4
|
|
4
|
+
# License: MIT https://opensource.org/licenses/MIT
|
|
5
|
+
#
|
|
6
|
+
# flake8: noqa: E501
|
|
7
|
+
import json
|
|
8
|
+
import inspect
|
|
9
|
+
from datetime import datetime, date
|
|
10
|
+
from types import ModuleType
|
|
11
|
+
from tina4_python import Constant
|
|
12
|
+
from tina4_python import DatabaseResult
|
|
13
|
+
from tina4_python.ORM import ORM
|
|
14
|
+
from tina4_python.Template import Template
|
|
15
|
+
|
|
16
|
+
headers = {}
|
|
17
|
+
content = ""
|
|
18
|
+
http_code = Constant.HTTP_OK
|
|
19
|
+
content_type = Constant.TEXT_HTML
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Response:
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def convert_special_types(obj):
|
|
26
|
+
if isinstance(obj, dict):
|
|
27
|
+
return {k: Response.convert_special_types(v) for k, v in obj.items()}
|
|
28
|
+
elif isinstance(obj, list):
|
|
29
|
+
return [Response.convert_special_types(i) for i in obj]
|
|
30
|
+
elif isinstance(obj, (date, datetime)):
|
|
31
|
+
return obj.isoformat()
|
|
32
|
+
else:
|
|
33
|
+
return obj
|
|
34
|
+
|
|
35
|
+
def __init__(self, content_in=None, http_code_in=None, content_type_in=None,
|
|
36
|
+
headers_in=None):
|
|
37
|
+
global headers
|
|
38
|
+
global content
|
|
39
|
+
global http_code
|
|
40
|
+
global content_type
|
|
41
|
+
|
|
42
|
+
if (not isinstance(content_in, bool) and not isinstance(content_in, object)
|
|
43
|
+
and not isinstance(content_in, bytes)
|
|
44
|
+
and not isinstance(content_in, str)
|
|
45
|
+
and not isinstance(content_in, list) and inspect.isclass(type(content_in))):
|
|
46
|
+
content_in = dict(content_in)
|
|
47
|
+
|
|
48
|
+
if isinstance(content_in, ORM):
|
|
49
|
+
content_type = Constant.APPLICATION_JSON
|
|
50
|
+
content_in = content_in.to_json()
|
|
51
|
+
|
|
52
|
+
# check if database result
|
|
53
|
+
if type(content_in) is DatabaseResult.DatabaseResult:
|
|
54
|
+
content_type = Constant.APPLICATION_JSON
|
|
55
|
+
content_in = content_in.to_json()
|
|
56
|
+
|
|
57
|
+
# convert the dictionary or list into JSON
|
|
58
|
+
if not isinstance(content_in, bool) and type(content_in) is dict or type(content_in) is list:
|
|
59
|
+
content_in = json.dumps(Response.convert_special_types(content_in))
|
|
60
|
+
content_type = Constant.APPLICATION_JSON
|
|
61
|
+
|
|
62
|
+
if isinstance(content_in, bool):
|
|
63
|
+
if content_in:
|
|
64
|
+
content_in = "True"
|
|
65
|
+
else:
|
|
66
|
+
content_in = "False"
|
|
67
|
+
|
|
68
|
+
if isinstance(content_in, ModuleType):
|
|
69
|
+
content_in = json.dumps({"error": "Cannot decode object of type " + str(type(content_in))})
|
|
70
|
+
content_type = Constant.APPLICATION_JSON
|
|
71
|
+
|
|
72
|
+
if content is not None and isinstance(content_in, str):
|
|
73
|
+
content_in = content + content_in
|
|
74
|
+
|
|
75
|
+
self.headers = headers_in if headers_in is not None else headers
|
|
76
|
+
self.content = content_in if content_in is not None else content
|
|
77
|
+
self.http_code = http_code_in if http_code_in is not None else http_code
|
|
78
|
+
self.content_type = content_type_in if content_type_in is not None else content_type
|
|
79
|
+
headers = self.headers
|
|
80
|
+
http_code = self.http_code
|
|
81
|
+
content_type = self.content_type
|
|
82
|
+
content = self.content
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def redirect(redirect_url):
|
|
86
|
+
"""
|
|
87
|
+
Redirects a request to redirect_url
|
|
88
|
+
:param redirect_url:
|
|
89
|
+
:return:
|
|
90
|
+
"""
|
|
91
|
+
global headers
|
|
92
|
+
global content
|
|
93
|
+
global http_code
|
|
94
|
+
global content_type
|
|
95
|
+
headers = {}
|
|
96
|
+
http_code = Constant.HTTP_REDIRECT
|
|
97
|
+
headers["Location"] = redirect_url
|
|
98
|
+
content = ""
|
|
99
|
+
content_type = Constant.TEXT_HTML
|
|
100
|
+
return Response("", http_code, content_type, headers)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def render(template_name, data=None):
|
|
105
|
+
global content, content_type, http_code
|
|
106
|
+
http_code = Constant.HTTP_OK
|
|
107
|
+
content_type = Constant.TEXT_HTML
|
|
108
|
+
|
|
109
|
+
return Response(Template.render(template_name, data=data), http_code, content_type)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def add_header(key, value):
|
|
114
|
+
"""
|
|
115
|
+
Adds a header for the response
|
|
116
|
+
:param key:
|
|
117
|
+
:param value:
|
|
118
|
+
:return:
|
|
119
|
+
"""
|
|
120
|
+
global headers
|
|
121
|
+
headers[key] = value
|
tina4_python/Router.py
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Tina4 - This is not a 4ramework.
|
|
3
|
+
# Copy-right 2007 - current Tina4
|
|
4
|
+
# License: MIT https://opensource.org/licenses/MIT
|
|
5
|
+
#
|
|
6
|
+
# flake8: noqa: E501
|
|
7
|
+
import json
|
|
8
|
+
import mimetypes
|
|
9
|
+
import re
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import io
|
|
13
|
+
import tina4_python
|
|
14
|
+
from tina4_python import Constant
|
|
15
|
+
from tina4_python import Response
|
|
16
|
+
from tina4_python import Request
|
|
17
|
+
from tina4_python.Debug import Debug
|
|
18
|
+
from tina4_python.Template import Template
|
|
19
|
+
from tina4_python.MiddleWare import MiddleWare
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Router:
|
|
23
|
+
variables = None
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def get_variables(url, route_path):
|
|
27
|
+
variables = {}
|
|
28
|
+
url_segments = url.strip('/').split('/')
|
|
29
|
+
route_segments = route_path.strip('/').split('/')
|
|
30
|
+
for i, segment in enumerate(route_segments):
|
|
31
|
+
if '{' in segment: # parameter part
|
|
32
|
+
param_name = re.search(r'{(.*?)}', segment).group(1)
|
|
33
|
+
variables[param_name] = url_segments[i]
|
|
34
|
+
return variables
|
|
35
|
+
|
|
36
|
+
# Matches the URL to the route and extracts the parameters
|
|
37
|
+
@staticmethod
|
|
38
|
+
def match(url, route_path):
|
|
39
|
+
matching = False
|
|
40
|
+
variables = {}
|
|
41
|
+
|
|
42
|
+
# splitting URL and route and putting them into lists to compare
|
|
43
|
+
url_segments = url.strip('/').split('/')
|
|
44
|
+
route_segments = route_path.strip('/').split('/')
|
|
45
|
+
|
|
46
|
+
if len(url_segments) == len(route_segments):
|
|
47
|
+
matching = True
|
|
48
|
+
for i, segment in enumerate(route_segments):
|
|
49
|
+
if '{' in segment: # parameter part
|
|
50
|
+
param_name = re.search(r'{(.*?)}', segment).group(1)
|
|
51
|
+
variables[param_name] = url_segments[i]
|
|
52
|
+
elif segment != url_segments[i]: # non-parameter part
|
|
53
|
+
matching = False
|
|
54
|
+
break
|
|
55
|
+
|
|
56
|
+
Router.variables = variables
|
|
57
|
+
|
|
58
|
+
return matching
|
|
59
|
+
|
|
60
|
+
# Renders the URL and returns the content
|
|
61
|
+
@staticmethod
|
|
62
|
+
async def get_result(url, method, request, headers, session):
|
|
63
|
+
global Request
|
|
64
|
+
global Response
|
|
65
|
+
|
|
66
|
+
Response.headers = {}
|
|
67
|
+
Response.content = ""
|
|
68
|
+
Response.http_code = Constant.HTTP_NOT_FOUND
|
|
69
|
+
Response.content_type = Constant.TEXT_HTML
|
|
70
|
+
result = Response
|
|
71
|
+
|
|
72
|
+
Debug("Root Path " + tina4_python.root_path + " " + url, method, Constant.TINA4_LOG_DEBUG)
|
|
73
|
+
tina4_python.tina4_current_request["url"] = url
|
|
74
|
+
tina4_python.tina4_current_request["headers"] = headers
|
|
75
|
+
|
|
76
|
+
validated = False
|
|
77
|
+
# we can add other methods later but right now we validate posts
|
|
78
|
+
if method in [Constant.TINA4_GET, Constant.TINA4_POST, Constant.TINA4_PUT, Constant.TINA4_PATCH,
|
|
79
|
+
Constant.TINA4_DELETE]:
|
|
80
|
+
content_type = "text/html"
|
|
81
|
+
if "content-type" in headers:
|
|
82
|
+
content_type = headers["content-type"]
|
|
83
|
+
|
|
84
|
+
if content_type == "application/json":
|
|
85
|
+
content = {"error": "403 - Forbidden", "data": {"server": {"url": url}}}
|
|
86
|
+
else:
|
|
87
|
+
content = Template.render_twig_template(
|
|
88
|
+
"errors/403.twig", {"server": {"url": url}})
|
|
89
|
+
|
|
90
|
+
# check to see if we have an auth ability
|
|
91
|
+
if "authorization" in headers:
|
|
92
|
+
token = headers["authorization"].replace("Bearer", "").strip()
|
|
93
|
+
if tina4_python.tina4_auth.valid(token):
|
|
94
|
+
validated = True
|
|
95
|
+
|
|
96
|
+
if request["params"] is not None and "formToken" in request["params"]:
|
|
97
|
+
token = request["params"]["formToken"]
|
|
98
|
+
if tina4_python.tina4_auth.valid(token):
|
|
99
|
+
validated = True
|
|
100
|
+
|
|
101
|
+
if request["body"] is not None and "formToken" in request["body"]:
|
|
102
|
+
token = request["body"]["formToken"]
|
|
103
|
+
if tina4_python.tina4_auth.valid(token):
|
|
104
|
+
validated = True
|
|
105
|
+
|
|
106
|
+
if request["body"] is not None and "formToken" in request["body"]:
|
|
107
|
+
request["params"]["formToken"] = request["body"]["formToken"]
|
|
108
|
+
del request["body"]["formToken"]
|
|
109
|
+
|
|
110
|
+
# split URL and extract query string
|
|
111
|
+
url_parts = url.split('?')
|
|
112
|
+
url = url_parts[0]
|
|
113
|
+
|
|
114
|
+
# Serve statics
|
|
115
|
+
static_file = tina4_python.root_path + os.sep + "src" + os.sep + "public" + url.replace("/", os.sep)
|
|
116
|
+
Debug("Attempting to serve static file: " + static_file, Constant.TINA4_LOG_DEBUG)
|
|
117
|
+
if os.path.isfile(static_file):
|
|
118
|
+
mime_type = mimetypes.guess_type(url)[0]
|
|
119
|
+
with open(static_file, 'rb') as file:
|
|
120
|
+
return Response.Response(file.read(), Constant.HTTP_OK, mime_type)
|
|
121
|
+
|
|
122
|
+
old_stdout = None
|
|
123
|
+
buffer = io.StringIO()
|
|
124
|
+
for route in tina4_python.tina4_routes.values():
|
|
125
|
+
if route["method"] != method:
|
|
126
|
+
continue
|
|
127
|
+
Debug("Matching route " + route['route'] + " to " + url, Constant.TINA4_LOG_DEBUG)
|
|
128
|
+
if Router.match(url, route['route']):
|
|
129
|
+
if not "noauth" in route:
|
|
130
|
+
if "secure" in route or ("swagger" in route and route["swagger"] is not None and "secure" in route["swagger"]):
|
|
131
|
+
if (("secure" in route and route["secure"]) or ("swagger" in route and route["swagger"] is not None and route["swagger"]["secure"])) and not validated:
|
|
132
|
+
return Response.Response(content, Constant.HTTP_FORBIDDEN, Constant.TEXT_HTML)
|
|
133
|
+
else:
|
|
134
|
+
if not validated and method not in [Constant.TINA4_OPTIONS, Constant.TINA4_GET]:
|
|
135
|
+
return Response.Response(content, Constant.HTTP_FORBIDDEN, Constant.TEXT_HTML)
|
|
136
|
+
|
|
137
|
+
router_response = route["callback"]
|
|
138
|
+
|
|
139
|
+
# Add the inline variables & construct a Request variable
|
|
140
|
+
request["params"].update(Router.variables)
|
|
141
|
+
|
|
142
|
+
Request.request = request # Add the request object
|
|
143
|
+
Request.headers = headers # Add the headers
|
|
144
|
+
Request.params = request["params"]
|
|
145
|
+
Request.body = request["body"] if "body" in request else None
|
|
146
|
+
Request.files = request["files"] if "files" in request else None
|
|
147
|
+
Request.session = session
|
|
148
|
+
Request.raw_data = request["raw_data"] if "raw_data" in request else None
|
|
149
|
+
Request.raw_request = request["raw_request"] if "raw_request" in request else None
|
|
150
|
+
Request.raw_content = request["raw_content"] if "raw_content" in request else None
|
|
151
|
+
Request.url = url
|
|
152
|
+
Request.transport = request["transport"] if "transport" in request else None
|
|
153
|
+
Request.asgi_response = request["asgi_response"] if "asgi_response" in request else None
|
|
154
|
+
|
|
155
|
+
tina4_python.tina4_current_request = Request
|
|
156
|
+
|
|
157
|
+
old_stdout = sys.stdout # Memorize the default stdout stream
|
|
158
|
+
sys.stdout = buffer = io.StringIO()
|
|
159
|
+
|
|
160
|
+
if "middleware" in route:
|
|
161
|
+
middleware_runner = MiddleWare(route["middleware"]["class"])
|
|
162
|
+
|
|
163
|
+
if "methods" in route["middleware"] and route["middleware"]["methods"] is not None and len(route["middleware"]["methods"]) > 0:
|
|
164
|
+
for method in route["middleware"]["methods"]:
|
|
165
|
+
Request, Response = middleware_runner.call_direct_method(Request, Response, method)
|
|
166
|
+
else:
|
|
167
|
+
Request, Response = await middleware_runner.call_before_methods(Request, Response)
|
|
168
|
+
Request, Response = await middleware_runner.call_any_methods(Request, Response)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
result = await router_response(request=Request, response=Response.Response)
|
|
172
|
+
except Exception as e:
|
|
173
|
+
error_string = tina4_python.global_exception_handler(e)
|
|
174
|
+
if Constant.TINA4_LOG_DEBUG in os.getenv("TINA4_DEBUG_LEVEL") or Constant.TINA4_LOG_ALL in os.getenv("TINA4_DEBUG_LEVEL"):
|
|
175
|
+
html = Template.render_twig_template("errors/500.twig",
|
|
176
|
+
{"server": {"url": url}, "error_message": error_string})
|
|
177
|
+
return Response.Response(html, Constant.HTTP_SERVER_ERROR, Constant.TEXT_HTML)
|
|
178
|
+
else:
|
|
179
|
+
return Response.Response(error_string, Constant.HTTP_SERVER_ERROR, Constant.TEXT_HTML)
|
|
180
|
+
|
|
181
|
+
# we have found a result ... make sure we reflect this if the user didn't actually put the correct http response code in
|
|
182
|
+
if result is not None:
|
|
183
|
+
if result.http_code == Constant.HTTP_NOT_FOUND:
|
|
184
|
+
result.http_code = Constant.HTTP_OK
|
|
185
|
+
|
|
186
|
+
if "middleware" in route:
|
|
187
|
+
middleware_runner = MiddleWare(route["middleware"]["class"])
|
|
188
|
+
|
|
189
|
+
if "methods" in route["middleware"] and route["middleware"]["methods"] is not None and len(route["middleware"]["methods"]) > 0:
|
|
190
|
+
for method in route["middleware"]["methods"]:
|
|
191
|
+
Request, result = middleware_runner.call_direct_method(Request, result, method)
|
|
192
|
+
else:
|
|
193
|
+
Request, result = await middleware_runner.call_after_methods(Request, result)
|
|
194
|
+
Request, result = await middleware_runner.call_any_methods(Request, result)
|
|
195
|
+
|
|
196
|
+
if result is not None:
|
|
197
|
+
result.headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
198
|
+
if "cache" in route and route["cache"] is not None:
|
|
199
|
+
if not route["cache"]["cached"]:
|
|
200
|
+
result.headers["Cache-Control"] = "max-age=1, must-revalidate"
|
|
201
|
+
result.headers["Pragma"] = "no-cache"
|
|
202
|
+
else:
|
|
203
|
+
result.headers["Cache-Control"] = "max-age=" + str(
|
|
204
|
+
route["cache"]["max_age"]) + ", must-revalidate"
|
|
205
|
+
result.headers["Pragma"] = "cache"
|
|
206
|
+
else:
|
|
207
|
+
result.headers["Cache-Control"] = "max-age=-1, must-revalidate"
|
|
208
|
+
result.headers["Pragma"] = "cache"
|
|
209
|
+
|
|
210
|
+
break
|
|
211
|
+
|
|
212
|
+
if result is None and old_stdout is not None:
|
|
213
|
+
result = Response
|
|
214
|
+
result.headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
215
|
+
sys.stdout = old_stdout
|
|
216
|
+
if buffer.getvalue() != "":
|
|
217
|
+
try:
|
|
218
|
+
return Response.Response(json.loads(buffer.getvalue()), Constant.HTTP_OK, Constant.APPLICATION_JSON, result.headers)
|
|
219
|
+
except Exception:
|
|
220
|
+
return Response.Response(buffer.getvalue(), Constant.HTTP_OK, Constant.TEXT_HTML, result.headers)
|
|
221
|
+
else:
|
|
222
|
+
result = Response
|
|
223
|
+
result.http_code = Constant.HTTP_NOT_FOUND
|
|
224
|
+
|
|
225
|
+
# If no route is matched, serve 404
|
|
226
|
+
if result.http_code == Constant.HTTP_NOT_FOUND:
|
|
227
|
+
# Serve twigs if the files exist
|
|
228
|
+
twig_files = []
|
|
229
|
+
if url == "/":
|
|
230
|
+
twig_files.append("index.twig")
|
|
231
|
+
else:
|
|
232
|
+
twig_files.append(url + ".twig")
|
|
233
|
+
twig_files.append(url + "index.twig")
|
|
234
|
+
|
|
235
|
+
# see if we can find the twig file
|
|
236
|
+
for twig_file in twig_files:
|
|
237
|
+
if os.path.isfile(tina4_python.root_path + os.sep + "src" + os.sep + "templates" + os.sep + twig_file):
|
|
238
|
+
Debug("Looking for twig file",
|
|
239
|
+
tina4_python.root_path + os.sep + "src" + os.sep + "templates" + os.sep + twig_file,
|
|
240
|
+
Constant.TINA4_LOG_DEBUG)
|
|
241
|
+
|
|
242
|
+
result.headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
243
|
+
result.headers["Cache-Control"] = "max-age=-1, public"
|
|
244
|
+
result.headers["Pragma"] = "no-cache"
|
|
245
|
+
content = Template.render_twig_template(twig_file, {"request": tina4_python.tina4_current_request})
|
|
246
|
+
if content != "":
|
|
247
|
+
return Response.Response(content, Constant.HTTP_OK, Constant.TEXT_HTML, result.headers)
|
|
248
|
+
|
|
249
|
+
if result.http_code == Constant.HTTP_NOT_FOUND:
|
|
250
|
+
content = Template.render_twig_template(
|
|
251
|
+
"errors/404.twig", {"server": {"url": url}})
|
|
252
|
+
return Response.Response(content, Constant.HTTP_NOT_FOUND, Constant.TEXT_HTML)
|
|
253
|
+
|
|
254
|
+
result.headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
255
|
+
return result
|
|
256
|
+
|
|
257
|
+
@staticmethod
|
|
258
|
+
async def resolve(method, url, request, headers, session):
|
|
259
|
+
url = Router.clean_url(url)
|
|
260
|
+
Debug(method, "Resolving URL: " + url, Constant.TINA4_LOG_DEBUG)
|
|
261
|
+
return await Router.get_result(url, method, request, headers, session)
|
|
262
|
+
|
|
263
|
+
# cleans the url of double slashes
|
|
264
|
+
@staticmethod
|
|
265
|
+
def clean_url(url):
|
|
266
|
+
return url.replace('//', '/')
|
|
267
|
+
|
|
268
|
+
# adds a route to the router
|
|
269
|
+
@staticmethod
|
|
270
|
+
def add(method, route, callback):
|
|
271
|
+
Debug("Adding a route: " + route, Constant.TINA4_LOG_DEBUG)
|
|
272
|
+
if callback not in tina4_python.tina4_routes:
|
|
273
|
+
tina4_python.tina4_routes[callback] = {"route": route, "callback": callback, "method": method,
|
|
274
|
+
"swagger": None, "cached": False}
|
|
275
|
+
else:
|
|
276
|
+
tina4_python.tina4_routes[callback]["route"] = route
|
|
277
|
+
tina4_python.tina4_routes[callback]["callback"] = callback
|
|
278
|
+
tina4_python.tina4_routes[callback]["method"] = method
|
|
279
|
+
|
|
280
|
+
if '{' in route: # store the parameters if needed
|
|
281
|
+
route_variables = re.findall(r'{(.*?)}', route)
|
|
282
|
+
tina4_python.tina4_routes[callback]["params"] = route_variables
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def get(path: str):
|
|
287
|
+
"""
|
|
288
|
+
Get router
|
|
289
|
+
:param arguments:
|
|
290
|
+
:return:
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
def actual_get(callback):
|
|
294
|
+
route_paths = path.split('|')
|
|
295
|
+
for route_path in route_paths:
|
|
296
|
+
Router.add(Constant.TINA4_GET, route_path, callback)
|
|
297
|
+
return callback
|
|
298
|
+
|
|
299
|
+
return actual_get
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def post(path):
|
|
303
|
+
"""
|
|
304
|
+
Post router
|
|
305
|
+
:param path:
|
|
306
|
+
:return:
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
def actual_post(callback):
|
|
310
|
+
route_paths = path.split('|')
|
|
311
|
+
for route_path in route_paths:
|
|
312
|
+
Router.add(Constant.TINA4_POST, route_path, callback)
|
|
313
|
+
return callback
|
|
314
|
+
|
|
315
|
+
return actual_post
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def put(path):
|
|
319
|
+
"""
|
|
320
|
+
Put router
|
|
321
|
+
:param path:
|
|
322
|
+
:return:
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
def actual_put(callback):
|
|
326
|
+
route_paths = path.split('|')
|
|
327
|
+
for route_path in route_paths:
|
|
328
|
+
Router.add(Constant.TINA4_PUT, route_path, callback)
|
|
329
|
+
return callback
|
|
330
|
+
|
|
331
|
+
return actual_put
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def patch(path):
|
|
335
|
+
"""
|
|
336
|
+
Patch router
|
|
337
|
+
:param path:
|
|
338
|
+
:return:
|
|
339
|
+
"""
|
|
340
|
+
|
|
341
|
+
def actual_patch(callback):
|
|
342
|
+
route_paths = path.split('|')
|
|
343
|
+
for route_path in route_paths:
|
|
344
|
+
Router.add(Constant.TINA4_PATCH, route_path, callback)
|
|
345
|
+
return callback
|
|
346
|
+
|
|
347
|
+
return actual_patch
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def delete(path):
|
|
351
|
+
"""
|
|
352
|
+
Delete router
|
|
353
|
+
:param path:
|
|
354
|
+
:return:
|
|
355
|
+
"""
|
|
356
|
+
|
|
357
|
+
def actual_delete(callback):
|
|
358
|
+
route_paths = path.split('|')
|
|
359
|
+
for route_path in route_paths:
|
|
360
|
+
Router.add(Constant.TINA4_DELETE, route_path, callback)
|
|
361
|
+
return callback
|
|
362
|
+
|
|
363
|
+
return actual_delete
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def cached(is_cached, max_age=60):
|
|
367
|
+
"""
|
|
368
|
+
Sets whether the route is cached or not
|
|
369
|
+
:param is_cached:
|
|
370
|
+
:param max_age:
|
|
371
|
+
:return:
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
def actual_cached(callback):
|
|
375
|
+
if callback not in tina4_python.tina4_routes:
|
|
376
|
+
tina4_python.tina4_routes[callback] = {}
|
|
377
|
+
tina4_python.tina4_routes[callback]["cache"] = {"cached": is_cached, "max_age": max_age}
|
|
378
|
+
return callback
|
|
379
|
+
|
|
380
|
+
return actual_cached
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def middleware(middleware, specific_methods=[]):
|
|
384
|
+
"""
|
|
385
|
+
Sets middleware for the route and methods that need to be called
|
|
386
|
+
:param middleware:
|
|
387
|
+
:param specific_methods:
|
|
388
|
+
:return:
|
|
389
|
+
"""
|
|
390
|
+
|
|
391
|
+
def actual_middleware(callback):
|
|
392
|
+
if callback not in tina4_python.tina4_routes:
|
|
393
|
+
tina4_python.tina4_routes[callback] = {}
|
|
394
|
+
tina4_python.tina4_routes[callback]["middleware"] = {"class": middleware, "methods": specific_methods}
|
|
395
|
+
return callback
|
|
396
|
+
|
|
397
|
+
return actual_middleware
|
|
398
|
+
|
|
399
|
+
def secured():
|
|
400
|
+
"""
|
|
401
|
+
Makes a route secure - secured vs secure with swagger
|
|
402
|
+
:return:
|
|
403
|
+
"""
|
|
404
|
+
def actual_secure(callback):
|
|
405
|
+
if callback not in tina4_python.tina4_routes:
|
|
406
|
+
tina4_python.tina4_routes[callback] = {}
|
|
407
|
+
tina4_python.tina4_routes[callback]["secure"] = True
|
|
408
|
+
return callback
|
|
409
|
+
|
|
410
|
+
return actual_secure
|
|
411
|
+
|
|
412
|
+
def noauth():
|
|
413
|
+
"""
|
|
414
|
+
Defines a route with no auth
|
|
415
|
+
:return:
|
|
416
|
+
"""
|
|
417
|
+
def actual_noauth(callback):
|
|
418
|
+
if callback not in tina4_python.tina4_routes:
|
|
419
|
+
tina4_python.tina4_routes[callback] = {}
|
|
420
|
+
tina4_python.tina4_routes[callback]["noauth"] = True
|
|
421
|
+
return callback
|
|
422
|
+
|
|
423
|
+
return actual_noauth
|