brilliance-admin 0.43.2__py3-none-any.whl → 0.43.4__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/integrations/sqlalchemy/fields_schema.py +15 -12
- brilliance_admin/integrations/sqlalchemy/table/base.py +4 -4
- brilliance_admin/integrations/sqlalchemy/table/retrieve.py +3 -0
- brilliance_admin/schema/category.py +0 -1
- brilliance_admin/schema/table/fields/base.py +37 -8
- brilliance_admin/schema/table/fields_schema.py +2 -1
- brilliance_admin/translations.py +3 -3
- brilliance_admin/utils.py +3 -3
- {brilliance_admin-0.43.2.dist-info → brilliance_admin-0.43.4.dist-info}/METADATA +1 -1
- {brilliance_admin-0.43.2.dist-info → brilliance_admin-0.43.4.dist-info}/RECORD +13 -13
- {brilliance_admin-0.43.2.dist-info → brilliance_admin-0.43.4.dist-info}/WHEEL +0 -0
- {brilliance_admin-0.43.2.dist-info → brilliance_admin-0.43.4.dist-info}/licenses/LICENSE +0 -0
- {brilliance_admin-0.43.2.dist-info → brilliance_admin-0.43.4.dist-info}/top_level.txt +0 -0
|
@@ -54,9 +54,6 @@ class SQLAlchemyFieldsSchema(schema.FieldsSchema):
|
|
|
54
54
|
and not col.primary_key
|
|
55
55
|
)
|
|
56
56
|
|
|
57
|
-
if "choices" in info:
|
|
58
|
-
field_data["choices"] = [(c[0], c[1]) for c in info["choices"]]
|
|
59
|
-
|
|
60
57
|
col_type = col.type
|
|
61
58
|
try:
|
|
62
59
|
py_t = col_type.python_type
|
|
@@ -64,12 +61,16 @@ class SQLAlchemyFieldsSchema(schema.FieldsSchema):
|
|
|
64
61
|
py_t = None
|
|
65
62
|
|
|
66
63
|
impl = getattr(attr, 'impl', None)
|
|
67
|
-
|
|
64
|
+
is_impl_mutable = isinstance(impl, Mutable)
|
|
68
65
|
|
|
69
66
|
# Foreign key column
|
|
70
67
|
if col.foreign_keys:
|
|
71
68
|
continue
|
|
72
69
|
|
|
70
|
+
elif "choices" in info:
|
|
71
|
+
field_data["choices"] = info['choices']
|
|
72
|
+
field_class = schema.ChoiceField
|
|
73
|
+
|
|
73
74
|
elif isinstance(col_type, (sqltypes.BigInteger, sqltypes.Integer)) or py_t is int:
|
|
74
75
|
field_class = schema.IntegerField
|
|
75
76
|
|
|
@@ -97,7 +98,7 @@ class SQLAlchemyFieldsSchema(schema.FieldsSchema):
|
|
|
97
98
|
elif isinstance(col_type, ARRAY):
|
|
98
99
|
field_class = schema.ArrayField
|
|
99
100
|
field_data["array_type"] = type(col_type.item_type).__name__.lower()
|
|
100
|
-
field_data["read_only"] =
|
|
101
|
+
field_data["read_only"] = is_impl_mutable or isinstance(col_type, Mutable)
|
|
101
102
|
|
|
102
103
|
elif isinstance(col_type, sqltypes.NullType):
|
|
103
104
|
continue
|
|
@@ -239,15 +240,17 @@ class SQLAlchemyFieldsSchema(schema.FieldsSchema):
|
|
|
239
240
|
return stmt
|
|
240
241
|
|
|
241
242
|
async def serialize(self, record, extra: dict, *args, **kwargs) -> dict:
|
|
242
|
-
# pylint: disable=import-outside-toplevel
|
|
243
|
-
from sqlalchemy import inspect
|
|
244
243
|
|
|
245
244
|
# Convert model values to dict
|
|
246
|
-
record_data = {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
record_data = {}
|
|
246
|
+
|
|
247
|
+
for slug, field in self.get_fields().items():
|
|
248
|
+
# pylint: disable=protected-access
|
|
249
|
+
if field._type == 'related':
|
|
250
|
+
record_data[slug] = record
|
|
251
|
+
else:
|
|
252
|
+
record_data[slug] = getattr(record, slug, None)
|
|
253
|
+
|
|
251
254
|
return await super().serialize(record_data, extra, *args, **kwargs)
|
|
252
255
|
|
|
253
256
|
def validate_incoming_data(self, data):
|
|
@@ -123,11 +123,11 @@ class SQLAlchemyAdminBase(SQLAlchemyAdminAutocompleteMixin, CategoryTable):
|
|
|
123
123
|
# pylint: disable=protected-access
|
|
124
124
|
if field._type == "related":
|
|
125
125
|
|
|
126
|
-
# pylint: disable=import-outside-toplevel
|
|
127
|
-
from sqlalchemy import inspect
|
|
128
|
-
|
|
129
|
-
model_attrs = [attr.key for attr in inspect(self.model).mapper.attrs]
|
|
130
126
|
if not hasattr(self.model, field.rel_name):
|
|
127
|
+
# pylint: disable=import-outside-toplevel
|
|
128
|
+
from sqlalchemy import inspect
|
|
129
|
+
model_attrs = [attr.key for attr in inspect(self.model).mapper.attrs]
|
|
130
|
+
|
|
131
131
|
msg = EXCEPTION_REL_NAME.format(
|
|
132
132
|
slug=slug,
|
|
133
133
|
model_name=self.model.__name__,
|
|
@@ -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.integrations.sqlalchemy.fields_schema import SQLAlchemyFieldsSchema
|
|
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
|
|
@@ -12,6 +13,8 @@ logger = get_logger()
|
|
|
12
13
|
class SQLAlchemyAdminRetrieveMixin:
|
|
13
14
|
has_retrieve: bool = True
|
|
14
15
|
|
|
16
|
+
table_schema: SQLAlchemyFieldsSchema
|
|
17
|
+
|
|
15
18
|
async def retrieve(
|
|
16
19
|
self,
|
|
17
20
|
pk: Any,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import datetime
|
|
3
|
-
from
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any, ClassVar
|
|
4
5
|
|
|
5
6
|
from pydantic.dataclasses import dataclass
|
|
6
7
|
|
|
@@ -52,6 +53,8 @@ class TableField(abc.ABC, FieldSchemaData):
|
|
|
52
53
|
class IntegerField(TableField):
|
|
53
54
|
_type = 'integer'
|
|
54
55
|
|
|
56
|
+
choices: Any | None = None
|
|
57
|
+
|
|
55
58
|
max_value: int | None = None
|
|
56
59
|
min_value: int | None = None
|
|
57
60
|
|
|
@@ -62,8 +65,6 @@ class IntegerField(TableField):
|
|
|
62
65
|
def generate_schema(self, user, field_slug, language_context: LanguageContext) -> FieldSchemaData:
|
|
63
66
|
schema = super().generate_schema(user, field_slug, language_context)
|
|
64
67
|
|
|
65
|
-
schema.choices = self.choices
|
|
66
|
-
|
|
67
68
|
if self.max_value is not None:
|
|
68
69
|
schema.max_value = self.max_value
|
|
69
70
|
|
|
@@ -95,13 +96,12 @@ class StringField(TableField):
|
|
|
95
96
|
min_length: int | None = None
|
|
96
97
|
max_length: int | None = None
|
|
97
98
|
|
|
98
|
-
choices:
|
|
99
|
+
choices: Any | None = None
|
|
99
100
|
|
|
100
101
|
def generate_schema(self, user, field_slug, language_context: LanguageContext) -> FieldSchemaData:
|
|
101
102
|
schema = super().generate_schema(user, field_slug, language_context)
|
|
102
103
|
|
|
103
104
|
schema.multilined = self.multilined
|
|
104
|
-
schema.choices = self.choices
|
|
105
105
|
schema.ckeditor = self.ckeditor
|
|
106
106
|
schema.tinymce = self.tinymce
|
|
107
107
|
|
|
@@ -227,23 +227,52 @@ class ImageField(TableField):
|
|
|
227
227
|
class ChoiceField(TableField):
|
|
228
228
|
_type = 'choice'
|
|
229
229
|
|
|
230
|
+
# Tag color available:
|
|
230
231
|
# https://vuetifyjs.com/en/styles/colors/#classes
|
|
231
|
-
|
|
232
|
+
choices: Any | None = None
|
|
232
233
|
|
|
233
234
|
# https://vuetifyjs.com/en/components/chips/#color-and-variants
|
|
234
235
|
variant: str = 'elevated'
|
|
235
236
|
size: str = 'default'
|
|
236
237
|
|
|
238
|
+
def __post_init__(self):
|
|
239
|
+
self.choices = self.generate_choices()
|
|
240
|
+
|
|
241
|
+
def generate_choices(self):
|
|
242
|
+
if not self.choices:
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
if issubclass(self.choices, Enum):
|
|
246
|
+
return [
|
|
247
|
+
{'value': c.value, 'title': c.label, 'tag_color': getattr(c, 'tag_color', None)}
|
|
248
|
+
for c in self.choices
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
msg = f'Field choices is not suppored: {self.choices}'
|
|
252
|
+
raise NotImplementedError(msg)
|
|
253
|
+
|
|
254
|
+
def find_choice(self, value):
|
|
255
|
+
if not self.choices:
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
return next((c for c in self.choices if c.get('value') == value), None)
|
|
259
|
+
|
|
237
260
|
def generate_schema(self, user, field_slug, language_context: LanguageContext) -> FieldSchemaData:
|
|
238
261
|
schema = super().generate_schema(user, field_slug, language_context)
|
|
239
262
|
|
|
240
263
|
schema.choices = self.choices
|
|
241
264
|
|
|
242
|
-
schema.tag_colors = self.tag_colors
|
|
243
265
|
schema.size = self.size
|
|
244
266
|
schema.variant = self.variant
|
|
245
267
|
|
|
246
268
|
return schema
|
|
247
269
|
|
|
248
270
|
async def serialize(self, value, extra: dict, *args, **kwargs) -> Any:
|
|
249
|
-
|
|
271
|
+
if not value:
|
|
272
|
+
return
|
|
273
|
+
|
|
274
|
+
choice = self.find_choice(value)
|
|
275
|
+
return {
|
|
276
|
+
'value': value,
|
|
277
|
+
'title': choice.get('title') or value if choice else value.capitalize(),
|
|
278
|
+
}
|
|
@@ -148,9 +148,10 @@ class FieldsSchema:
|
|
|
148
148
|
list_display=self.list_display,
|
|
149
149
|
)
|
|
150
150
|
|
|
151
|
+
context = {'language_context': language_context}
|
|
151
152
|
for field_slug, field in self.get_fields().items():
|
|
152
153
|
field_schema: FieldSchemaData = field.generate_schema(user, field_slug, language_context)
|
|
153
|
-
fields_schema.fields[field_slug] = field_schema.to_dict(keep_none=False)
|
|
154
|
+
fields_schema.fields[field_slug] = field_schema.to_dict(keep_none=False, context=context)
|
|
154
155
|
|
|
155
156
|
return fields_schema
|
|
156
157
|
|
brilliance_admin/translations.py
CHANGED
|
@@ -63,14 +63,14 @@ class LanguageManager(abc.ABC):
|
|
|
63
63
|
|
|
64
64
|
builtin_locales_dir = resources.files("brilliance_admin").joinpath("locales")
|
|
65
65
|
self.phrases.load_folder(builtin_locales_dir)
|
|
66
|
-
logger.
|
|
66
|
+
logger.debug('Language manager builtin dir loaded: %s', builtin_locales_dir)
|
|
67
67
|
|
|
68
68
|
if locales_dir:
|
|
69
69
|
self.phrases.load_folder(locales_dir)
|
|
70
|
-
logger.
|
|
70
|
+
logger.debug('Language manager locales_dir loaded: %s', locales_dir)
|
|
71
71
|
|
|
72
72
|
langs = ', '.join(self.phrases.data.keys())
|
|
73
|
-
logger.
|
|
73
|
+
logger.debug('Language manager setup completed; languages: %s', langs)
|
|
74
74
|
|
|
75
75
|
def get_text(self, text, language) -> str:
|
|
76
76
|
if not isinstance(text, TranslateText):
|
brilliance_admin/utils.py
CHANGED
|
@@ -42,8 +42,8 @@ class DataclassBase:
|
|
|
42
42
|
adapter = TypeAdapter(type(self))
|
|
43
43
|
return adapter.dump_python(self, *args, **kwargs)
|
|
44
44
|
|
|
45
|
-
def to_dict(self, keep_none=True) -> dict:
|
|
46
|
-
data = self.model_dump()
|
|
45
|
+
def to_dict(self, *args, keep_none=True, **kwargs) -> dict:
|
|
46
|
+
data = self.model_dump(*args, **kwargs)
|
|
47
47
|
return {
|
|
48
48
|
k: v for k, v in data.items()
|
|
49
49
|
if v is not None and not keep_none
|
|
@@ -150,4 +150,4 @@ class YamlI18n:
|
|
|
150
150
|
if isinstance(node, str):
|
|
151
151
|
return node
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
return slug
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brilliance-admin
|
|
3
|
-
Version: 0.43.
|
|
3
|
+
Version: 0.43.4
|
|
4
4
|
Summary: Simple and lightweight admin panel framework powered by FastAPI and Vue3 Vuetify together.. Some call it heavenly in its brilliance.
|
|
5
5
|
License-Expression: AGPL-3.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -2,8 +2,8 @@ brilliance_admin/__init__.py,sha256=qxGzLVhFNm2FKL2lVt7bEFb6pTPqyXEQvUsDfyfv6SM,
|
|
|
2
2
|
brilliance_admin/auth.py,sha256=d57XRfLJIbOosLP1-0SCFkePPT8M5WhLcwxu4yW92RA,673
|
|
3
3
|
brilliance_admin/docs.py,sha256=fKeJKuiCCi1jHRmNcmkuDD6_2di7bwc6-w8V1VCTu0s,1231
|
|
4
4
|
brilliance_admin/exceptions.py,sha256=7_L3qVTwdLrzmDJjGv2yqCOVECP35wh0NyTvgjP7ETc,913
|
|
5
|
-
brilliance_admin/translations.py,sha256=
|
|
6
|
-
brilliance_admin/utils.py,sha256=
|
|
5
|
+
brilliance_admin/translations.py,sha256=I_iSfj05Qv5fbZqDvnnHZGUFsi1wk-J0EXSftKBLw5Q,3850
|
|
6
|
+
brilliance_admin/utils.py,sha256=RB88GC3qeysP1PpUGiXSgUZRpdxHGLB0FRgramScLaA,4584
|
|
7
7
|
brilliance_admin/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
brilliance_admin/api/routers.py,sha256=GXz-GFXRH5VbDH1r5O9LLnnmaMhbQq4RctzVEubHnsk,810
|
|
9
9
|
brilliance_admin/api/utils.py,sha256=ezvHK49OlpCdT9fLB41Y1nswZDLdzC3zTcQtGtuTYUk,999
|
|
@@ -20,29 +20,29 @@ brilliance_admin/integrations/sqlalchemy/__init__.py,sha256=tIegMU2eIW_zA-PdblCX
|
|
|
20
20
|
brilliance_admin/integrations/sqlalchemy/auth.py,sha256=99O7zmhcKWB3cWGTbMd3OSyIJ81Vcfz7byDK6oLinm8,4910
|
|
21
21
|
brilliance_admin/integrations/sqlalchemy/autocomplete.py,sha256=baRroMwGg35uR5zt-aiQc2-ugX4hpwNf79R6bZH9UX0,1416
|
|
22
22
|
brilliance_admin/integrations/sqlalchemy/fields.py,sha256=giVCIixwHz1iHFYHdi39_s4zo9cSZA_0CUoEAJRUGps,9467
|
|
23
|
-
brilliance_admin/integrations/sqlalchemy/fields_schema.py,sha256=
|
|
23
|
+
brilliance_admin/integrations/sqlalchemy/fields_schema.py,sha256=7WkOrt5dVvrsZppNZEZS8QaQPMSrfcWChwOaOFSRVOg,11419
|
|
24
24
|
brilliance_admin/integrations/sqlalchemy/table/__init__.py,sha256=g_in2pLTi8UQnT5uNFA8mLW5mxlT84irQ7yVaP_OSS4,605
|
|
25
|
-
brilliance_admin/integrations/sqlalchemy/table/base.py,sha256
|
|
25
|
+
brilliance_admin/integrations/sqlalchemy/table/base.py,sha256=-osqhTvqE7YcBxsAjqIUMWyYk1df04GIDmdvtieTXcg,4885
|
|
26
26
|
brilliance_admin/integrations/sqlalchemy/table/create.py,sha256=z40PuKJYZ6goJdhsANVuEyTW1gh0PipCBdBSe5Ii5Tw,2693
|
|
27
27
|
brilliance_admin/integrations/sqlalchemy/table/delete.py,sha256=Awv50IG7DQsYrHVlk4dtYBMwexmlO92xhMBgrgEDBgs,731
|
|
28
28
|
brilliance_admin/integrations/sqlalchemy/table/list.py,sha256=--KVTLbuCr1fD79q0LXqlu6CuiYA3QhQj6rrdP7jR14,6692
|
|
29
|
-
brilliance_admin/integrations/sqlalchemy/table/retrieve.py,sha256=
|
|
29
|
+
brilliance_admin/integrations/sqlalchemy/table/retrieve.py,sha256=ny60-YN_ndUyibVd5cwogEFKXtzguJmWas2_xoQk3vQ,2272
|
|
30
30
|
brilliance_admin/integrations/sqlalchemy/table/update.py,sha256=AGEEbEsgKre784Dg4_kTKB6NfMwdAwNiMjm0ZKeg-LE,3543
|
|
31
31
|
brilliance_admin/locales/en.yml,sha256=lCM58SoP4HExXFCTHpl8pYw82tH_8TvlrcCXZDXYb5c,1129
|
|
32
32
|
brilliance_admin/locales/ru.yml,sha256=hXZwS71Z_aAyK9DB14pwmbtLI5xn6PvsnuLIZlEexbM,1661
|
|
33
33
|
brilliance_admin/schema/__init__.py,sha256=X-izShvv84jkFU47WfpUwtvRh3NOv570iUB3NRNEIDU,248
|
|
34
34
|
brilliance_admin/schema/admin_schema.py,sha256=fKVtaLkFkDF8ZkjIftackZ4rfCDcqLvci8PO6ZLycgc,6393
|
|
35
|
-
brilliance_admin/schema/category.py,sha256=
|
|
35
|
+
brilliance_admin/schema/category.py,sha256=hkE4BJQeNbjtuloIgkNEy8Fz068lcMK98-lnZADClg4,4070
|
|
36
36
|
brilliance_admin/schema/group.py,sha256=Gdz3ME_EfQP_CFPou6OOJZWGWXKIYgB3zNX_oWsClwE,2240
|
|
37
37
|
brilliance_admin/schema/graphs/__init__.py,sha256=qvmZv9QWdiutPtN5VYQLYbsjY2SOg8p_XRaz2rUlIxY,44
|
|
38
38
|
brilliance_admin/schema/graphs/category_graphs.py,sha256=2nj_oiAoGXwGhc-gNVNFMNKDCkCdUWVn6u9CRCsb2DA,1513
|
|
39
39
|
brilliance_admin/schema/table/__init__.py,sha256=vuRw8HBuak2LaTZi2dNn5YOrJPalQps-O3Ht-d0AZV4,378
|
|
40
40
|
brilliance_admin/schema/table/admin_action.py,sha256=0ymRL9DKkBK-AF6wKy7K9R4hkmblh55eHuZA_rjO1Lk,2018
|
|
41
41
|
brilliance_admin/schema/table/category_table.py,sha256=BNdxspZ9Di6_bX0QQEGxgZLlddC7GIAWjBYha6bLtZo,6449
|
|
42
|
-
brilliance_admin/schema/table/fields_schema.py,sha256=
|
|
42
|
+
brilliance_admin/schema/table/fields_schema.py,sha256=Tlnxpzb1RgMKLDqFpRD3t6x9lDEAf--hnmzRC3vHZpo,8350
|
|
43
43
|
brilliance_admin/schema/table/table_models.py,sha256=xidraifRYbXGkiVLn6dJ96dkOhW8-22ynE-fbiOjfAU,1018
|
|
44
44
|
brilliance_admin/schema/table/fields/__init__.py,sha256=RW-sIFTAaSQo4mMR6iWtnefogWPjmg6KAsDwe9mKW1k,291
|
|
45
|
-
brilliance_admin/schema/table/fields/base.py,sha256=
|
|
45
|
+
brilliance_admin/schema/table/fields/base.py,sha256=fllUue5ZWj8qA8FGm72zyLHDNyGCkWHLxzpTx6dLLXQ,8507
|
|
46
46
|
brilliance_admin/schema/table/fields/function_field.py,sha256=4fm9kS8zpBG5oqp9sA81NQDHiqvU0BQmpf-wjkTuuwM,1780
|
|
47
47
|
brilliance_admin/static/index-D9axz5zK.js,sha256=KB_EHC9hoBK_LinkeMaE897Ws4Tl8xlJ8c_smbis_VE,3202111
|
|
48
48
|
brilliance_admin/static/index-vlBToOhT.css,sha256=hoVCpcStTHdAVRm37k1umrNdXjOwIIveu9lxk4ocpEc,983028
|
|
@@ -67,8 +67,8 @@ brilliance_admin/static/tinymce/plugins/codesample/css/prism.css,sha256=exAdMtHb
|
|
|
67
67
|
brilliance_admin/static/tinymce/plugins/customLink/plugin.js,sha256=illBNpnHDkBsLG6wo_jDPF6z7CGnO1MQWUoDwZKy6vQ,5589
|
|
68
68
|
brilliance_admin/static/tinymce/plugins/customLink/css/link.css,sha256=gh5nvY8Z92hJfCEBPnIm4jIPCcKKbJnab-30oIfX7Hc,56
|
|
69
69
|
brilliance_admin/templates/index.html,sha256=ZLJ_TKUvBDIo_hYfbW43ov0S_bFrzBF-283XP6BKtDI,1294
|
|
70
|
-
brilliance_admin-0.43.
|
|
71
|
-
brilliance_admin-0.43.
|
|
72
|
-
brilliance_admin-0.43.
|
|
73
|
-
brilliance_admin-0.43.
|
|
74
|
-
brilliance_admin-0.43.
|
|
70
|
+
brilliance_admin-0.43.4.dist-info/licenses/LICENSE,sha256=PjeDRXGbVLtKul5Xpfco_6CyB6bYGWVVPrO0oubquuM,727
|
|
71
|
+
brilliance_admin-0.43.4.dist-info/METADATA,sha256=XowThszR-MHi2j4ceq8Otv64Kq6qMFDsUAnAB9L0IO0,7459
|
|
72
|
+
brilliance_admin-0.43.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
73
|
+
brilliance_admin-0.43.4.dist-info/top_level.txt,sha256=almFFSWrVYieI3i54hYL0fMUaeuIYiazS2Kx4wtK-ns,17
|
|
74
|
+
brilliance_admin-0.43.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|