tina4-python 0.2.138__tar.gz → 0.2.140__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.138 → tina4_python-0.2.140}/.gitignore +1 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/PKG-INFO +5 -9
- {tina4_python-0.2.138 → tina4_python-0.2.140}/README.md +4 -8
- {tina4_python-0.2.138 → tina4_python-0.2.140}/pyproject.toml +64 -63
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Constant.py +3 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/ORM.py +5 -1
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Request.py +3 -1
- tina4_python-0.2.140/tina4_python/Response.py +209 -0
- tina4_python-0.2.140/tina4_python/Router.py +672 -0
- tina4_python-0.2.140/tina4_python/Swagger.py +358 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Template.py +32 -0
- tina4_python-0.2.140/tina4_python/WSDL.py +438 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Webserver.py +23 -11
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Websocket.py +1 -3
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/__init__.py +87 -9
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/cli.py +18 -7
- tina4_python-0.2.138/tina4_python/Response.py +0 -120
- tina4_python-0.2.138/tina4_python/Router.py +0 -442
- tina4_python-0.2.138/tina4_python/Swagger.py +0 -228
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Api.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Auth.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/CRUD.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Database.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/DatabaseResult.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/DatabaseTypes.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Debug.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Env.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/FieldTypes.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Localization.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Messages.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/MiddleWare.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Migration.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Queue.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/Session.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/ShellColors.py +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/messages.pot +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/css/readme.md +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/images/403.png +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/images/404.png +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/images/500.png +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/images/logo.png +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/images/readme.md +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/js/readme.md +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/js/reconnecting-websocket.js +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/js/tina4helper.js +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/templates/readme.md +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.138 → tina4_python-0.2.140}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tina4-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.140
|
|
4
4
|
Summary: Tina4Python - This is not another framework for Python
|
|
5
5
|
Author-email: Andre van Zuydam <andrevanzuydam@gmail.com>
|
|
6
6
|
Requires-Python: <4.0,>=3.12
|
|
@@ -21,19 +21,15 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
|
|
22
22
|
Laravel joy. Python speed. 10× less code.
|
|
23
23
|
|
|
24
|
+
## Quickstart
|
|
24
25
|
```bash
|
|
25
26
|
pip install tina4_python
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
That’s it. Save the code above as `app.py`, run it, and you have a fully working Tina4 Python web server.
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pip install tina4-python
|
|
27
|
+
tina4 init my_project
|
|
28
|
+
cd my_project
|
|
32
29
|
python app.py
|
|
33
|
-
# → http://localhost:7145
|
|
34
30
|
```
|
|
35
31
|
|
|
36
|
-
You just built your first Tina4 app — zero configuration, zero classes, zero boilerplate
|
|
32
|
+
You've just built your first Tina4 app — zero configuration, zero classes, zero boilerplate!
|
|
37
33
|
|
|
38
34
|
## Features
|
|
39
35
|
|
|
@@ -2,19 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Laravel joy. Python speed. 10× less code.
|
|
4
4
|
|
|
5
|
+
## Quickstart
|
|
5
6
|
```bash
|
|
6
7
|
pip install tina4_python
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
That’s it. Save the code above as `app.py`, run it, and you have a fully working Tina4 Python web server.
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
pip install tina4-python
|
|
8
|
+
tina4 init my_project
|
|
9
|
+
cd my_project
|
|
13
10
|
python app.py
|
|
14
|
-
# → http://localhost:7145
|
|
15
11
|
```
|
|
16
12
|
|
|
17
|
-
You just built your first Tina4 app — zero configuration, zero classes, zero boilerplate
|
|
13
|
+
You've just built your first Tina4 app — zero configuration, zero classes, zero boilerplate!
|
|
18
14
|
|
|
19
15
|
## Features
|
|
20
16
|
|
|
@@ -1,63 +1,64 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "tina4-python"
|
|
3
|
-
version = "0.2.
|
|
4
|
-
description = "Tina4Python - This is not another framework for Python"
|
|
5
|
-
authors = [
|
|
6
|
-
{name = "Andre van Zuydam",email = "andrevanzuydam@gmail.com"}
|
|
7
|
-
]
|
|
8
|
-
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.12,<4.0"
|
|
10
|
-
dependencies = [
|
|
11
|
-
"jinja2>=3.1.5,<4.0.0",
|
|
12
|
-
"libsass (>=0.23.0,<0.24.0)",
|
|
13
|
-
"python-dotenv (>=1.0.1,<2.0.0)",
|
|
14
|
-
"pyjwt (>=2.10.1,<3.0.0)",
|
|
15
|
-
"cryptography (>=44.0.0,<45.0.0)",
|
|
16
|
-
"watchdog (>=6.0.0,<7.0.0)",
|
|
17
|
-
"bcrypt (>=4.2.1,<5.0.0)",
|
|
18
|
-
"litequeue (>=0.9,<0.10)",
|
|
19
|
-
"simple-websocket (>=1.1.0,<2.0.0)",
|
|
20
|
-
"asyncer>=0.0.8",
|
|
21
|
-
"hypercorn>=0.18.0",
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
[dependency-groups]
|
|
25
|
-
dev = [
|
|
26
|
-
"flake8>=7.2.0",
|
|
27
|
-
"jurigged>=0.6.0",
|
|
28
|
-
"mkdocs>=1.6.1",
|
|
29
|
-
"mysql-connector-python>=9.3.0",
|
|
30
|
-
"psycopg2-binary>=2.9.10",
|
|
31
|
-
"pydoc-markdown>=4.8.2",
|
|
32
|
-
"pytest>=8.3.5",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
[project]
|
|
2
|
+
name = "tina4-python"
|
|
3
|
+
version = "0.2.140"
|
|
4
|
+
description = "Tina4Python - This is not another framework for Python"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "Andre van Zuydam",email = "andrevanzuydam@gmail.com"}
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.12,<4.0"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"jinja2>=3.1.5,<4.0.0",
|
|
12
|
+
"libsass (>=0.23.0,<0.24.0)",
|
|
13
|
+
"python-dotenv (>=1.0.1,<2.0.0)",
|
|
14
|
+
"pyjwt (>=2.10.1,<3.0.0)",
|
|
15
|
+
"cryptography (>=44.0.0,<45.0.0)",
|
|
16
|
+
"watchdog (>=6.0.0,<7.0.0)",
|
|
17
|
+
"bcrypt (>=4.2.1,<5.0.0)",
|
|
18
|
+
"litequeue (>=0.9,<0.10)",
|
|
19
|
+
"simple-websocket (>=1.1.0,<2.0.0)",
|
|
20
|
+
"asyncer>=0.0.8",
|
|
21
|
+
"hypercorn>=0.18.0",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"flake8>=7.2.0",
|
|
27
|
+
"jurigged>=0.6.0",
|
|
28
|
+
"mkdocs>=1.6.1",
|
|
29
|
+
"mysql-connector-python>=9.3.0",
|
|
30
|
+
"psycopg2-binary>=2.9.10",
|
|
31
|
+
"pydoc-markdown>=4.8.2",
|
|
32
|
+
"pytest>=8.3.5",
|
|
33
|
+
"pytest-asyncio>=1.3.0",
|
|
34
|
+
"python-keycloak>=5.8.1",
|
|
35
|
+
"ruff>=0.11.9",
|
|
36
|
+
"safety>=3.5.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["hatchling"]
|
|
41
|
+
build-backend = "hatchling.build"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build]
|
|
44
|
+
include = [
|
|
45
|
+
"tina4_python/**/*"
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
tina4 = "tina4_python.cli:main"
|
|
50
|
+
|
|
51
|
+
[[tool.pydoc-markdown.loaders]]
|
|
52
|
+
type = "python"
|
|
53
|
+
search_path = [ "./tina4_python" ]
|
|
54
|
+
|
|
55
|
+
[tool.pydoc-markdown.renderer]
|
|
56
|
+
type = "mkdocs"
|
|
57
|
+
site_name= "Tina4Python"
|
|
58
|
+
|
|
59
|
+
[[tool.pydoc-markdown.renderer.pages]]
|
|
60
|
+
title = "API Documentation"
|
|
61
|
+
name = "index"
|
|
62
|
+
|
|
63
|
+
contents = [ "*" ]
|
|
64
|
+
|
|
@@ -71,6 +71,8 @@ LOOKUP_HTTP_CODE = {
|
|
|
71
71
|
HTTP_NO_CONTENT: "No Content",
|
|
72
72
|
HTTP_PARTIAL_CONTENT: "Partial Content",
|
|
73
73
|
HTTP_REDIRECT: "Redirect",
|
|
74
|
+
HTTP_REDIRECT_MOVED: "Redirect Moved",
|
|
75
|
+
HTTP_REDIRECT_OTHER: "Redirect Other",
|
|
74
76
|
HTTP_BAD_REQUEST: "Bad Request",
|
|
75
77
|
HTTP_UNAUTHORIZED: "Unauthorized",
|
|
76
78
|
HTTP_FORBIDDEN: "Forbidden",
|
|
@@ -85,6 +87,7 @@ LOOKUP_HTTP_CODE = {
|
|
|
85
87
|
TEXT_HTML = "text/html" #: HTML documents and templates
|
|
86
88
|
TEXT_CSS = "text/css" #: Cascading Style Sheets
|
|
87
89
|
TEXT_PLAIN = "text/plain" #: Plain text files
|
|
90
|
+
TEXT_JAVASCRIPT = "text/javascript" #: Javascript files
|
|
88
91
|
APPLICATION_JSON = "application/json" #: JSON API responses
|
|
89
92
|
APPLICATION_XML = "application/xml" #: XML data (RSS, SOAP, etc.)
|
|
90
93
|
|
|
@@ -197,6 +197,9 @@ class ORM:
|
|
|
197
197
|
return self.to_json()
|
|
198
198
|
|
|
199
199
|
def __create_table__(self, table_name, execute=False):
|
|
200
|
+
if self.__dba__ is None:
|
|
201
|
+
Debug.warning("Create Table", table_name, "database not assigned to ORM , use orm(dba)")
|
|
202
|
+
return False
|
|
200
203
|
sql = "create table " + table_name + " ("
|
|
201
204
|
counter = 0
|
|
202
205
|
for field, field_definition in self.__field_definitions__.items():
|
|
@@ -213,6 +216,7 @@ class ORM:
|
|
|
213
216
|
|
|
214
217
|
if execute:
|
|
215
218
|
self.__dba__.execute(sql)
|
|
219
|
+
return None
|
|
216
220
|
else:
|
|
217
221
|
return sql
|
|
218
222
|
|
|
@@ -221,7 +225,7 @@ class ORM:
|
|
|
221
225
|
Creates the table for the ORM structure
|
|
222
226
|
:return:
|
|
223
227
|
"""
|
|
224
|
-
self.
|
|
228
|
+
return self.__create_table__(self.__table_name__, True)
|
|
225
229
|
|
|
226
230
|
def __build_sql(self, column_names="*", join="", filter="", group_by="", having="", order_by=""):
|
|
227
231
|
"""
|
|
@@ -0,0 +1,209 @@
|
|
|
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 os
|
|
8
|
+
import json
|
|
9
|
+
import inspect
|
|
10
|
+
from datetime import datetime, date
|
|
11
|
+
from types import ModuleType
|
|
12
|
+
from tina4_python import Constant
|
|
13
|
+
from tina4_python import DatabaseResult
|
|
14
|
+
from tina4_python.ORM import ORM
|
|
15
|
+
from tina4_python.Template import Template
|
|
16
|
+
|
|
17
|
+
headers = {}
|
|
18
|
+
content = ""
|
|
19
|
+
http_code = Constant.HTTP_OK
|
|
20
|
+
content_type = Constant.TEXT_HTML
|
|
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) and http_code_in == Constant.HTTP_OK:
|
|
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, http_code_in=Constant.HTTP_REDIRECT):
|
|
86
|
+
"""
|
|
87
|
+
Redirects a request to redirect_url
|
|
88
|
+
:param http_code_in:
|
|
89
|
+
:param redirect_url:
|
|
90
|
+
:return:
|
|
91
|
+
"""
|
|
92
|
+
global headers
|
|
93
|
+
global content
|
|
94
|
+
global http_code
|
|
95
|
+
global content_type
|
|
96
|
+
headers = {}
|
|
97
|
+
http_code = http_code_in
|
|
98
|
+
headers["Location"] = redirect_url
|
|
99
|
+
content = "Redirecting..."
|
|
100
|
+
content_type = Constant.TEXT_HTML
|
|
101
|
+
return Response("Redirecting...", http_code, content_type, headers)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def render(template_name, data=None):
|
|
106
|
+
global content, content_type, http_code
|
|
107
|
+
http_code = Constant.HTTP_OK
|
|
108
|
+
content_type = Constant.TEXT_HTML
|
|
109
|
+
|
|
110
|
+
return Response(Template.render(template_name, data=data), http_code, content_type)
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def file(file_path: str, root_path: str = "src/public"):
|
|
114
|
+
"""
|
|
115
|
+
Serve a static file from the file system.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
file_path (str): The requested file path (e.g., "images/logo.png", "css/style.css")
|
|
119
|
+
root_path (str): Base directory to serve files from (defaults to src/public)
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Response: A properly configured Response object with file content and correct MIME type
|
|
123
|
+
"""
|
|
124
|
+
global content, content_type, http_code
|
|
125
|
+
|
|
126
|
+
# Resolve full path and prevent directory traversal
|
|
127
|
+
full_path = os.path.abspath(os.path.join(root_path, file_path.lstrip("/")))
|
|
128
|
+
|
|
129
|
+
# Security: ensure the requested file is inside the root_path
|
|
130
|
+
if not full_path.startswith(os.path.abspath(root_path)):
|
|
131
|
+
http_code = Constant.HTTP_FORBIDDEN
|
|
132
|
+
content_type = Constant.TEXT_PLAIN
|
|
133
|
+
content = "403 - Forbidden"
|
|
134
|
+
return Response(content, http_code, content_type)
|
|
135
|
+
|
|
136
|
+
# Check if file exists
|
|
137
|
+
if not os.path.isfile(full_path):
|
|
138
|
+
http_code = Constant.HTTP_NOT_FOUND
|
|
139
|
+
content_type = Constant.TEXT_PLAIN
|
|
140
|
+
content = "404 - File Not Found"
|
|
141
|
+
return Response(content, http_code, content_type)
|
|
142
|
+
|
|
143
|
+
# Determine MIME type
|
|
144
|
+
extension = os.path.splitext(file_path)[1].lower()
|
|
145
|
+
mime_map = {
|
|
146
|
+
".html": Constant.TEXT_HTML,
|
|
147
|
+
".css": Constant.TEXT_CSS,
|
|
148
|
+
".js": Constant.TEXT_JAVASCRIPT,
|
|
149
|
+
".json": Constant.APPLICATION_JSON,
|
|
150
|
+
".png": "image/png",
|
|
151
|
+
".jpg": "image/jpeg",
|
|
152
|
+
".jpeg": "image/jpeg",
|
|
153
|
+
".gif": "image/gif",
|
|
154
|
+
".svg": "image/svg+xml",
|
|
155
|
+
".ico": "image/x-icon",
|
|
156
|
+
".woff": "font/woff",
|
|
157
|
+
".woff2":"font/woff2",
|
|
158
|
+
".ttf": "font/ttf",
|
|
159
|
+
".pdf": "application/pdf",
|
|
160
|
+
".txt": Constant.TEXT_PLAIN,
|
|
161
|
+
}
|
|
162
|
+
content_type = mime_map.get(extension, "application/octet-stream")
|
|
163
|
+
|
|
164
|
+
# Read file content (binary for non-text, text for text)
|
|
165
|
+
try:
|
|
166
|
+
if content_type.startswith("text/") or content_type in ["application/json", "image/svg+xml"]:
|
|
167
|
+
with open(full_path, "r", encoding="utf-8") as f:
|
|
168
|
+
content = f.read()
|
|
169
|
+
else:
|
|
170
|
+
with open(full_path, "rb") as f:
|
|
171
|
+
content = f.read()
|
|
172
|
+
except Exception as e:
|
|
173
|
+
http_code = Constant.HTTP_BAD_REQUEST
|
|
174
|
+
content_type = Constant.TEXT_PLAIN
|
|
175
|
+
content = f"Error reading file: {str(e)}"
|
|
176
|
+
return Response(content, http_code, content_type)
|
|
177
|
+
|
|
178
|
+
http_code = Constant.HTTP_OK
|
|
179
|
+
return Response(content, http_code, content_type)
|
|
180
|
+
|
|
181
|
+
@staticmethod
|
|
182
|
+
def add_header(key, value):
|
|
183
|
+
"""
|
|
184
|
+
Adds a header for the response
|
|
185
|
+
:param key:
|
|
186
|
+
:param value:
|
|
187
|
+
:return:
|
|
188
|
+
"""
|
|
189
|
+
global headers
|
|
190
|
+
headers[key] = value
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
def wsdl(wsdl_instance):
|
|
194
|
+
"""
|
|
195
|
+
Sets the response for a WSDL/SOAP handler.
|
|
196
|
+
|
|
197
|
+
This method handles WSDL and SOAP responses by calling the handle method of the provided
|
|
198
|
+
WSDL instance, setting the content type to 'text/xml', and updating the response content
|
|
199
|
+
and status code accordingly.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
wsdl_instance: Instance of a WSDL subclass (e.g., CIS(request)).
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
Self (the Response object) with updated content, headers, and status.
|
|
206
|
+
"""
|
|
207
|
+
xml_content = wsdl_instance.handle()
|
|
208
|
+
|
|
209
|
+
return Response(xml_content, Constant.HTTP_OK, Constant.APPLICATION_XML)
|