brilliance-admin 0.44.6__tar.gz → 0.44.8__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.
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/PKG-INFO +9 -2
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/README.md +8 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/autocomplete.py +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/table.py +5 -5
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/autocomplete.py +6 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/create.py +2 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/delete.py +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/list.py +18 -6
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/retrieve.py +15 -6
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/update.py +5 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/locales/en.yml +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/locales/ru.yml +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/admin_schema.py +4 -2
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/category_table.py +10 -7
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/fields/base.py +44 -5
- brilliance_admin-0.44.6/brilliance_admin/static/index-BV43pxcV.js → brilliance_admin-0.44.8/brilliance_admin/static/index-BSBmA7K6.js +119 -119
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/templates/index.html +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin.egg-info/PKG-INFO +9 -2
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin.egg-info/SOURCES.txt +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/pyproject.toml +1 -1
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_sqlalcmeny_crud.py +77 -2
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_sqlalcmeny_filters.py +10 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/LICENSE +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/routers.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/utils.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/auth.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/graphs.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/index.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/schema.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/settings.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/auth.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/docs.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/exceptions.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/auth.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/fields.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/fields_schema.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/integrations/sqlalchemy/table/base.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/category.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/graphs/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/graphs/category_graphs.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/admin_action.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/fields/__init__.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/fields/function_field.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/fields_schema.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/table_models.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/index-P_wdMBbz.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/materialdesignicons-webfont-CYDMK1kx.woff2 +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/materialdesignicons-webfont-CgCzGbLl.woff +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/materialdesignicons-webfont-D3kAzl71.ttf +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/materialdesignicons-webfont-DttUABo4.eot +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/dark-first/content.min.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/dark-first/skin.min.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/dark-slim/content.min.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/dark-slim/skin.min.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/img/example.png +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/img/tinymce.woff2 +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/lightgray/content.min.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/lightgray/fonts/tinymce.woff +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/lightgray/skin.min.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/plugins/accordion/css/accordion.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/plugins/accordion/plugin.js +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/plugins/codesample/css/prism.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/plugins/customLink/css/link.css +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/plugins/customLink/plugin.js +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/tinymce/tinymce.min.js +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/static/vanilla-picker-B6E6ObS_.js +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/translations.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/utils.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin.egg-info/dependency_links.txt +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin.egg-info/requires.txt +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin.egg-info/top_level.txt +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/setup.cfg +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_action.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_payments_fields_schema.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_settings.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_sqlalcmeny_auth.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_sqlalcmeny_schema.py +0 -0
- {brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/tests/test_translations.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brilliance-admin
|
|
3
|
-
Version: 0.44.
|
|
3
|
+
Version: 0.44.8
|
|
4
4
|
Summary: Simple and lightweight data managment framework powered by FastAPI and Vue3 Vuetify all-in-one. Some call it heavenly in its brilliance.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -40,7 +40,7 @@ Dynamic: license-file
|
|
|
40
40
|
[](https://pypi.org/project/brilliance-admin/)
|
|
41
41
|
[](https://github.com/brilliance-admin/backend-python/actions)
|
|
42
42
|
|
|
43
|
-
Simple and lightweight data
|
|
43
|
+
Simple and lightweight data management framework powered by `FastAPI` and `Vue3` `Vuetify` all-in-one. \
|
|
44
44
|
Integrated with `SQLAlchemy`. Inspaired by Django Admin and DRF.\
|
|
45
45
|
_Some call it heavenly in its brilliance._
|
|
46
46
|
|
|
@@ -60,6 +60,13 @@ This endpoint can be added to any ASGI compatable backend. For existing project
|
|
|
60
60
|
- API to fetch the UI JSON schema
|
|
61
61
|
- API methods for that UI to work with (to read and modify data)
|
|
62
62
|
|
|
63
|
+
<details open>
|
|
64
|
+
<summary><h2>Screenshots</h2></summary>
|
|
65
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/login.png?raw=true"/></div>
|
|
66
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/table.png?raw=true"/></div>
|
|
67
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/charts.png?raw=true"/></div>
|
|
68
|
+
</details>
|
|
69
|
+
|
|
63
70
|
## Key ideas
|
|
64
71
|
|
|
65
72
|
- **API Oriented** <br>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://pypi.org/project/brilliance-admin/)
|
|
7
7
|
[](https://github.com/brilliance-admin/backend-python/actions)
|
|
8
8
|
|
|
9
|
-
Simple and lightweight data
|
|
9
|
+
Simple and lightweight data management framework powered by `FastAPI` and `Vue3` `Vuetify` all-in-one. \
|
|
10
10
|
Integrated with `SQLAlchemy`. Inspaired by Django Admin and DRF.\
|
|
11
11
|
_Some call it heavenly in its brilliance._
|
|
12
12
|
|
|
@@ -26,6 +26,13 @@ This endpoint can be added to any ASGI compatable backend. For existing project
|
|
|
26
26
|
- API to fetch the UI JSON schema
|
|
27
27
|
- API methods for that UI to work with (to read and modify data)
|
|
28
28
|
|
|
29
|
+
<details open>
|
|
30
|
+
<summary><h2>Screenshots</h2></summary>
|
|
31
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/login.png?raw=true"/></div>
|
|
32
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/table.png?raw=true"/></div>
|
|
33
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/charts.png?raw=true"/></div>
|
|
34
|
+
</details>
|
|
35
|
+
|
|
29
36
|
## Key ideas
|
|
30
37
|
|
|
31
38
|
- **API Oriented** <br>
|
{brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/api/views/autocomplete.py
RENAMED
|
@@ -23,7 +23,7 @@ async def autocomplete(request: Request, group: str, category: str, data: Autoco
|
|
|
23
23
|
context = {'language_context': language_context}
|
|
24
24
|
|
|
25
25
|
try:
|
|
26
|
-
result: AutocompleteResult = await schema_category.autocomplete(data, user, language_context)
|
|
26
|
+
result: AutocompleteResult = await schema_category.autocomplete(data, user, language_context, schema)
|
|
27
27
|
except AdminAPIException as e:
|
|
28
28
|
return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
|
|
29
29
|
except Exception as e:
|
|
@@ -30,7 +30,7 @@ async def table_list(request: Request, group: str, category: str, list_data: Lis
|
|
|
30
30
|
context = {'language_context': language_context}
|
|
31
31
|
|
|
32
32
|
try:
|
|
33
|
-
result: TableListResult = await schema_category.get_list(list_data, user, language_context)
|
|
33
|
+
result: TableListResult = await schema_category.get_list(list_data, user, language_context, schema)
|
|
34
34
|
except AdminAPIException as e:
|
|
35
35
|
return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
|
|
36
36
|
|
|
@@ -54,7 +54,7 @@ async def table_retrieve(request: Request, group: str, category: str, pk: Any) -
|
|
|
54
54
|
context = {'language_context': language_context}
|
|
55
55
|
|
|
56
56
|
try:
|
|
57
|
-
result: RetrieveResult = await schema_category.retrieve(pk, user, language_context)
|
|
57
|
+
result: RetrieveResult = await schema_category.retrieve(pk, user, language_context, schema)
|
|
58
58
|
except AdminAPIException as e:
|
|
59
59
|
return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
|
|
60
60
|
|
|
@@ -77,7 +77,7 @@ async def table_create(request: Request, group: str, category: str) -> CreateRes
|
|
|
77
77
|
context = {'language_context': language_context}
|
|
78
78
|
|
|
79
79
|
try:
|
|
80
|
-
result: CreateResult = await schema_category.create(await request.json(), user, language_context)
|
|
80
|
+
result: CreateResult = await schema_category.create(await request.json(), user, language_context, schema)
|
|
81
81
|
except AdminAPIException as e:
|
|
82
82
|
return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
|
|
83
83
|
|
|
@@ -100,7 +100,7 @@ async def table_update(request: Request, group: str, category: str, pk: Any) ->
|
|
|
100
100
|
context = {'language_context': language_context}
|
|
101
101
|
|
|
102
102
|
try:
|
|
103
|
-
result: UpdateResult = await schema_category.update(pk, await request.json(), user, language_context)
|
|
103
|
+
result: UpdateResult = await schema_category.update(pk, await request.json(), user, language_context, schema)
|
|
104
104
|
except AdminAPIException as e:
|
|
105
105
|
return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
|
|
106
106
|
|
|
@@ -129,7 +129,7 @@ async def table_action(
|
|
|
129
129
|
try:
|
|
130
130
|
# pylint: disable=protected-access
|
|
131
131
|
result: ActionResult = await schema_category._perform_action(
|
|
132
|
-
request, action, action_data, language_context, user,
|
|
132
|
+
request, action, action_data, language_context, user, schema,
|
|
133
133
|
)
|
|
134
134
|
except AdminAPIException as e:
|
|
135
135
|
return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
from brilliance_admin.auth import UserABC
|
|
2
|
+
from brilliance_admin.schema.admin_schema import AdminSchema
|
|
2
3
|
from brilliance_admin.schema.table.table_models import AutocompleteData, AutocompleteResult
|
|
3
4
|
from brilliance_admin.translations import LanguageContext
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class SQLAlchemyAdminAutocompleteMixin:
|
|
7
8
|
async def autocomplete(
|
|
8
|
-
self,
|
|
9
|
+
self,
|
|
10
|
+
data: AutocompleteData,
|
|
11
|
+
user: UserABC,
|
|
12
|
+
language_context: LanguageContext,
|
|
13
|
+
admin_schema: AdminSchema,
|
|
9
14
|
) -> AutocompleteResult:
|
|
10
15
|
form_schema = None
|
|
11
16
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from brilliance_admin import schema
|
|
2
2
|
from brilliance_admin.auth import UserABC
|
|
3
3
|
from brilliance_admin.exceptions import AdminAPIException, APIError
|
|
4
|
+
from brilliance_admin.schema.admin_schema import AdminSchema
|
|
4
5
|
from brilliance_admin.translations import LanguageContext
|
|
5
6
|
from brilliance_admin.translations import TranslateText as _
|
|
6
7
|
from brilliance_admin.utils import get_logger
|
|
@@ -16,6 +17,7 @@ class SQLAlchemyAdminCreate:
|
|
|
16
17
|
data: dict,
|
|
17
18
|
user: UserABC,
|
|
18
19
|
language_context: LanguageContext,
|
|
20
|
+
admin_schema: AdminSchema,
|
|
19
21
|
) -> schema.CreateResult:
|
|
20
22
|
if not self.has_create:
|
|
21
23
|
raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
|
|
@@ -12,7 +12,7 @@ class SQLAlchemyDeleteAction:
|
|
|
12
12
|
base_color='red-lighten-2',
|
|
13
13
|
variant='outlined',
|
|
14
14
|
)
|
|
15
|
-
async def delete(self, action_data: ActionData):
|
|
15
|
+
async def delete(self, *args, action_data: ActionData, **kwargs):
|
|
16
16
|
if not self.has_delete:
|
|
17
17
|
raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
|
|
18
18
|
return ActionResult(message=ActionMessage(_('deleted_successfully')))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from brilliance_admin import auth, schema
|
|
2
2
|
from brilliance_admin.exceptions import AdminAPIException, APIError, FieldError
|
|
3
3
|
from brilliance_admin.integrations.sqlalchemy.fields_schema import SQLAlchemyFieldsSchema
|
|
4
|
+
from brilliance_admin.schema.admin_schema import AdminSchema
|
|
4
5
|
from brilliance_admin.translations import LanguageContext
|
|
5
6
|
from brilliance_admin.translations import TranslateText as _
|
|
6
7
|
from brilliance_admin.utils import get_logger
|
|
@@ -88,6 +89,7 @@ class SQLAlchemyAdminListMixin:
|
|
|
88
89
|
list_data: schema.ListData,
|
|
89
90
|
user: auth.UserABC,
|
|
90
91
|
language_context: LanguageContext,
|
|
92
|
+
admin_schema: AdminSchema,
|
|
91
93
|
) -> schema.TableListResult:
|
|
92
94
|
# pylint: disable=import-outside-toplevel
|
|
93
95
|
from sqlalchemy import exc, func, select
|
|
@@ -120,7 +122,10 @@ class SQLAlchemyAdminListMixin:
|
|
|
120
122
|
'list_data': list_data,
|
|
121
123
|
}
|
|
122
124
|
)
|
|
123
|
-
|
|
125
|
+
msg = _('errors.filters_exception') % {
|
|
126
|
+
'error': str(e) if admin_schema.debug else type(e).__name__,
|
|
127
|
+
}
|
|
128
|
+
raise AdminAPIException(APIError(message=msg, code='filters_exception'), status_code=500) from e
|
|
124
129
|
|
|
125
130
|
try:
|
|
126
131
|
async with self.db_async_session() as session:
|
|
@@ -163,7 +168,9 @@ class SQLAlchemyAdminListMixin:
|
|
|
163
168
|
'list_data': list_data,
|
|
164
169
|
}
|
|
165
170
|
)
|
|
166
|
-
msg = _('errors.db_error_list') % {
|
|
171
|
+
msg = _('errors.db_error_list') % {
|
|
172
|
+
'error_type': str(e) if admin_schema.debug else type(e).__name__,
|
|
173
|
+
}
|
|
167
174
|
raise AdminAPIException(
|
|
168
175
|
APIError(message=msg, code='db_error_list'), status_code=500,
|
|
169
176
|
) from e
|
|
@@ -182,15 +189,20 @@ class SQLAlchemyAdminListMixin:
|
|
|
182
189
|
'SQLAlchemy %s list %s serialize field error: %s',
|
|
183
190
|
type(self).__name__, self.model.__name__, e,
|
|
184
191
|
)
|
|
185
|
-
msg = _('serialize_error.field_error') % {
|
|
186
|
-
|
|
192
|
+
msg = _('serialize_error.field_error') % {
|
|
193
|
+
'error': e.message,
|
|
194
|
+
'field_slug': e.field_slug,
|
|
195
|
+
}
|
|
196
|
+
raise AdminAPIException(APIError(message=msg, code='field_error'), status_code=500) from e
|
|
187
197
|
|
|
188
198
|
except Exception as e:
|
|
189
199
|
logger.exception(
|
|
190
200
|
'SQLAlchemy %s list %s serialize error: %s',
|
|
191
201
|
type(self).__name__, self.model.__name__, e,
|
|
192
202
|
)
|
|
193
|
-
msg = _('serialize_error.unexpected_error') % {
|
|
194
|
-
|
|
203
|
+
msg = _('serialize_error.unexpected_error') % {
|
|
204
|
+
'error': str(e) if admin_schema.debug else type(e).__name__,
|
|
205
|
+
}
|
|
206
|
+
raise AdminAPIException(APIError(message=msg, code='unexpected_error'), status_code=500) from e
|
|
195
207
|
|
|
196
208
|
return schema.TableListResult(data=data, total_count=int(total_count or 0))
|
|
@@ -3,6 +3,7 @@ from typing import Any
|
|
|
3
3
|
from brilliance_admin import auth, schema
|
|
4
4
|
from brilliance_admin.exceptions import AdminAPIException, APIError, FieldError
|
|
5
5
|
from brilliance_admin.integrations.sqlalchemy.fields_schema import SQLAlchemyFieldsSchema
|
|
6
|
+
from brilliance_admin.schema.admin_schema import AdminSchema
|
|
6
7
|
from brilliance_admin.translations import LanguageContext
|
|
7
8
|
from brilliance_admin.translations import TranslateText as _
|
|
8
9
|
from brilliance_admin.utils import get_logger
|
|
@@ -20,8 +21,9 @@ class SQLAlchemyAdminRetrieveMixin:
|
|
|
20
21
|
pk: Any,
|
|
21
22
|
user: auth.UserABC,
|
|
22
23
|
language_context: LanguageContext,
|
|
24
|
+
admin_schema: AdminSchema,
|
|
23
25
|
) -> schema.RetrieveResult:
|
|
24
|
-
if not self.
|
|
26
|
+
if not self.has_retrieve:
|
|
25
27
|
raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
|
|
26
28
|
|
|
27
29
|
# pylint: disable=import-outside-toplevel
|
|
@@ -42,7 +44,9 @@ class SQLAlchemyAdminRetrieveMixin:
|
|
|
42
44
|
'SQLAlchemy %s retrieve %s #%s db error: %s',
|
|
43
45
|
type(self).__name__, self.model.__name__, pk, e,
|
|
44
46
|
)
|
|
45
|
-
msg = _('errors.db_error_retrieve') % {
|
|
47
|
+
msg = _('errors.db_error_retrieve') % {
|
|
48
|
+
'error_type': str(e) if admin_schema.debug else type(e).__name__,
|
|
49
|
+
}
|
|
46
50
|
raise AdminAPIException(
|
|
47
51
|
APIError(message=msg, code='db_error_retrieve'), status_code=500,
|
|
48
52
|
) from e
|
|
@@ -64,16 +68,21 @@ class SQLAlchemyAdminRetrieveMixin:
|
|
|
64
68
|
'SQLAlchemy %s retrieve %s #%s serialize field error: %s',
|
|
65
69
|
type(self).__name__, self.model.__name__, pk, e,
|
|
66
70
|
)
|
|
67
|
-
msg = _('serialize_error.field_error') % {
|
|
68
|
-
|
|
71
|
+
msg = _('serialize_error.field_error') % {
|
|
72
|
+
'error': e.message,
|
|
73
|
+
'field_slug': e.field_slug,
|
|
74
|
+
}
|
|
75
|
+
raise AdminAPIException(APIError(message=msg, code='field_error'), status_code=500) from e
|
|
69
76
|
|
|
70
77
|
except Exception as e:
|
|
71
78
|
logger.exception(
|
|
72
79
|
'SQLAlchemy %s list %s #%s serialize error: %s',
|
|
73
80
|
type(self).__name__, self.model.__name__, pk, e,
|
|
74
81
|
)
|
|
75
|
-
msg = _('serialize_error.unexpected_error') % {
|
|
76
|
-
|
|
82
|
+
msg = _('serialize_error.unexpected_error') % {
|
|
83
|
+
'error': str(e) if admin_schema.debug else type(e).__name__,
|
|
84
|
+
}
|
|
85
|
+
raise AdminAPIException(APIError(message=msg, code='unexpected_error'), status_code=500) from e
|
|
77
86
|
|
|
78
87
|
logger.debug(
|
|
79
88
|
'%s model %s #%s retrieved by %s',
|
|
@@ -2,6 +2,7 @@ from typing import Any
|
|
|
2
2
|
|
|
3
3
|
from brilliance_admin import auth, schema
|
|
4
4
|
from brilliance_admin.exceptions import AdminAPIException, APIError
|
|
5
|
+
from brilliance_admin.schema.admin_schema import AdminSchema
|
|
5
6
|
from brilliance_admin.translations import LanguageContext
|
|
6
7
|
from brilliance_admin.translations import TranslateText as _
|
|
7
8
|
from brilliance_admin.utils import get_logger
|
|
@@ -19,6 +20,7 @@ class SQLAlchemyAdminUpdate:
|
|
|
19
20
|
data: dict,
|
|
20
21
|
user: auth.UserABC,
|
|
21
22
|
language_context: LanguageContext,
|
|
23
|
+
admin_schema: AdminSchema,
|
|
22
24
|
) -> schema.UpdateResult:
|
|
23
25
|
if not self.has_update:
|
|
24
26
|
raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
|
|
@@ -83,7 +85,9 @@ class SQLAlchemyAdminUpdate:
|
|
|
83
85
|
type(self).__name__, self.table_schema.model.__name__, pk, e,
|
|
84
86
|
extra={'data': data}
|
|
85
87
|
)
|
|
86
|
-
msg = _('errors.db_error_update') % {
|
|
88
|
+
msg = _('errors.db_error_update') % {
|
|
89
|
+
'error_type': str(e) if admin_schema.debug else type(e).__name__,
|
|
90
|
+
}
|
|
87
91
|
raise AdminAPIException(
|
|
88
92
|
APIError(message=msg, code='db_error_update'), status_code=500,
|
|
89
93
|
) from e
|
|
@@ -12,7 +12,7 @@ errors:
|
|
|
12
12
|
db_error_list: 'Failed to retrieve table data from the database: %(error_type)s'
|
|
13
13
|
|
|
14
14
|
connection_refused_error: 'Database connection error: %(error)s'
|
|
15
|
-
filters_exception: 'An unknown technical error occurred while filtering data
|
|
15
|
+
filters_exception: 'An unknown technical error occurred while filtering data: %(error_type)s'
|
|
16
16
|
method_not_allowed: 'Error, method not allowed. This action is not permitted.'
|
|
17
17
|
filter_error: 'An error occurred during filtering: {error}'
|
|
18
18
|
bad_type_error: 'Invalid data type: %(type)s but %(expected)s expected'
|
|
@@ -12,7 +12,7 @@ errors:
|
|
|
12
12
|
db_error_list: 'Ошибка получения данных таблицы из базы данных: %(error_type)s'
|
|
13
13
|
|
|
14
14
|
connection_refused_error: 'Ошибка подключения к базе данных: %(error)s'
|
|
15
|
-
filters_exception: 'Произошла неизвестная техническая ошибка при фильтрации
|
|
15
|
+
filters_exception: 'Произошла неизвестная техническая ошибка при фильтрации данных: %(error_type)s'
|
|
16
16
|
method_not_allowed: 'Ошибка, данный метод недоступен.'
|
|
17
17
|
filter_error: 'Проишла ошибка при фильтрации: %(error)s'
|
|
18
18
|
bad_type_error: 'Некорректный тип данных: %(type)s; ожидается %(expected)s'
|
|
@@ -68,6 +68,8 @@ class AdminSchema:
|
|
|
68
68
|
|
|
69
69
|
language_manager: LanguageManager | None = None
|
|
70
70
|
|
|
71
|
+
debug: bool = False
|
|
72
|
+
|
|
71
73
|
def __post_init__(self):
|
|
72
74
|
for category in self.categories:
|
|
73
75
|
if not issubclass(category.__class__, BaseCategory):
|
|
@@ -122,8 +124,6 @@ class AdminSchema:
|
|
|
122
124
|
languages=languages,
|
|
123
125
|
)
|
|
124
126
|
|
|
125
|
-
# pylint: disable=too-many-arguments
|
|
126
|
-
# pylint: disable=too-many-positional-arguments
|
|
127
127
|
def generate_app(
|
|
128
128
|
self,
|
|
129
129
|
debug=False,
|
|
@@ -133,6 +133,8 @@ class AdminSchema:
|
|
|
133
133
|
include_docs=False,
|
|
134
134
|
include_redoc=False,
|
|
135
135
|
) -> FastAPI:
|
|
136
|
+
self.debug = debug
|
|
137
|
+
|
|
136
138
|
# pylint: disable=unused-variable
|
|
137
139
|
language_context = self.get_language_context(language_slug=None)
|
|
138
140
|
|
{brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/category_table.py
RENAMED
|
@@ -8,8 +8,8 @@ from pydantic import Field
|
|
|
8
8
|
|
|
9
9
|
from brilliance_admin.auth import UserABC
|
|
10
10
|
from brilliance_admin.exceptions import AdminAPIException, APIError
|
|
11
|
-
from brilliance_admin.schema.
|
|
12
|
-
from brilliance_admin.schema.category import TableInfoSchemaData
|
|
11
|
+
from brilliance_admin.schema.admin_schema import AdminSchema
|
|
12
|
+
from brilliance_admin.schema.category import BaseCategory, TableInfoSchemaData
|
|
13
13
|
from brilliance_admin.schema.table.admin_action import ActionData, ActionResult
|
|
14
14
|
from brilliance_admin.schema.table.fields_schema import FieldsSchema
|
|
15
15
|
from brilliance_admin.schema.table.table_models import AutocompleteData, AutocompleteResult, ListData, TableListResult
|
|
@@ -130,6 +130,7 @@ class CategoryTable(BaseCategory):
|
|
|
130
130
|
action_data: ActionData,
|
|
131
131
|
language_context: LanguageContext,
|
|
132
132
|
user: UserABC,
|
|
133
|
+
admin_schema: AdminSchema,
|
|
133
134
|
) -> ActionResult:
|
|
134
135
|
action_fn = self._get_action_fn(action)
|
|
135
136
|
if action_fn is None:
|
|
@@ -156,7 +157,7 @@ class CategoryTable(BaseCategory):
|
|
|
156
157
|
|
|
157
158
|
return result
|
|
158
159
|
|
|
159
|
-
async def autocomplete(self, data: AutocompleteData, user: UserABC) -> AutocompleteResult:
|
|
160
|
+
async def autocomplete(self, data: AutocompleteData, user: UserABC, schema: AdminSchema) -> AutocompleteResult:
|
|
160
161
|
"""
|
|
161
162
|
Retrieves list of found options to select.
|
|
162
163
|
"""
|
|
@@ -164,14 +165,16 @@ class CategoryTable(BaseCategory):
|
|
|
164
165
|
|
|
165
166
|
# pylint: disable=too-many-arguments
|
|
166
167
|
@abc.abstractmethod
|
|
167
|
-
async def get_list(
|
|
168
|
+
async def get_list(
|
|
169
|
+
self, list_data: ListData, user: UserABC, language_context: LanguageContext, admin_schema: AdminSchema
|
|
170
|
+
) -> TableListResult:
|
|
168
171
|
raise NotImplementedError()
|
|
169
172
|
|
|
170
|
-
# async def retrieve(self, pk: Any, user: UserABC) -> RetrieveResult:
|
|
173
|
+
# async def retrieve(self, pk: Any, user: UserABC, language_context: LanguageContext, admin_schema: AdminSchema) -> RetrieveResult:
|
|
171
174
|
# raise NotImplementedError()
|
|
172
175
|
|
|
173
|
-
# async def create(self, data: dict, user: UserABC) -> CreateResult:
|
|
176
|
+
# async def create(self, data: dict, user: UserABC, language_context: LanguageContext, admin_schema: AdminSchema) -> CreateResult:
|
|
174
177
|
# raise NotImplementedError()
|
|
175
178
|
|
|
176
|
-
# async def update(self, pk: Any, data: dict, user: UserABC) -> UpdateResult:
|
|
179
|
+
# async def update(self, pk: Any, data: dict, user: UserABC, language_context: LanguageContext, admin_schema: AdminSchema) -> UpdateResult:
|
|
177
180
|
# raise NotImplementedError()
|
{brilliance_admin-0.44.6 → brilliance_admin-0.44.8}/brilliance_admin/schema/table/fields/base.py
RENAMED
|
@@ -127,6 +127,18 @@ class BooleanField(TableField):
|
|
|
127
127
|
_type = 'boolean'
|
|
128
128
|
|
|
129
129
|
|
|
130
|
+
def _parse_iso(value: str) -> datetime.datetime:
|
|
131
|
+
if value.endswith('Z'):
|
|
132
|
+
value = value.replace('Z', '+00:00')
|
|
133
|
+
|
|
134
|
+
dt = datetime.datetime.fromisoformat(value)
|
|
135
|
+
|
|
136
|
+
if dt.tzinfo is None:
|
|
137
|
+
dt = dt.replace(tzinfo=datetime.timezone.utc)
|
|
138
|
+
|
|
139
|
+
return dt
|
|
140
|
+
|
|
141
|
+
|
|
130
142
|
@dataclass
|
|
131
143
|
class DateTimeField(TableField):
|
|
132
144
|
_type = 'datetime'
|
|
@@ -155,16 +167,17 @@ class DateTimeField(TableField):
|
|
|
155
167
|
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'datetime'})
|
|
156
168
|
|
|
157
169
|
if isinstance(value, str):
|
|
158
|
-
return
|
|
170
|
+
return _parse_iso(value)
|
|
159
171
|
|
|
160
172
|
if isinstance(value, dict):
|
|
161
173
|
if not value.get('from') or not value.get('to'):
|
|
162
|
-
|
|
163
|
-
|
|
174
|
+
raise FieldError(
|
|
175
|
+
f'{type(self).__name__} value must be dict with from,to values: {value}'
|
|
176
|
+
)
|
|
164
177
|
|
|
165
178
|
return {
|
|
166
|
-
'from':
|
|
167
|
-
'to':
|
|
179
|
+
'from': _parse_iso(value['from']),
|
|
180
|
+
'to': _parse_iso(value['to']),
|
|
168
181
|
}
|
|
169
182
|
|
|
170
183
|
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'datetime'})
|
|
@@ -291,3 +304,29 @@ class ChoiceField(TableField):
|
|
|
291
304
|
'value': value,
|
|
292
305
|
'title': choice.get('title') or value if choice else value.capitalize(),
|
|
293
306
|
}
|
|
307
|
+
|
|
308
|
+
async def deserialize(self, value, action: DeserializeAction, extra: dict, *args, **kwargs) -> Any:
|
|
309
|
+
value = await super().deserialize(value, action, extra, *args, **kwargs)
|
|
310
|
+
|
|
311
|
+
if value is None:
|
|
312
|
+
return
|
|
313
|
+
|
|
314
|
+
if isinstance(value, dict):
|
|
315
|
+
if 'value' not in value:
|
|
316
|
+
raise FieldError(
|
|
317
|
+
f'{type(self).__name__} dict value must contain "value": {value}'
|
|
318
|
+
)
|
|
319
|
+
value = value['value']
|
|
320
|
+
|
|
321
|
+
if not isinstance(value, str):
|
|
322
|
+
raise FieldError(
|
|
323
|
+
f'{type(self).__name__} value must be str, got {type(value)}'
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
choice = self.find_choice(value)
|
|
327
|
+
if not choice:
|
|
328
|
+
raise FieldError(
|
|
329
|
+
f'Invalid choice value "{value}", allowed: {[c["value"] for c in self.choices or []]}'
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return value
|