brilliance-admin 0.44.0__py3-none-any.whl → 0.44.2__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.
- brilliance_admin/api/views/table.py +2 -1
- brilliance_admin/integrations/sqlalchemy/auth.py +1 -2
- brilliance_admin/integrations/sqlalchemy/fields.py +22 -9
- brilliance_admin/schema/table/fields/base.py +21 -6
- brilliance_admin/static/{index-MLuDem5W.js → index-rBvEkjGg.js} +2 -2
- brilliance_admin/templates/index.html +1 -1
- {brilliance_admin-0.44.0.dist-info → brilliance_admin-0.44.2.dist-info}/METADATA +4 -1
- {brilliance_admin-0.44.0.dist-info → brilliance_admin-0.44.2.dist-info}/RECORD +11 -13
- brilliance_admin/locales/en.yml +0 -25
- brilliance_admin/locales/ru.yml +0 -26
- {brilliance_admin-0.44.0.dist-info → brilliance_admin-0.44.2.dist-info}/WHEEL +0 -0
- {brilliance_admin-0.44.0.dist-info → brilliance_admin-0.44.2.dist-info}/licenses/LICENSE +0 -0
- {brilliance_admin-0.44.0.dist-info → brilliance_admin-0.44.2.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,8 @@ from brilliance_admin.exceptions import AdminAPIException, APIError
|
|
|
8
8
|
from brilliance_admin.schema import AdminSchema
|
|
9
9
|
from brilliance_admin.schema.table.admin_action import ActionData, ActionResult
|
|
10
10
|
from brilliance_admin.schema.table.category_table import CategoryTable
|
|
11
|
-
from brilliance_admin.schema.table.table_models import
|
|
11
|
+
from brilliance_admin.schema.table.table_models import (
|
|
12
|
+
CreateResult, ListData, RetrieveResult, TableListResult, UpdateResult)
|
|
12
13
|
from brilliance_admin.translations import LanguageContext
|
|
13
14
|
from brilliance_admin.utils import get_logger
|
|
14
15
|
|
|
@@ -122,6 +122,7 @@ class SQLAlchemyJWTAdminAuthentication(AdminAuthentication):
|
|
|
122
122
|
try:
|
|
123
123
|
async with self.db_async_session() as session:
|
|
124
124
|
result = await session.execute(stmt)
|
|
125
|
+
user = result.scalar_one_or_none()
|
|
125
126
|
|
|
126
127
|
except ConnectionRefusedError as e:
|
|
127
128
|
logger.exception(
|
|
@@ -133,8 +134,6 @@ class SQLAlchemyJWTAdminAuthentication(AdminAuthentication):
|
|
|
133
134
|
status_code=500,
|
|
134
135
|
) from e
|
|
135
136
|
|
|
136
|
-
user = result.scalar_one_or_none()
|
|
137
|
-
|
|
138
137
|
if not user:
|
|
139
138
|
raise AdminAPIException(
|
|
140
139
|
APIError(message="User not found", code="user_not_found"),
|
|
@@ -6,7 +6,7 @@ from brilliance_admin.auth import UserABC
|
|
|
6
6
|
from brilliance_admin.exceptions import AdminAPIException, APIError, FieldError
|
|
7
7
|
from brilliance_admin.schema.category import FieldSchemaData
|
|
8
8
|
from brilliance_admin.schema.table.fields.base import TableField
|
|
9
|
-
from brilliance_admin.schema.table.table_models import Record
|
|
9
|
+
from brilliance_admin.schema.table.table_models import AutocompleteData, Record
|
|
10
10
|
from brilliance_admin.translations import LanguageContext
|
|
11
11
|
from brilliance_admin.translations import TranslateText as _
|
|
12
12
|
from brilliance_admin.utils import DeserializeAction
|
|
@@ -96,10 +96,9 @@ class SQLAlchemyRelatedField(TableField):
|
|
|
96
96
|
msg = f'Cannot resolve target model for FK "{field_slug}"'
|
|
97
97
|
raise AttributeError(msg)
|
|
98
98
|
|
|
99
|
-
async def autocomplete(self, model, data, user, *, extra: dict | None = None) -> List[Record]:
|
|
99
|
+
async def autocomplete(self, model, data: AutocompleteData, user, *, extra: dict | None = None) -> List[Record]:
|
|
100
100
|
# pylint: disable=import-outside-toplevel
|
|
101
101
|
from sqlalchemy import select
|
|
102
|
-
from sqlalchemy.sql import expression
|
|
103
102
|
|
|
104
103
|
if extra is None or extra.get('db_async_session') is None:
|
|
105
104
|
msg = f'SQLAlchemyRelatedField.autocomplete {type(self).__name__} requires extra["db_async_session"] (AsyncSession)'
|
|
@@ -113,23 +112,37 @@ class SQLAlchemyRelatedField(TableField):
|
|
|
113
112
|
limit = min(150, data.limit)
|
|
114
113
|
stmt = select(target_model).limit(limit)
|
|
115
114
|
|
|
115
|
+
pk = get_pk(target_model)
|
|
116
|
+
python_pk_type = pk.property.columns[0].type.python_type
|
|
117
|
+
|
|
116
118
|
if data.search_string:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
try:
|
|
120
|
+
value = python_pk_type(data.search_string)
|
|
121
|
+
except (ValueError, TypeError):
|
|
122
|
+
# Search string cannot be cast to primary key type, skip id filter
|
|
123
|
+
value = None
|
|
124
|
+
|
|
125
|
+
stmt = stmt.where(pk == value)
|
|
119
126
|
|
|
120
127
|
# Add already selected choices
|
|
121
|
-
existed_choices = []
|
|
122
128
|
if data.existed_choices:
|
|
123
129
|
existed_choices = [i['key'] for i in data.existed_choices if 'key' in i]
|
|
124
130
|
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
values = []
|
|
132
|
+
for value in existed_choices:
|
|
133
|
+
try:
|
|
134
|
+
values.append(python_pk_type(value))
|
|
135
|
+
except (ValueError, TypeError) as e:
|
|
136
|
+
msg = f'Invalid existed_choices value "{value}" for pk {pk} python_pk_type:{python_pk_type.__name__}'
|
|
137
|
+
raise AdminAPIException(APIError(message=msg), status_code=500) from e
|
|
138
|
+
|
|
139
|
+
stmt = stmt.where(pk.in_(values))
|
|
127
140
|
|
|
128
141
|
async with db_async_session() as session:
|
|
129
142
|
records = (await session.execute(stmt)).scalars().all()
|
|
130
143
|
|
|
131
144
|
for record in records:
|
|
132
|
-
results.append(Record(key=getattr(record,
|
|
145
|
+
results.append(Record(key=getattr(record, pk.key), title=str(record)))
|
|
133
146
|
|
|
134
147
|
return results
|
|
135
148
|
|
|
@@ -8,6 +8,7 @@ from pydantic.dataclasses import dataclass
|
|
|
8
8
|
from brilliance_admin.exceptions import FieldError
|
|
9
9
|
from brilliance_admin.schema.category import FieldSchemaData
|
|
10
10
|
from brilliance_admin.translations import LanguageContext
|
|
11
|
+
from brilliance_admin.translations import TranslateText as _
|
|
11
12
|
from brilliance_admin.utils import DeserializeAction, SupportsStr, humanize_field_name
|
|
12
13
|
|
|
13
14
|
|
|
@@ -80,7 +81,7 @@ class IntegerField(TableField):
|
|
|
80
81
|
async def deserialize(self, value, action: DeserializeAction, extra: dict, *args, **kwargs) -> Any:
|
|
81
82
|
value = await super().deserialize(value, action, extra, *args, **kwargs)
|
|
82
83
|
if value and not isinstance(value, int):
|
|
83
|
-
raise FieldError(
|
|
84
|
+
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'init'})
|
|
84
85
|
|
|
85
86
|
return value
|
|
86
87
|
|
|
@@ -116,7 +117,7 @@ class StringField(TableField):
|
|
|
116
117
|
async def deserialize(self, value, action: DeserializeAction, extra: dict, *args, **kwargs) -> Any:
|
|
117
118
|
value = await super().deserialize(value, action, extra, *args, **kwargs)
|
|
118
119
|
if value and not isinstance(value, str):
|
|
119
|
-
raise FieldError(
|
|
120
|
+
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'string'})
|
|
120
121
|
|
|
121
122
|
return value
|
|
122
123
|
|
|
@@ -151,7 +152,7 @@ class DateTimeField(TableField):
|
|
|
151
152
|
return
|
|
152
153
|
|
|
153
154
|
if value and not isinstance(value, (str, dict)):
|
|
154
|
-
raise FieldError(
|
|
155
|
+
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'datetime'})
|
|
155
156
|
|
|
156
157
|
if isinstance(value, str):
|
|
157
158
|
return datetime.datetime.strptime(value, self.format)
|
|
@@ -166,13 +167,24 @@ class DateTimeField(TableField):
|
|
|
166
167
|
'to': datetime.datetime.strptime(value.get('to'), self.format),
|
|
167
168
|
}
|
|
168
169
|
|
|
169
|
-
raise
|
|
170
|
+
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'datetime'})
|
|
170
171
|
|
|
171
172
|
|
|
172
173
|
@dataclass
|
|
173
174
|
class JSONField(TableField):
|
|
174
175
|
_type = 'json'
|
|
175
176
|
|
|
177
|
+
async def deserialize(self, value, action: DeserializeAction, extra: dict, *args, **kwargs) -> Any:
|
|
178
|
+
value = await super().deserialize(value, action, extra, *args, **kwargs)
|
|
179
|
+
|
|
180
|
+
if value is None:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
if not isinstance(value, (dict, list)):
|
|
184
|
+
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'JSON'})
|
|
185
|
+
|
|
186
|
+
return value
|
|
187
|
+
|
|
176
188
|
|
|
177
189
|
@dataclass
|
|
178
190
|
class ArrayField(TableField):
|
|
@@ -190,8 +202,11 @@ class ArrayField(TableField):
|
|
|
190
202
|
async def deserialize(self, value, action: DeserializeAction, extra: dict, *args, **kwargs) -> Any:
|
|
191
203
|
value = await super().deserialize(value, action, extra, *args, **kwargs)
|
|
192
204
|
|
|
193
|
-
if value
|
|
194
|
-
|
|
205
|
+
if value is None:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
if not isinstance(value, list):
|
|
209
|
+
raise FieldError(_('errors.bad_type_error') % {'type': type(value), 'expected': 'Array'})
|
|
195
210
|
|
|
196
211
|
return value
|
|
197
212
|
|