tina4-python 0.2.109__tar.gz → 0.2.111__tar.gz
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-0.2.109 → tina4_python-0.2.111}/PKG-INFO +1 -1
- {tina4_python-0.2.109 → tina4_python-0.2.111}/pyproject.toml +1 -1
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Database.py +5 -2
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/ORM.py +5 -5
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Router.py +12 -1
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Session.py +82 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Webserver.py +22 -6
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/__init__.py +3 -2
- {tina4_python-0.2.109 → tina4_python-0.2.111}/.gitignore +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/README.md +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Auth.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Constant.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/DatabaseResult.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/DatabaseTypes.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Debug.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Env.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Localization.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Messages.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/MiddleWare.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Migration.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Queue.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Request.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Response.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/ShellColors.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Swagger.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Template.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/Websocket.py +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/messages.pot +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/css/readme.md +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/images/403.png +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/images/404.png +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/images/500.png +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/images/logo.png +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/images/readme.md +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/js/readme.md +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/js/reconnecting-websocket.js +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/js/tina4helper.js +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/templates/readme.md +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
|
@@ -141,7 +141,6 @@ class Database:
|
|
|
141
141
|
:return: bool : True if table exists, else False
|
|
142
142
|
"""
|
|
143
143
|
|
|
144
|
-
sql = ""
|
|
145
144
|
if self.database_engine == MSSQL:
|
|
146
145
|
sql = "select count(*) as count_table from sys.tables WHERE name = '"+table_name.upper()+"'"
|
|
147
146
|
elif self.database_engine == SQLITE:
|
|
@@ -158,7 +157,11 @@ class Database:
|
|
|
158
157
|
else:
|
|
159
158
|
return False
|
|
160
159
|
|
|
161
|
-
|
|
160
|
+
try:
|
|
161
|
+
record = self.fetch_one(sql)
|
|
162
|
+
except Exception as e:
|
|
163
|
+
raise Exception (f"Error checking if table {table_name} exists: "+str(e))
|
|
164
|
+
|
|
162
165
|
if record:
|
|
163
166
|
if record["count_table"] > 0:
|
|
164
167
|
return True
|
|
@@ -330,16 +330,16 @@ class ORM:
|
|
|
330
330
|
self.__populate_orm({})
|
|
331
331
|
|
|
332
332
|
# Debug("Checking for", self.__table_name__, TINA4_LOG_INFO)
|
|
333
|
-
if self.__dba__:
|
|
333
|
+
if self.__dba__ is not None:
|
|
334
334
|
self.__table_exists = self.__dba__.table_exists(self.__table_name__)
|
|
335
335
|
if not self.__table_exists:
|
|
336
336
|
sql = self.__create_table__(self.__table_name__)
|
|
337
337
|
filename = root_path + os.sep + "migrations" + os.sep + "__" + self.__table_name__ + ".sql"
|
|
338
338
|
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
339
|
-
with open(filename, "w") as f:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
339
|
+
#with open(filename, "w") as f:
|
|
340
|
+
# f.write(sql)
|
|
341
|
+
# f.close()
|
|
342
|
+
Debug.warning("Create Table ? ", sql)
|
|
343
343
|
else:
|
|
344
344
|
self.__table_exists = False
|
|
345
345
|
|
|
@@ -143,6 +143,7 @@ class Router:
|
|
|
143
143
|
Request.headers = headers # Add the headers
|
|
144
144
|
Request.params = request["params"]
|
|
145
145
|
Request.body = request["body"] if "body" in request else None
|
|
146
|
+
Request.files = request["files"] if "files" in request else None
|
|
146
147
|
Request.session = session
|
|
147
148
|
Request.raw_data = request["raw_data"] if "raw_data" in request else None
|
|
148
149
|
Request.raw_request = request["raw_request"] if "raw_request" in request else None
|
|
@@ -151,6 +152,7 @@ class Router:
|
|
|
151
152
|
Request.transport = request["transport"] if "transport" in request else None
|
|
152
153
|
Request.asgi_response = request["asgi_response"] if "asgi_response" in request else None
|
|
153
154
|
|
|
155
|
+
|
|
154
156
|
tina4_python.tina4_current_request = Request
|
|
155
157
|
|
|
156
158
|
old_stdout = sys.stdout # Memorize the default stdout stream
|
|
@@ -166,7 +168,16 @@ class Router:
|
|
|
166
168
|
Request, Response = middleware_runner.call_before_methods(Request, Response)
|
|
167
169
|
Request, Response = middleware_runner.call_any_methods(Request, Response)
|
|
168
170
|
|
|
169
|
-
|
|
171
|
+
try:
|
|
172
|
+
result = await router_response(request=Request, response=Response.Response)
|
|
173
|
+
except Exception as e:
|
|
174
|
+
error_string = tina4_python.global_exception_handler(e)
|
|
175
|
+
if Constant.TINA4_LOG_DEBUG in os.getenv("TINA4_DEBUG_LEVEL") or Constant.TINA4_LOG_ALL in os.getenv("TINA4_DEBUG_LEVEL"):
|
|
176
|
+
html = Template.render_twig_template("errors/500.twig",
|
|
177
|
+
{"server": {"url": url}, "error_message": error_string})
|
|
178
|
+
return Response.Response(html, Constant.HTTP_SERVER_ERROR, Constant.TEXT_HTML)
|
|
179
|
+
else:
|
|
180
|
+
return Response.Response(error_string, Constant.HTTP_SERVER_ERROR, Constant.TEXT_HTML)
|
|
170
181
|
|
|
171
182
|
# we have found a result ... make sure we reflect this if the user didn't actually put the correct http response code in
|
|
172
183
|
if result is not None:
|
|
@@ -179,6 +179,88 @@ class SessionRedisHandler(SessionHandler):
|
|
|
179
179
|
Debug("Session save failure", str(e), Constant.TINA4_LOG_ERROR)
|
|
180
180
|
return False
|
|
181
181
|
|
|
182
|
+
class SessionValkeyHandler(SessionHandler):
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def __init_valkey():
|
|
186
|
+
try:
|
|
187
|
+
valkey = importlib.import_module("valkey")
|
|
188
|
+
except Exception as e:
|
|
189
|
+
Debug("Valkey not installed, install with pip/uv", str(e), Constant.TINA4_LOG_ERROR)
|
|
190
|
+
sys.exit(1)
|
|
191
|
+
|
|
192
|
+
params = {
|
|
193
|
+
"host": os.getenv("TINA4_SESSION_VALKEY_HOST", "localhost"),
|
|
194
|
+
"port": int(os.getenv("TINA4_SESSION_VALKEY_PORT", 6379)),
|
|
195
|
+
"decode_responses": True
|
|
196
|
+
}
|
|
197
|
+
if os.getenv("TINA4_SESSION_VALKEY_SECRET", ""):
|
|
198
|
+
params["password"] = os.getenv("TINA4_SESSION_VALKEY_SECRET", "")
|
|
199
|
+
params["username"] = os.getenv("TINA4_SESSION_VALKEY_USER", "default")
|
|
200
|
+
|
|
201
|
+
if os.getenv("TINA4_SESSION_VALKEY_SSL", "False").upper() == "TRUE":
|
|
202
|
+
params["ssl"] = True
|
|
203
|
+
|
|
204
|
+
valkey_instance = valkey.Valkey(**params)
|
|
205
|
+
|
|
206
|
+
return valkey_instance
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
Session Valkey Handler
|
|
210
|
+
"""
|
|
211
|
+
@staticmethod
|
|
212
|
+
def load(session, _hash):
|
|
213
|
+
"""
|
|
214
|
+
Loads the Valkey session
|
|
215
|
+
:param session:
|
|
216
|
+
:param _hash:
|
|
217
|
+
:return:
|
|
218
|
+
"""
|
|
219
|
+
try:
|
|
220
|
+
session.session_hash = _hash
|
|
221
|
+
r = SessionValkeyHandler.__init_valkey()
|
|
222
|
+
token = r.get(_hash)
|
|
223
|
+
if tina4_python.tina4_auth.valid(token):
|
|
224
|
+
payload = tina4_python.tina4_auth.get_payload(token)
|
|
225
|
+
for key in payload:
|
|
226
|
+
if key != "expires":
|
|
227
|
+
session.set(key, payload[key])
|
|
228
|
+
else:
|
|
229
|
+
Debug("Session expired, starting a new one", Constant.TINA4_LOG_DEBUG)
|
|
230
|
+
session.start(_hash)
|
|
231
|
+
except Exception:
|
|
232
|
+
Debug("Valkey not available, sessions will fail", Constant.TINA4_LOG_ERROR)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
def close(session):
|
|
237
|
+
"""
|
|
238
|
+
Closes the Valkey session
|
|
239
|
+
:param session:
|
|
240
|
+
:return:
|
|
241
|
+
"""
|
|
242
|
+
r = SessionValkeyHandler.__init_valkey()
|
|
243
|
+
try:
|
|
244
|
+
r.set(session.session_hash, "")
|
|
245
|
+
return True
|
|
246
|
+
except Exception:
|
|
247
|
+
return False
|
|
248
|
+
|
|
249
|
+
@staticmethod
|
|
250
|
+
def save(session):
|
|
251
|
+
"""
|
|
252
|
+
Saves the Valkey session
|
|
253
|
+
:param session:
|
|
254
|
+
:return:
|
|
255
|
+
"""
|
|
256
|
+
r = SessionValkeyHandler.__init_valkey()
|
|
257
|
+
try:
|
|
258
|
+
token = tina4_python.tina4_auth.get_token(payload_data=session.session_values)
|
|
259
|
+
r.set(session.session_hash, token)
|
|
260
|
+
return True
|
|
261
|
+
except Exception as e:
|
|
262
|
+
Debug("Session save failure", str(e), Constant.TINA4_LOG_ERROR)
|
|
263
|
+
return False
|
|
182
264
|
|
|
183
265
|
class Session:
|
|
184
266
|
|
|
@@ -64,6 +64,7 @@ class Webserver:
|
|
|
64
64
|
content = b"\r\n" + content
|
|
65
65
|
data_array = content.split(str.encode(boundary))
|
|
66
66
|
body = {}
|
|
67
|
+
files = {}
|
|
67
68
|
for data in data_array:
|
|
68
69
|
data = data.split(b"\r\n\r\n")
|
|
69
70
|
data_names = data[0].decode("utf-8").split("; ")
|
|
@@ -91,10 +92,24 @@ class Webserver:
|
|
|
91
92
|
if "Content-Type" in meta_data:
|
|
92
93
|
content_type = meta_data["Content-Type"]
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
|
|
96
|
+
if key_name in body:
|
|
97
|
+
body[key_name] = [body[key_name]]
|
|
98
|
+
body[key_name].append({"file_name": file_name, "content_type": content_type,"content": base64.encodebytes(data_value).decode("utf-8").replace(
|
|
99
|
+
"\n", "")})
|
|
100
|
+
else:
|
|
101
|
+
body[key_name] = {"file_name": file_name, "content_type": content_type,"content": base64.encodebytes(data_value).decode("utf-8").replace(
|
|
102
|
+
"\n", "")}
|
|
103
|
+
|
|
104
|
+
if key_name in files:
|
|
105
|
+
files[key_name] = [files[key_name]]
|
|
106
|
+
files[key_name].append({"file_name": file_name, "content_type": content_type,"content": base64.encodebytes(data_value).decode("utf-8").replace(
|
|
107
|
+
"\n", "")})
|
|
108
|
+
else:
|
|
109
|
+
files[key_name] = {"file_name": file_name, "content_type": content_type,"content": base64.encodebytes(data_value).decode("utf-8").replace(
|
|
110
|
+
"\n", "")}
|
|
111
|
+
|
|
112
|
+
return body, files
|
|
98
113
|
|
|
99
114
|
return {"data": base64.encodebytes(content).decode("utf-8").replace("\n", "")}
|
|
100
115
|
|
|
@@ -181,11 +196,12 @@ class Webserver:
|
|
|
181
196
|
|
|
182
197
|
content_length = await self.get_content_length()
|
|
183
198
|
if method != Constant.TINA4_GET:
|
|
184
|
-
body = await self.get_content_body(content_length)
|
|
199
|
+
body, files = await self.get_content_body(content_length)
|
|
185
200
|
else:
|
|
186
201
|
body = None
|
|
202
|
+
files = None
|
|
187
203
|
|
|
188
|
-
request = {"params": params, "body": body, "raw_data": self.request, "url": self.path, "session": self.session,
|
|
204
|
+
request = {"params": params, "body": body, "files": files, "raw_data": self.request, "url": self.path, "session": self.session,
|
|
189
205
|
"headers": self.lowercase_headers, "raw_request": self.request_raw, "raw_content": self.content_raw,
|
|
190
206
|
"transport": transport, "asgi_response": asgi_response}
|
|
191
207
|
|
|
@@ -82,7 +82,7 @@ def global_exception_handler(exception):
|
|
|
82
82
|
or debug_level in os.getenv("TINA4_DEBUG_LEVEL", [Constant.TINA4_LOG_ALL])):
|
|
83
83
|
pass
|
|
84
84
|
else:
|
|
85
|
-
error_string = ""
|
|
85
|
+
error_string = "An exception happened"
|
|
86
86
|
return error_string
|
|
87
87
|
|
|
88
88
|
def start_in_thread(target, exception_hook=None):
|
|
@@ -279,7 +279,6 @@ async def app(scope, receive, send):
|
|
|
279
279
|
webserver.content_raw = b""
|
|
280
280
|
webserver.content_length = parsed_headers_lowercase["content-length"]
|
|
281
281
|
webserver.router_handler = Router()
|
|
282
|
-
webserver.session = Session
|
|
283
282
|
|
|
284
283
|
cookie_list = {}
|
|
285
284
|
if "cookie" in webserver.lowercase_headers:
|
|
@@ -340,6 +339,7 @@ def webserver(host_name, port):
|
|
|
340
339
|
:return:
|
|
341
340
|
"""
|
|
342
341
|
if os.getenv('TINA4_DEFAULT_WEBSERVER', 'FALSE').upper() == 'TRUE':
|
|
342
|
+
Debug("Using default webserver", Constant.TINA4_LOG_INFO)
|
|
343
343
|
# runs the built-in webserver (websockets) don't work on windows
|
|
344
344
|
web_server = Webserver(host_name, int(port)) # HTTPServer((host_name, int(port)), Webserver)
|
|
345
345
|
web_server.router_handler = Router()
|
|
@@ -354,6 +354,7 @@ def webserver(host_name, port):
|
|
|
354
354
|
web_server.server_close()
|
|
355
355
|
else:
|
|
356
356
|
# Runs a hyper corn server
|
|
357
|
+
Debug("Using hypercorn webserver", Constant.TINA4_LOG_INFO)
|
|
357
358
|
try:
|
|
358
359
|
from hypercorn.config import Config
|
|
359
360
|
from hypercorn.asyncio import serve
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/js/reconnecting-websocket.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/public/swagger/oauth2-redirect.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.109 → tina4_python-0.2.111}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|