brilliance-admin 0.43.7__py3-none-any.whl → 0.44.0__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/schema/__init__.py +2 -2
- brilliance_admin/schema/admin_schema.py +21 -19
- brilliance_admin/schema/category.py +85 -10
- brilliance_admin/schema/graphs/category_graphs.py +2 -3
- brilliance_admin/schema/table/category_table.py +4 -2
- brilliance_admin/static/{index-BnnESruI.js → index-MLuDem5W.js} +57 -57
- brilliance_admin/static/{index-vlBToOhT.css → index-P_wdMBbz.css} +1 -1
- brilliance_admin/templates/index.html +2 -2
- brilliance_admin/utils.py +38 -0
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.0.dist-info}/METADATA +46 -108
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.0.dist-info}/RECORD +14 -15
- brilliance_admin-0.44.0.dist-info/licenses/LICENSE +21 -0
- brilliance_admin/schema/group.py +0 -67
- brilliance_admin-0.43.7.dist-info/licenses/LICENSE +0 -17
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.0.dist-info}/WHEEL +0 -0
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.0.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# pylint: disable=wildcard-import, unused-wildcard-import, unused-import
|
|
2
2
|
# flake8: noqa: F405
|
|
3
3
|
from .admin_schema import AdminSchema, AdminSchemaData
|
|
4
|
-
from .category import
|
|
4
|
+
from .category import CategoryGroup, CategoryLink
|
|
5
5
|
from .graphs import *
|
|
6
|
-
from .group import Group
|
|
7
6
|
from .table import *
|
|
7
|
+
from .table.category_table import CategoryTable
|
|
@@ -7,11 +7,12 @@ from urllib.parse import urljoin
|
|
|
7
7
|
from fastapi import FastAPI, Request
|
|
8
8
|
from fastapi.middleware.cors import CORSMiddleware
|
|
9
9
|
from fastapi.staticfiles import StaticFiles
|
|
10
|
+
from pydantic import Field
|
|
10
11
|
from pydantic.dataclasses import dataclass
|
|
11
12
|
|
|
12
13
|
from brilliance_admin.auth import UserABC
|
|
13
14
|
from brilliance_admin.docs import build_redoc_docs, build_scalar_docs
|
|
14
|
-
from brilliance_admin.schema.
|
|
15
|
+
from brilliance_admin.schema.category import BaseCategory, CategorySchemaData
|
|
15
16
|
from brilliance_admin.translations import LanguageContext, LanguageManager
|
|
16
17
|
from brilliance_admin.utils import DataclassBase, SupportsStr
|
|
17
18
|
|
|
@@ -23,8 +24,8 @@ DEFAULT_LANGUAGES = {
|
|
|
23
24
|
|
|
24
25
|
@dataclass
|
|
25
26
|
class AdminSchemaData(DataclassBase):
|
|
26
|
-
groups: Dict[str, GroupSchemaData]
|
|
27
27
|
profile: UserABC | Any
|
|
28
|
+
categories: Dict[str, CategorySchemaData] = Field(default_factory=dict)
|
|
28
29
|
|
|
29
30
|
def __post_init__(self):
|
|
30
31
|
if not isinstance(self.profile, UserABC):
|
|
@@ -50,7 +51,7 @@ class AdminIndexContextData(DataclassBase):
|
|
|
50
51
|
|
|
51
52
|
@dataclass
|
|
52
53
|
class AdminSchema:
|
|
53
|
-
|
|
54
|
+
categories: List[BaseCategory]
|
|
54
55
|
auth: Any
|
|
55
56
|
|
|
56
57
|
title: SupportsStr | None = 'Admin'
|
|
@@ -68,9 +69,9 @@ class AdminSchema:
|
|
|
68
69
|
language_manager: LanguageManager | None = None
|
|
69
70
|
|
|
70
71
|
def __post_init__(self):
|
|
71
|
-
for
|
|
72
|
-
if not issubclass(
|
|
73
|
-
raise TypeError(f'
|
|
72
|
+
for category in self.categories:
|
|
73
|
+
if not issubclass(category.__class__, BaseCategory):
|
|
74
|
+
raise TypeError(f'Root category "{category}" is not instance of BaseCategory subclass')
|
|
74
75
|
|
|
75
76
|
if not self.language_manager:
|
|
76
77
|
self.language_manager = LanguageManager(DEFAULT_LANGUAGES)
|
|
@@ -81,24 +82,25 @@ class AdminSchema:
|
|
|
81
82
|
def generate_schema(self, user: UserABC, language_slug: str | None) -> AdminSchemaData:
|
|
82
83
|
language_context: LanguageContext = self.get_language_context(language_slug)
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
result = AdminSchemaData(profile=user)
|
|
85
86
|
|
|
86
|
-
for
|
|
87
|
-
if not
|
|
88
|
-
msg = f'Category
|
|
87
|
+
for category in self.categories:
|
|
88
|
+
if not category.slug:
|
|
89
|
+
msg = f'Category {type(category).__name__}.slug is empty'
|
|
89
90
|
raise AttributeError(msg)
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
try:
|
|
93
|
+
result.categories[category.slug] = category.generate_schema(user, language_context).to_dict(keep_none=False)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
msg = f'Root category "{category.slug}" generate_schema error: {e}'
|
|
96
|
+
raise Exception(msg) from e
|
|
92
97
|
|
|
93
|
-
return
|
|
94
|
-
groups=groups,
|
|
95
|
-
profile=user,
|
|
96
|
-
)
|
|
98
|
+
return result
|
|
97
99
|
|
|
98
|
-
def get_group(self, group_slug: str) -> Optional[
|
|
99
|
-
for
|
|
100
|
-
if
|
|
101
|
-
return
|
|
100
|
+
def get_group(self, group_slug: str) -> Optional[BaseCategory]:
|
|
101
|
+
for category in self.categories:
|
|
102
|
+
if category.slug == group_slug:
|
|
103
|
+
return category
|
|
102
104
|
|
|
103
105
|
return None
|
|
104
106
|
|
|
@@ -4,10 +4,13 @@ from typing import Any, ClassVar, Dict, List
|
|
|
4
4
|
from pydantic import Field
|
|
5
5
|
from pydantic.dataclasses import dataclass
|
|
6
6
|
from pydantic_core import core_schema
|
|
7
|
+
from structlog import get_logger
|
|
7
8
|
|
|
8
9
|
from brilliance_admin.auth import UserABC
|
|
9
10
|
from brilliance_admin.translations import LanguageContext
|
|
10
|
-
from brilliance_admin.utils import DataclassBase, SupportsStr, humanize_field_name
|
|
11
|
+
from brilliance_admin.utils import DataclassBase, KwargsInitMixin, SupportsStr, humanize_field_name
|
|
12
|
+
|
|
13
|
+
logger = get_logger()
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
# pylint: disable=too-many-instance-attributes
|
|
@@ -106,37 +109,56 @@ class CategorySchemaData(DataclassBase):
|
|
|
106
109
|
icon: str | None
|
|
107
110
|
type: str
|
|
108
111
|
|
|
112
|
+
categories: dict = Field(default_factory=dict)
|
|
113
|
+
|
|
109
114
|
table_info: TableInfoSchemaData | None = None
|
|
110
115
|
graph_info: GraphInfoSchemaData | None = None
|
|
111
116
|
|
|
117
|
+
link: str | None = None
|
|
118
|
+
|
|
112
119
|
def __repr__(self):
|
|
113
120
|
return f'<CategorySchemaData type={self.type} "{self.title}">'
|
|
114
121
|
|
|
115
122
|
|
|
116
|
-
class
|
|
117
|
-
slug:
|
|
118
|
-
title:
|
|
119
|
-
description:
|
|
123
|
+
class BaseCategory(KwargsInitMixin, abc.ABC):
|
|
124
|
+
slug: str
|
|
125
|
+
title: SupportsStr | None = None
|
|
126
|
+
description: SupportsStr | None = None
|
|
120
127
|
|
|
121
128
|
# https://pictogrammers.com/library/mdi/
|
|
122
|
-
icon:
|
|
129
|
+
icon: str | None = None
|
|
123
130
|
|
|
124
131
|
_type_slug: ClassVar[str]
|
|
125
132
|
|
|
126
133
|
def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
|
|
127
|
-
|
|
134
|
+
type_slug = getattr(type(self), '_type_slug', None)
|
|
135
|
+
if not type_slug:
|
|
136
|
+
msg = f'{type(self).__name__}._type_slug must be set!'
|
|
137
|
+
raise AttributeError(msg)
|
|
138
|
+
|
|
139
|
+
result = CategorySchemaData(
|
|
128
140
|
title=language_context.get_text(self.title) or humanize_field_name(self.slug),
|
|
129
141
|
description=language_context.get_text(self.description),
|
|
130
142
|
icon=self.icon,
|
|
131
|
-
type=
|
|
143
|
+
type=type_slug,
|
|
132
144
|
)
|
|
145
|
+
return result
|
|
146
|
+
|
|
147
|
+
def __init_subclass__(cls, **kwargs):
|
|
148
|
+
super().__init_subclass__(**kwargs)
|
|
149
|
+
|
|
150
|
+
if cls is BaseCategory:
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
if not issubclass(cls, BaseCategory):
|
|
154
|
+
raise TypeError(f'{cls.__name__} must inherit from Category')
|
|
133
155
|
|
|
134
156
|
@classmethod
|
|
135
157
|
def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> core_schema.CoreSchema:
|
|
136
|
-
def validate(v: Any) -> "
|
|
158
|
+
def validate(v: Any) -> "BaseCategory":
|
|
137
159
|
if isinstance(v, cls):
|
|
138
160
|
return v
|
|
139
|
-
raise TypeError(f"Expected {cls.__name__} instance")
|
|
161
|
+
raise TypeError(f"Expected {cls.__name__} instance, recieved: {type(v)} {v}")
|
|
140
162
|
|
|
141
163
|
return core_schema.no_info_plain_validator_function(
|
|
142
164
|
validate,
|
|
@@ -146,3 +168,56 @@ class Category(abc.ABC):
|
|
|
146
168
|
return_schema=core_schema.str_schema(),
|
|
147
169
|
),
|
|
148
170
|
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class CategoryLink(BaseCategory):
|
|
174
|
+
_type_slug: str = 'link'
|
|
175
|
+
|
|
176
|
+
link: str
|
|
177
|
+
|
|
178
|
+
def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
|
|
179
|
+
result = super().generate_schema(user, language_context)
|
|
180
|
+
result.link = self.link
|
|
181
|
+
return result
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class CategoryGroup(BaseCategory):
|
|
185
|
+
_type_slug: str = 'group'
|
|
186
|
+
|
|
187
|
+
subcategories: list = Field(default_factory=list)
|
|
188
|
+
|
|
189
|
+
def __init__(self, *args, **kwargs):
|
|
190
|
+
super().__init__(*args, **kwargs)
|
|
191
|
+
|
|
192
|
+
for category in self.subcategories:
|
|
193
|
+
if not isinstance(category, BaseCategory):
|
|
194
|
+
raise TypeError(f'Category "{category}" is not instance of BaseCategory subclass')
|
|
195
|
+
|
|
196
|
+
def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
|
|
197
|
+
result = super().generate_schema(user, language_context)
|
|
198
|
+
|
|
199
|
+
for category in self.subcategories:
|
|
200
|
+
|
|
201
|
+
if not category.slug:
|
|
202
|
+
msg = f'Category {type(category).__name__}.slug is empty'
|
|
203
|
+
raise AttributeError(msg)
|
|
204
|
+
|
|
205
|
+
if category.slug in result.categories:
|
|
206
|
+
exists = result.categories[category.slug]
|
|
207
|
+
msg = f'Category {type(category).__name__}.slug "{self.slug}" already registered by "{exists.title}"'
|
|
208
|
+
raise KeyError(msg)
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
result.categories[category.slug] = category.generate_schema(user, language_context)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
msg = f'Category "{category.slug}" {type(category)} generate_schema error: {e}'
|
|
214
|
+
raise Exception(msg) from e
|
|
215
|
+
|
|
216
|
+
return result
|
|
217
|
+
|
|
218
|
+
def get_category(self, category_slug: str):
|
|
219
|
+
for category in self.subcategories:
|
|
220
|
+
if category.slug == category_slug:
|
|
221
|
+
return category
|
|
222
|
+
|
|
223
|
+
return None
|
|
@@ -2,8 +2,7 @@ from typing import Any, Dict, List
|
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
|
|
5
|
-
from brilliance_admin.schema import
|
|
6
|
-
from brilliance_admin.schema.category import GraphInfoSchemaData
|
|
5
|
+
from brilliance_admin.schema.category import BaseCategory, GraphInfoSchemaData
|
|
7
6
|
from brilliance_admin.schema.table.fields_schema import FieldsSchema
|
|
8
7
|
from brilliance_admin.translations import LanguageContext
|
|
9
8
|
from brilliance_admin.utils import SupportsStr
|
|
@@ -26,7 +25,7 @@ class GraphsDataResult(BaseModel):
|
|
|
26
25
|
charts: List[ChartData]
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
class CategoryGraphs(
|
|
28
|
+
class CategoryGraphs(BaseCategory):
|
|
30
29
|
_type_slug: str = 'graphs'
|
|
31
30
|
|
|
32
31
|
search_enabled: bool = False
|
|
@@ -8,7 +8,7 @@ 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 import
|
|
11
|
+
from brilliance_admin.schema.category import BaseCategory
|
|
12
12
|
from brilliance_admin.schema.category import TableInfoSchemaData
|
|
13
13
|
from brilliance_admin.schema.table.admin_action import ActionData, ActionResult
|
|
14
14
|
from brilliance_admin.schema.table.fields_schema import FieldsSchema
|
|
@@ -17,7 +17,7 @@ from brilliance_admin.translations import LanguageContext
|
|
|
17
17
|
from brilliance_admin.utils import DeserializeAction, SupportsStr
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class CategoryTable(
|
|
20
|
+
class CategoryTable(BaseCategory):
|
|
21
21
|
_type_slug: str = 'table'
|
|
22
22
|
|
|
23
23
|
search_enabled: bool = False
|
|
@@ -32,6 +32,8 @@ class CategoryTable(Category):
|
|
|
32
32
|
pk_name: str | None = None
|
|
33
33
|
|
|
34
34
|
def __init__(self, *args, table_schema=None, table_filters=None, **kwargs):
|
|
35
|
+
super().__init__(*args, **kwargs)
|
|
36
|
+
|
|
35
37
|
if table_schema:
|
|
36
38
|
self.table_schema = table_schema
|
|
37
39
|
|