tina4-python 0.2.126__tar.gz → 0.2.128__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.126 → tina4_python-0.2.128}/PKG-INFO +1 -1
- {tina4_python-0.2.126 → tina4_python-0.2.128}/pyproject.toml +1 -1
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/CRUD.py +70 -9
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Database.py +4 -0
- tina4_python-0.2.128/tina4_python/DatabaseResult.py +67 -0
- tina4_python-0.2.126/tina4_python/DatabaseResult.py +0 -116
- {tina4_python-0.2.126 → tina4_python-0.2.128}/.gitignore +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/README.md +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Auth.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Constant.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/DatabaseTypes.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Debug.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Env.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Localization.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Messages.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/MiddleWare.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Migration.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/ORM.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Queue.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Request.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Response.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Router.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Session.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/ShellColors.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Swagger.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Template.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Webserver.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/Websocket.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/__init__.py +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/messages.pot +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/css/readme.md +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/images/403.png +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/images/404.png +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/images/500.png +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/images/logo.png +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/images/readme.md +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/js/readme.md +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/js/reconnecting-websocket.js +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/js/tina4helper.js +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/templates/readme.md +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import datetime
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
|
|
1
5
|
from tina4_python.Debug import Debug
|
|
2
6
|
import re
|
|
3
7
|
from tina4_python.Template import Template
|
|
@@ -6,6 +10,7 @@ from tina4_python.Router import Router
|
|
|
6
10
|
import tina4_python
|
|
7
11
|
import os
|
|
8
12
|
import shutil
|
|
13
|
+
import json
|
|
9
14
|
|
|
10
15
|
class CRUD:
|
|
11
16
|
|
|
@@ -17,8 +22,7 @@ class CRUD:
|
|
|
17
22
|
self.search_columns = []
|
|
18
23
|
self.total_count = 0
|
|
19
24
|
self.sql = None
|
|
20
|
-
|
|
21
|
-
import re
|
|
25
|
+
self.error = ""
|
|
22
26
|
|
|
23
27
|
def strip_sql_pagination(self, sql: str) -> str:
|
|
24
28
|
"""
|
|
@@ -139,7 +143,6 @@ class CRUD:
|
|
|
139
143
|
def to_crud(self, request, options=None):
|
|
140
144
|
table_name = self.get_table_name(self.sql)
|
|
141
145
|
table_nice_name = Template.get_nice_label(table_name)
|
|
142
|
-
twig_file = self.ensure_crud_template(table_name + ".twig")
|
|
143
146
|
|
|
144
147
|
if options is None:
|
|
145
148
|
options = {}
|
|
@@ -159,6 +162,13 @@ class CRUD:
|
|
|
159
162
|
if "search_columns" in options:
|
|
160
163
|
self.search_columns = options["search_columns"]
|
|
161
164
|
|
|
165
|
+
crud_name = table_name
|
|
166
|
+
if "name" in options:
|
|
167
|
+
crud_name = options["name"]
|
|
168
|
+
|
|
169
|
+
twig_file = self.ensure_crud_template(crud_name + ".twig")
|
|
170
|
+
|
|
171
|
+
|
|
162
172
|
async def get_record(request, response):
|
|
163
173
|
limit = int(request.params.get("limit", options.get("limit", 10)))
|
|
164
174
|
offset = int(request.params.get("offset", options.get("offset", 0)))
|
|
@@ -209,21 +219,72 @@ class CRUD:
|
|
|
209
219
|
self.dba.commit()
|
|
210
220
|
return response({"message": f"<script>showMessage('{table_nice_name} Record deleted');</script>"}, HTTP_OK, APPLICATION_JSON)
|
|
211
221
|
|
|
212
|
-
Router.add(TINA4_GET, os.path.join(request.url,
|
|
213
|
-
Router.add(TINA4_POST, os.path.join(request.url,
|
|
214
|
-
Router.add(TINA4_POST, os.path.join(request.url,
|
|
215
|
-
Router.add(TINA4_DELETE, os.path.join(request.url,
|
|
222
|
+
Router.add(TINA4_GET, os.path.join(request.url, crud_name).replace("\\", "/"), get_record)
|
|
223
|
+
Router.add(TINA4_POST, os.path.join(request.url, crud_name).replace("\\", "/"), post_record)
|
|
224
|
+
Router.add(TINA4_POST, os.path.join(request.url, crud_name, "{"+options["primary_key"]+"}").replace("\\", "/"), update_record)
|
|
225
|
+
Router.add(TINA4_DELETE, os.path.join(request.url, crud_name, "{"+options["primary_key"]+"}").replace("\\", "/"), delete_record)
|
|
216
226
|
|
|
217
227
|
fields = []
|
|
218
228
|
for column in self.columns:
|
|
219
229
|
fields.append({"name": column, "label": Template.get_nice_label(column)})
|
|
220
230
|
|
|
231
|
+
|
|
221
232
|
html = Template.render(twig_file.replace(os.path.join(tina4_python.root_path, "src", "templates"), "").replace("\\", "/"),
|
|
222
|
-
{"columns": fields, "records": self.
|
|
223
|
-
"table_name":
|
|
233
|
+
{"columns": fields, "records": self.to_array(),
|
|
234
|
+
"table_name": crud_name,
|
|
224
235
|
"total_records": self.total_count,
|
|
225
236
|
"options": options})
|
|
226
237
|
|
|
227
238
|
return html
|
|
228
239
|
|
|
229
240
|
|
|
241
|
+
def to_array(self, _filter=None):
|
|
242
|
+
"""
|
|
243
|
+
Creates an array or list of the items
|
|
244
|
+
:return:
|
|
245
|
+
"""
|
|
246
|
+
if self.error is not None:
|
|
247
|
+
return {"error": self.error}
|
|
248
|
+
elif len(self.records) > 0:
|
|
249
|
+
# check all the records - if we get bytes we base64encode them for the json to work
|
|
250
|
+
json_records = []
|
|
251
|
+
for record in self.records:
|
|
252
|
+
json_record = {}
|
|
253
|
+
for key in record:
|
|
254
|
+
if isinstance(record[key], Decimal):
|
|
255
|
+
json_record[key] = float(record[key])
|
|
256
|
+
elif isinstance(record[key], (datetime.date, datetime.datetime)):
|
|
257
|
+
json_record[key] = record[key].isoformat()
|
|
258
|
+
elif isinstance(record[key], memoryview):
|
|
259
|
+
json_record[key] = base64.b64encode(record[key].tobytes()).decode('utf-8')
|
|
260
|
+
elif isinstance(record[key], bytes):
|
|
261
|
+
json_record[key] = base64.b64encode(record[key]).decode('utf-8')
|
|
262
|
+
else:
|
|
263
|
+
json_record[key] = record[key]
|
|
264
|
+
|
|
265
|
+
if _filter is not None:
|
|
266
|
+
json_record = _filter(json_record)
|
|
267
|
+
|
|
268
|
+
json_records.append(json_record)
|
|
269
|
+
|
|
270
|
+
return json_records
|
|
271
|
+
else:
|
|
272
|
+
return []
|
|
273
|
+
|
|
274
|
+
def to_list(self, _filter=None):
|
|
275
|
+
return self.to_array(_filter)
|
|
276
|
+
|
|
277
|
+
def to_json(self, _filter=None):
|
|
278
|
+
return json.dumps(self.to_array(_filter))
|
|
279
|
+
|
|
280
|
+
def __iter__(self):
|
|
281
|
+
return iter(self.to_array())
|
|
282
|
+
|
|
283
|
+
def __getitem__(self, item):
|
|
284
|
+
if item < len(self.records):
|
|
285
|
+
return self.records[item]
|
|
286
|
+
else:
|
|
287
|
+
return {}
|
|
288
|
+
|
|
289
|
+
def __str__(self):
|
|
290
|
+
return self.to_json()
|
|
@@ -10,6 +10,8 @@ import sys
|
|
|
10
10
|
import importlib
|
|
11
11
|
import datetime
|
|
12
12
|
import json
|
|
13
|
+
from decimal import Decimal
|
|
14
|
+
|
|
13
15
|
from tina4_python import Debug, Constant
|
|
14
16
|
from tina4_python.Constant import TINA4_LOG_ERROR
|
|
15
17
|
from tina4_python.DatabaseResult import DatabaseResult
|
|
@@ -351,6 +353,8 @@ class Database:
|
|
|
351
353
|
if record.error is None and record.count == 1:
|
|
352
354
|
data = {}
|
|
353
355
|
for key in record.records[0]:
|
|
356
|
+
if isinstance(record.records[0][key], Decimal):
|
|
357
|
+
data[key] = float(record.records[0][key])
|
|
354
358
|
if isinstance(record.records[0][key], (datetime.date, datetime.datetime)):
|
|
355
359
|
data[key] = record.records[0][key].isoformat()
|
|
356
360
|
if isinstance(record.records[0][key], bytes):
|
|
@@ -0,0 +1,67 @@
|
|
|
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 base64
|
|
8
|
+
import json
|
|
9
|
+
import datetime
|
|
10
|
+
from decimal import Decimal
|
|
11
|
+
from tina4_python.CRUD import CRUD
|
|
12
|
+
class DatabaseResult(CRUD):
|
|
13
|
+
def __init__(self, _records=None, _columns=None, _error=None, count=None, limit=None, skip=None, sql=None, dba=None):
|
|
14
|
+
"""
|
|
15
|
+
DatabaseResult constructor
|
|
16
|
+
:param _records:
|
|
17
|
+
:param _columns:
|
|
18
|
+
:param _error:
|
|
19
|
+
:param count:
|
|
20
|
+
:param limit:
|
|
21
|
+
:param skip:
|
|
22
|
+
"""
|
|
23
|
+
super().__init__()
|
|
24
|
+
if count is not None:
|
|
25
|
+
self.total_count = count
|
|
26
|
+
else:
|
|
27
|
+
self.total_count = 0
|
|
28
|
+
|
|
29
|
+
if limit is not None:
|
|
30
|
+
self.limit = limit
|
|
31
|
+
else:
|
|
32
|
+
self.limit = 0
|
|
33
|
+
|
|
34
|
+
if skip is not None:
|
|
35
|
+
self.skip = skip
|
|
36
|
+
else:
|
|
37
|
+
self.skip = 0
|
|
38
|
+
|
|
39
|
+
if _records is not None:
|
|
40
|
+
self.records = _records
|
|
41
|
+
else:
|
|
42
|
+
self.records = []
|
|
43
|
+
|
|
44
|
+
self.count = len(self.records)
|
|
45
|
+
|
|
46
|
+
if _columns is not None:
|
|
47
|
+
self.columns = _columns
|
|
48
|
+
else:
|
|
49
|
+
self.columns = []
|
|
50
|
+
|
|
51
|
+
if sql is not None:
|
|
52
|
+
self.sql = sql
|
|
53
|
+
|
|
54
|
+
if dba is not None:
|
|
55
|
+
self.dba = dba
|
|
56
|
+
|
|
57
|
+
self.error = _error
|
|
58
|
+
|
|
59
|
+
def to_paginate(self):
|
|
60
|
+
|
|
61
|
+
return {"recordsTotal": self.total_count, "recordsOffset": self.skip, "recordCount": self.count,
|
|
62
|
+
"recordsFiltered": self.total_count, "fields": self.columns, "data": self.to_array(),
|
|
63
|
+
"dataError": self.error}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
@@ -1,116 +0,0 @@
|
|
|
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 base64
|
|
8
|
-
import json
|
|
9
|
-
import datetime
|
|
10
|
-
from decimal import Decimal
|
|
11
|
-
from tina4_python.CRUD import CRUD
|
|
12
|
-
class DatabaseResult(CRUD):
|
|
13
|
-
def __init__(self, _records=None, _columns=None, _error=None, count=None, limit=None, skip=None, sql=None, dba=None):
|
|
14
|
-
"""
|
|
15
|
-
DatabaseResult constructor
|
|
16
|
-
:param _records:
|
|
17
|
-
:param _columns:
|
|
18
|
-
:param _error:
|
|
19
|
-
:param count:
|
|
20
|
-
:param limit:
|
|
21
|
-
:param skip:
|
|
22
|
-
"""
|
|
23
|
-
super().__init__()
|
|
24
|
-
if count is not None:
|
|
25
|
-
self.total_count = count
|
|
26
|
-
else:
|
|
27
|
-
self.total_count = 0
|
|
28
|
-
|
|
29
|
-
if limit is not None:
|
|
30
|
-
self.limit = limit
|
|
31
|
-
else:
|
|
32
|
-
self.limit = 0
|
|
33
|
-
|
|
34
|
-
if skip is not None:
|
|
35
|
-
self.skip = skip
|
|
36
|
-
else:
|
|
37
|
-
self.skip = 0
|
|
38
|
-
|
|
39
|
-
if _records is not None:
|
|
40
|
-
self.records = _records
|
|
41
|
-
else:
|
|
42
|
-
self.records = []
|
|
43
|
-
|
|
44
|
-
self.count = len(self.records)
|
|
45
|
-
|
|
46
|
-
if _columns is not None:
|
|
47
|
-
self.columns = _columns
|
|
48
|
-
else:
|
|
49
|
-
self.columns = []
|
|
50
|
-
|
|
51
|
-
if sql is not None:
|
|
52
|
-
self.sql = sql
|
|
53
|
-
|
|
54
|
-
if dba is not None:
|
|
55
|
-
self.dba = dba
|
|
56
|
-
|
|
57
|
-
self.error = _error
|
|
58
|
-
|
|
59
|
-
def to_paginate(self):
|
|
60
|
-
|
|
61
|
-
return {"recordsTotal": self.total_count, "recordsOffset": self.skip, "recordCount": self.count,
|
|
62
|
-
"recordsFiltered": self.total_count, "fields": self.columns, "data": self.to_array(),
|
|
63
|
-
"dataError": self.error}
|
|
64
|
-
|
|
65
|
-
def to_array(self, _filter=None):
|
|
66
|
-
"""
|
|
67
|
-
Creates an array or list of the items
|
|
68
|
-
:return:
|
|
69
|
-
"""
|
|
70
|
-
if self.error is not None:
|
|
71
|
-
return {"error": self.error}
|
|
72
|
-
elif len(self.records) > 0:
|
|
73
|
-
# check all the records - if we get bytes we base64encode them for the json to work
|
|
74
|
-
json_records = []
|
|
75
|
-
for record in self.records:
|
|
76
|
-
json_record = {}
|
|
77
|
-
for key in record:
|
|
78
|
-
if isinstance(record[key], Decimal):
|
|
79
|
-
json_record[key] = float(record[key])
|
|
80
|
-
elif isinstance(record[key], (datetime.date, datetime.datetime)):
|
|
81
|
-
json_record[key] = record[key].isoformat()
|
|
82
|
-
elif isinstance(record[key], memoryview):
|
|
83
|
-
json_record[key] = base64.b64encode(record[key].tobytes()).decode('utf-8')
|
|
84
|
-
elif isinstance(record[key], bytes):
|
|
85
|
-
json_record[key] = base64.b64encode(record[key]).decode('utf-8')
|
|
86
|
-
else:
|
|
87
|
-
json_record[key] = record[key]
|
|
88
|
-
|
|
89
|
-
if _filter is not None:
|
|
90
|
-
json_record = _filter(json_record)
|
|
91
|
-
|
|
92
|
-
json_records.append(json_record)
|
|
93
|
-
|
|
94
|
-
return json_records
|
|
95
|
-
else:
|
|
96
|
-
return []
|
|
97
|
-
|
|
98
|
-
def to_list(self, _filter=None):
|
|
99
|
-
return self.to_array(_filter)
|
|
100
|
-
|
|
101
|
-
def to_json(self, _filter=None):
|
|
102
|
-
return json.dumps(self.to_array(_filter))
|
|
103
|
-
|
|
104
|
-
def __iter__(self):
|
|
105
|
-
return iter(self.to_array())
|
|
106
|
-
|
|
107
|
-
def __getitem__(self, item):
|
|
108
|
-
if item < len(self.records):
|
|
109
|
-
return self.records[item]
|
|
110
|
-
else:
|
|
111
|
-
return {}
|
|
112
|
-
|
|
113
|
-
def __str__(self):
|
|
114
|
-
return self.to_json()
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/js/reconnecting-websocket.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/public/swagger/oauth2-redirect.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.126 → tina4_python-0.2.128}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|