brilliance-admin 0.43.7__py3-none-any.whl → 0.44.1__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.
@@ -13,8 +13,8 @@
13
13
  <link rel="icon" href="{{ favicon_image }}" />
14
14
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
15
15
  <title>{{ title }}</title>
16
- <script type="module" crossorigin src="/admin/static/index-BnnESruI.js"></script>
17
- <link rel="stylesheet" crossorigin href="/admin/static/index-vlBToOhT.css">
16
+ <script type="module" crossorigin src="/admin/static/index-rBvEkjGg.js"></script>
17
+ <link rel="stylesheet" crossorigin href="/admin/static/index-P_wdMBbz.css">
18
18
  </head>
19
19
 
20
20
  <body>
brilliance_admin/utils.py CHANGED
@@ -5,6 +5,7 @@ from typing import Any, Dict, Protocol
5
5
 
6
6
  import yaml
7
7
  from pydantic import TypeAdapter
8
+ from pydantic.fields import FieldInfo
8
9
  from pydantic_core import core_schema
9
10
 
10
11
 
@@ -37,6 +38,43 @@ class DeserializeAction:
37
38
  FILTERS = 3
38
39
 
39
40
 
41
+ class KwargsInitMixin:
42
+ """
43
+ Принимает только аргументы, объявленные в аннотациях.
44
+ Применяет default / default_factory из Field.
45
+ """
46
+
47
+ def __init__(self, **kwargs):
48
+ annotations = {}
49
+ for cls in type(self).__mro__:
50
+ annotations.update(getattr(cls, '__annotations__', {}))
51
+
52
+ allowed = set(annotations.keys())
53
+
54
+ for key, value in kwargs.items():
55
+ if key not in allowed:
56
+ raise AttributeError(
57
+ f'{type(self).__name__} has no field "{key}". '
58
+ f'Allowed fields: {sorted(allowed)}'
59
+ )
60
+ setattr(self, key, value)
61
+
62
+ self._apply_field_defaults()
63
+
64
+ def _apply_field_defaults(self):
65
+ for cls in type(self).__mro__:
66
+ for name, value in cls.__dict__.items():
67
+ if not isinstance(value, FieldInfo):
68
+ continue
69
+
70
+ # если в инстансе всё ещё FieldInfo — заменить
71
+ if getattr(self, name, None) is value:
72
+ if value.default_factory is not None:
73
+ setattr(self, name, value.default_factory())
74
+ elif value.default is not None:
75
+ setattr(self, name, value.default)
76
+
77
+
40
78
  class DataclassBase:
41
79
  def model_dump(self, *args, **kwargs) -> dict:
42
80
  adapter = TypeAdapter(type(self))
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brilliance-admin
3
- Version: 0.43.7
4
- Summary: Simple and lightweight admin panel framework powered by FastAPI and Vue3 Vuetify together. Some call it heavenly in its brilliance.
5
- License-Expression: AGPL-3.0
3
+ Version: 0.44.1
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
+ License-Expression: MIT
6
6
  Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
@@ -16,6 +16,8 @@ Requires-Dist: faker>=38.2.0; extra == "example"
16
16
  Requires-Dist: pyjwt>=2.10.1; extra == "example"
17
17
  Requires-Dist: structlog>=25.5.0; extra == "example"
18
18
  Requires-Dist: rich>=14.2.0; extra == "example"
19
+ Requires-Dist: asyncpg>=0.31.0; extra == "example"
20
+ Requires-Dist: pydantic-settings>=2.12.0; extra == "example"
19
21
  Provides-Extra: tests
20
22
  Requires-Dist: pytest>=8.4.2; extra == "tests"
21
23
  Requires-Dist: pytest-asyncio>=1.2.0; extra == "tests"
@@ -37,58 +39,69 @@ Dynamic: license-file
37
39
  [![PyPI](https://img.shields.io/pypi/v/brilliance-admin)](https://pypi.org/project/brilliance-admin/)
38
40
  [![CI](https://github.com/brilliance-admin/backend-python/actions/workflows/deploy.yml/badge.svg)](https://github.com/brilliance-admin/backend-python/actions)
39
41
 
40
- Simple and lightweight admin panel framework powered by `FastAPI` and `Vue3` `Vuetify` together. \
42
+ Simple and lightweight data managment framework powered by `FastAPI` and `Vue3` `Vuetify` all-in-one. \
41
43
  Integrated with `SQLAlchemy`. Inspaired by Django Admin and DRF.\
42
44
  _Some call it heavenly in its brilliance._
43
45
 
44
- ### [Live Demo](https://brilliance-admin.com/) | [Demo Sources](https://github.com/brilliance-admin/backend-python/tree/main/example) | Documentation (todo)
46
+ ### [Live Demo](https://brilliance-admin.com/) | [Demo Sources](https://github.com/brilliance-admin/backend-python/tree/main/example) | [Documentation](https://docs.brilliance-admin.com/)
45
47
 
46
48
  <img src="https://github.com/brilliance-admin/backend-python/blob/main/screenshots/websitemockupgenerator.png?raw=true"
47
49
  alt="Preview">
48
50
 
49
51
  </div>
50
52
 
51
- **Key ideas:**
52
- - **API oriented**\
53
- Works entirely on FastAPI and provides a prebuilt SPA [frontend](https://github.com/brilliance-admin/frontend) via static files (Vue3 + Vuetify). No separate startup is required.
54
- > Data generation/updating API separated from rendering fontend with zero hardcode, this makes it possible to have a single frontend with multiple backend implementations in different languages and makes test coverage easier.
55
- - **Rich visualization**\
53
+ ### Brilliance Admin provides
54
+
55
+ A quick way to create a data management interface using:
56
+
57
+ - Admin page - endpoint with a prebuilt SPA [frontend Vue3 + Vuetify](https://github.com/brilliance-admin/frontend) <br>
58
+ This endpoint can be added to any ASGI compatable backend. For existing project or standalone admin app.
59
+ - API to fetch the UI JSON schema
60
+ - API methods for that UI to work with (to read and modify data)
61
+
62
+ ## Key ideas
63
+
64
+ - **API Oriented** <br>
65
+ Data generation/updating API separated from rendering fontend with zero hardcode, this makes it possible to have a single frontend with multiple backend implementations in different languages and makes test coverage easier.
66
+ - **Rich visualization** <br>
56
67
  Providing rich and convenient ways to display and manage data (tables, charts, etc) from any data source.
57
- - **ORM**\
58
- Automatic schema generation and methods for CRUD operations.
59
- - **Minimal boilerplate**\
68
+ - **UI JSON Schema** <br>
69
+ Represents the data describing the structure of entire admin panel UI. <br>
70
+ You only need to specify what should be rendered. The frontend will display it and automatically request data from the backend for rendering or updates.
71
+ - **ORM** <br>
72
+ Automatic generation from ORM for schema UI frontend and backend methods for CRUD operations.
73
+ - **Minimal boilerplate** <br>
60
74
  Focused on simplified, but rich configuration.
61
75
 
62
- **How it works:**
63
- - After authentication, the user receives the admin panel schema, and the frontend renders it
64
- - The frontend communicates with the backend via API to fetch and modify data
65
-
66
- ### Features:
76
+ ## Features
67
77
 
68
78
  * Tables with full CRUD support, including filtering, sorting, and pagination.
69
79
  * Ability to define custom table actions with forms, response messages, and file downloads.
70
80
  * Graphs via ChartJS
71
81
  * Localization support
72
82
  * Adapted for different screen sizes and mobile devices
73
- * Authorization via any account data source
83
+ * Auth via any account data source
74
84
 
75
85
  **Integrations:**
86
+
76
87
  * **SQLAlchemy** - schema autogeneration for tables + CRUD operations + authorization
77
88
 
78
89
  **Planned:**
90
+
79
91
  * Dashboard features
80
92
  * Role-based access permissions system via interface
81
93
  * Backend interface for storing and viewing action history in the admin interface
82
94
  * Nested data support for creation and detail views (inline editing), nested CRUD workflows
83
95
  * Django ORM integration
96
+ * Support for Oauth providers
84
97
 
85
- ## How to use it
86
-
87
- Installation:
98
+ ## Installation:
88
99
  ``` shell
89
100
  pip install brilliance-admin
90
101
  ```
91
102
 
103
+ ## Usage example
104
+
92
105
  You need to generate `AdminSchema` instance:
93
106
  ``` python
94
107
  from brilliance_admin import schema
@@ -101,11 +114,9 @@ class CategoryExample(schema.CategoryTable):
101
114
  admin_schema = schema.AdminSchema(
102
115
  title='Admin Panel',
103
116
  auth=YourAdminAuthentication(),
104
- groups=[
105
- schema.Group(
117
+ categories=[
118
+ schema.Category(
106
119
  slug='example',
107
- title='Example',
108
- icon='mdi-star',
109
120
  categories=[
110
121
  CategoryExample(),
111
122
  ]
@@ -115,98 +126,27 @@ admin_schema = schema.AdminSchema(
115
126
 
116
127
  admin_app = admin_schema.generate_app()
117
128
 
118
- # Your FastAPI app
129
+ # Your FastAPI app (Any ASGI framework can be used)
119
130
  app = FastAPI()
120
131
  app.mount('/admin', admin_app)
121
132
  ```
122
133
 
123
- ## SQLAlchemy integration
124
-
125
- Supports automatic schema generation for CRUD tables:
126
-
127
- ``` python
128
- category = sqlalchemy.SQLAlchemyAdmin(db_async_session=async_sessionmaker, model=Terminal)
129
- ```
130
-
131
- > [!NOTE]
132
- > If `table_schema` is not specified, it will be generated automatically with all discovered fields and relationships
133
-
134
- Now, the `category` instance can be passed to `categories`.
135
-
136
- ### DRF class style schema
137
-
138
- ``` python
139
- from brilliance_admin import sqlalchemy
140
- from brilliance_admin.translations import TranslateText as _
141
-
142
- from your_project.models import Terminal
143
-
144
-
145
- class TerminalFiltersSchema(sqlalchemy.SQLAlchemyFieldsSchema):
146
- model = Terminal
147
- fields = ['id', 'created_at']
148
- created_at = schema.DateTimeField(range=True)
149
-
150
-
151
- class TerminalSchema(sqlalchemy.SQLAlchemyFieldsSchema):
152
- model = Terminal
153
- list_display = ['id', 'merchant_id']
154
-
155
-
156
- class TerminalAdmin(sqlalchemy.SQLAlchemyAdmin):
157
- db_async_session = async_sessionmaker
158
- model = Terminal
159
- title = _('terminals')
160
- icon = 'mdi-console-network-outline'
161
-
162
- ordering_fields = ['id']
163
- search_fields = ['id', 'title']
164
-
165
- table_schema = TerminalSchema()
166
- table_filters = TerminalFiltersSchema()
167
-
168
-
169
- category = TerminalAdmin()
170
- ```
171
-
172
- ### Can be used both via inheritance and instancing
134
+ For more details, check out our [how-to-start documentation](https://docs.brilliance-admin.com/how-to-start/)
173
135
 
174
- Optionally, functional-style generation can be used to reduce boilerplate code
175
-
176
- Availiable for `SQLAlchemyAdmin` and `SQLAlchemyFieldsSchema`
177
-
178
- ``` python
179
- category = sqlalchemy.SQLAlchemyAdmin(
180
- db_async_session=async_sessionmaker,
181
- model=Terminal,
182
-
183
- table_schema = sqlalchemy.SQLAlchemyFieldsSchema(
184
- model=Terminal,
185
- list_display=['id', 'merchant_id'],
186
- ),
187
- table_filters = sqlalchemy.SQLAlchemyFieldsSchema(
188
- model=Terminal,
189
- fields=['id', 'created_at'],
190
- created_at=schema.DateTimeField(range=True),
191
- ),
192
- )
193
- ```
136
+ ## Comparison of Similar Projects
194
137
 
195
- ### SQLAlchemy JWT Authentication
138
+ The project closest in concept is [React Admin](https://github.com/marmelab/react-admin). <br>
139
+ It is an SPA frontend that store the schema UI inside and works with separate API backend providers.
196
140
 
197
- ``` python
198
- auth = sqlalchemy.SQLAlchemyJWTAdminAuthentication(
199
- secret='auth_secret',
200
- db_async_session=async_session,
201
- user_model=User,
202
- )
203
- ```
141
+ The key difference of Brilliance Admin is that its all-in-one. <br>
142
+ It is more focused on rapid setup for data management, without the need to work with frontend configuration, while it still available.
204
143
 
205
- ## Comparison of Similar Projects
144
+ ## Comparison of Similar Python Projects
206
145
 
207
146
  | Criterion | Brilliance Admin | Django Admin | FastAPI Admin | Starlette Admin | SQLAdmin |
208
- |---------|------------------|---------------------|---------------|-----------------|----------|
209
- | Base framework | FastAPI | Django | FastAPI | Starlette / FastAPI | FastAPI / Starlette |
147
+ |---------|------------------|--------------|---------------|-----------------|----------|
148
+ | Base framework | FastAPI | Django | FastAPI | Starlette | FastAPI |
149
+ | ASGI compatible | Yes | Partial | Yes | Yes | Yes |
210
150
  | Rendering model | Prebuilt Vue 3 + Vuetify SPA + Jinja2 | Server-side Django templates | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Bootstrap |
211
151
  | Frontend architecture | Separate frontend (SPA) | Classic server-rendered UI | Server-rendered UI with JS interactivity | Server-rendered UI with JS interactivity | Server-rendered UI |
212
152
  | Data source | Any source + SQLAlchemy | Django ORM | Tortoise ORM | Any source + SQLAlchemy, MongoDB | SQLAlchemy |
@@ -3,7 +3,7 @@ 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
5
  brilliance_admin/translations.py,sha256=I_iSfj05Qv5fbZqDvnnHZGUFsi1wk-J0EXSftKBLw5Q,3850
6
- brilliance_admin/utils.py,sha256=RB88GC3qeysP1PpUGiXSgUZRpdxHGLB0FRgramScLaA,4584
6
+ brilliance_admin/utils.py,sha256=M_0WANlb-1NW4aOA33MxOgoRx0GIVJ6w6PCGKAwmflk,5971
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
@@ -14,7 +14,7 @@ brilliance_admin/api/views/graphs.py,sha256=nn91zoFRZ0FvSkFJoTy7ZQEr8B2cUj43nd8O
14
14
  brilliance_admin/api/views/index.py,sha256=DkMshrs5zmqpbbF9G2RhqeLGFKMrkrAmQ6nnba7aLl8,1400
15
15
  brilliance_admin/api/views/schema.py,sha256=MS9v9Qy3cRO9gGs4uW2PNRBS6Uw48sLRGRe49jnJ2yM,1019
16
16
  brilliance_admin/api/views/settings.py,sha256=2A9suZQONEtW9LkFban29Fe5ipQaaGT0CzpxnbuotJQ,1166
17
- brilliance_admin/api/views/table.py,sha256=29vLEwueHWBS8Dq6nBvujwy4CTs9v8ZcM1ErF9lYgIc,5932
17
+ brilliance_admin/api/views/table.py,sha256=ZCckiEaBVAF7Px-oDWkFkL4F3KmFJi-70LSqFXomovk,5939
18
18
  brilliance_admin/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  brilliance_admin/integrations/sqlalchemy/__init__.py,sha256=AmQHOvegS6_uaE4xYDHzRMdA9PyHn0cCt1s1IWc9G2U,318
20
20
  brilliance_admin/integrations/sqlalchemy/auth.py,sha256=NvOLKeeSJuNTzFhisNO9R3sEmGRS8IQrCwghPrtuzaw,4924
@@ -28,24 +28,23 @@ brilliance_admin/integrations/sqlalchemy/table/delete.py,sha256=toH9at-MAWO46K_4
28
28
  brilliance_admin/integrations/sqlalchemy/table/list.py,sha256=WPH4GoLrIU-TcGMrNoq46i3sJIz6vV76UaacmtG3Ytk,6720
29
29
  brilliance_admin/integrations/sqlalchemy/table/retrieve.py,sha256=O6mJ_XxfLJ59Hx_V5VdAZNxObkY6p5L7gZED8QGXfy0,2744
30
30
  brilliance_admin/integrations/sqlalchemy/table/update.py,sha256=RfIXTQHHEoZCrOtVeOxZ3ql0-is5czsgVAfO_1_gF7w,3578
31
- brilliance_admin/locales/en.yml,sha256=hq4ktzZZYmfbI7RVHHwvkUD9qjETMW1Fq2DQPCQAPao,1159
32
- brilliance_admin/locales/ru.yml,sha256=ySYstybcfNhWUgdYeTnepaddgOlPTu4cIAWKLAVYLeo,1770
33
- brilliance_admin/schema/__init__.py,sha256=X-izShvv84jkFU47WfpUwtvRh3NOv570iUB3NRNEIDU,248
34
- brilliance_admin/schema/admin_schema.py,sha256=fKVtaLkFkDF8ZkjIftackZ4rfCDcqLvci8PO6ZLycgc,6393
35
- brilliance_admin/schema/category.py,sha256=YIRjIwnBcH2QpKQ-9YZFvOajEaYKAqsk91kl8BsviQU,4112
36
- brilliance_admin/schema/group.py,sha256=sp_i98v4W5TaERQxosYpqQmHuGbAfr0zzoJNTWNzbTE,2282
31
+ brilliance_admin/locales/en.yml,sha256=o57Bhh5Z8zC2A1Y2h-iw4t6h9vjhAFQS0mw9J8t2nio,1287
32
+ brilliance_admin/locales/ru.yml,sha256=qquuAGkViLrNtgO0REWXZXlz1Ri2avFS1VmtAeTYwK0,1878
33
+ brilliance_admin/schema/__init__.py,sha256=tZIRTSKFsNOmDqjoAgtYthYrT8ljPvLnYRzfupBLT00,290
34
+ brilliance_admin/schema/admin_schema.py,sha256=9w88GuogRjdphFuDdx7On553qHTwGoJVCyKpooFSKQ8,6723
35
+ brilliance_admin/schema/category.py,sha256=D2aIpDyL-2CibkpenNu8uyh4AzOdQ2ArTDltVYS7xZQ,6592
37
36
  brilliance_admin/schema/graphs/__init__.py,sha256=qvmZv9QWdiutPtN5VYQLYbsjY2SOg8p_XRaz2rUlIxY,44
38
- brilliance_admin/schema/graphs/category_graphs.py,sha256=2nj_oiAoGXwGhc-gNVNFMNKDCkCdUWVn6u9CRCsb2DA,1513
37
+ brilliance_admin/schema/graphs/category_graphs.py,sha256=iTjwjQoZocEfJWJEAdYcJTGCLXWexJVpOiKSfGzrRS8,1486
39
38
  brilliance_admin/schema/table/__init__.py,sha256=vuRw8HBuak2LaTZi2dNn5YOrJPalQps-O3Ht-d0AZV4,378
40
39
  brilliance_admin/schema/table/admin_action.py,sha256=0ymRL9DKkBK-AF6wKy7K9R4hkmblh55eHuZA_rjO1Lk,2018
41
- brilliance_admin/schema/table/category_table.py,sha256=BNdxspZ9Di6_bX0QQEGxgZLlddC7GIAWjBYha6bLtZo,6449
40
+ brilliance_admin/schema/table/category_table.py,sha256=YNDEabnKkIjqhZ0niVOFqXDFIk0I2H6_FbGgbuO5NZ8,6509
42
41
  brilliance_admin/schema/table/fields_schema.py,sha256=Tlnxpzb1RgMKLDqFpRD3t6x9lDEAf--hnmzRC3vHZpo,8350
43
42
  brilliance_admin/schema/table/table_models.py,sha256=xidraifRYbXGkiVLn6dJ96dkOhW8-22ynE-fbiOjfAU,1018
44
43
  brilliance_admin/schema/table/fields/__init__.py,sha256=RW-sIFTAaSQo4mMR6iWtnefogWPjmg6KAsDwe9mKW1k,291
45
- brilliance_admin/schema/table/fields/base.py,sha256=fllUue5ZWj8qA8FGm72zyLHDNyGCkWHLxzpTx6dLLXQ,8507
44
+ brilliance_admin/schema/table/fields/base.py,sha256=HTOMWjuiTSV7lP1F5huUoit06j8Xd8v82cZ3Qz8Y7TI,9182
46
45
  brilliance_admin/schema/table/fields/function_field.py,sha256=4fm9kS8zpBG5oqp9sA81NQDHiqvU0BQmpf-wjkTuuwM,1780
47
- brilliance_admin/static/index-BnnESruI.js,sha256=_ogTWbz9PSzFhjEgdvIJI6PvfgQdtAyTgqg1Z4EZ1eQ,3202453
48
- brilliance_admin/static/index-vlBToOhT.css,sha256=hoVCpcStTHdAVRm37k1umrNdXjOwIIveu9lxk4ocpEc,983028
46
+ brilliance_admin/static/index-P_wdMBbz.css,sha256=Cp6VOK3Vb3pRGYOdLR7fnthIfMD1Kzmey6xPkBc1Jw0,983016
47
+ brilliance_admin/static/index-rBvEkjGg.js,sha256=m0u6zpuBv_okpz5yrnqt4nEJ-JbIeyrXgsuGVeV2EVc,3203281
49
48
  brilliance_admin/static/materialdesignicons-webfont-CYDMK1kx.woff2,sha256=5S1g9kJnzaoIQitQurXUW9NeZisDua91F5zq4ArF_Is,385360
50
49
  brilliance_admin/static/materialdesignicons-webfont-CgCzGbLl.woff,sha256=SNPuxqtw3HoZCPm6LyCOClhxi57hbj9qvbXbT0Yfolg,561776
51
50
  brilliance_admin/static/materialdesignicons-webfont-D3kAzl71.ttf,sha256=vXJaejiTnltZkE4benJlkZ7OwlYWbs5p1RXCEAUWWQc,1243500
@@ -66,9 +65,9 @@ brilliance_admin/static/tinymce/plugins/accordion/css/accordion.css,sha256=u5UQk
66
65
  brilliance_admin/static/tinymce/plugins/codesample/css/prism.css,sha256=exAdMtHbvwW7-DEs567MX65Fq1aJQTfREP5pw8gW-AY,1736
67
66
  brilliance_admin/static/tinymce/plugins/customLink/plugin.js,sha256=illBNpnHDkBsLG6wo_jDPF6z7CGnO1MQWUoDwZKy6vQ,5589
68
67
  brilliance_admin/static/tinymce/plugins/customLink/css/link.css,sha256=gh5nvY8Z92hJfCEBPnIm4jIPCcKKbJnab-30oIfX7Hc,56
69
- brilliance_admin/templates/index.html,sha256=pDpY8Xmn39Y9b85MEy_ytbwa8Cz9-2EsOvTu3qP8bNQ,1294
70
- brilliance_admin-0.43.7.dist-info/licenses/LICENSE,sha256=PjeDRXGbVLtKul5Xpfco_6CyB6bYGWVVPrO0oubquuM,727
71
- brilliance_admin-0.43.7.dist-info/METADATA,sha256=eyl-GfxMxDkszSfjqKbNx2rIOlPC1XA6yDXJV7xCSpY,7860
72
- brilliance_admin-0.43.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
73
- brilliance_admin-0.43.7.dist-info/top_level.txt,sha256=almFFSWrVYieI3i54hYL0fMUaeuIYiazS2Kx4wtK-ns,17
74
- brilliance_admin-0.43.7.dist-info/RECORD,,
68
+ brilliance_admin/templates/index.html,sha256=JK7a-EQtaRweQJ1KoXc3L82M4d7GSCXJEe85cxuvWaQ,1294
69
+ brilliance_admin-0.44.1.dist-info/licenses/LICENSE,sha256=rgWE5Cxk53W0PhTOVmcQedABEWN1QMG-PRz3fz531sE,1074
70
+ brilliance_admin-0.44.1.dist-info/METADATA,sha256=KB9guzLv6WvBDCLv4c93VsKUZ3x6byNXBu3wjw00ZVg,6910
71
+ brilliance_admin-0.44.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
72
+ brilliance_admin-0.44.1.dist-info/top_level.txt,sha256=almFFSWrVYieI3i54hYL0fMUaeuIYiazS2Kx4wtK-ns,17
73
+ brilliance_admin-0.44.1.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brilliance Admin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,67 +0,0 @@
1
- import abc
2
- from typing import Dict, List
3
-
4
- from pydantic.dataclasses import dataclass
5
-
6
- from brilliance_admin.auth import UserABC
7
- from brilliance_admin.schema.category import Category, CategorySchemaData
8
- from brilliance_admin.translations import LanguageContext
9
- from brilliance_admin.utils import DataclassBase, SupportsStr, get_logger, humanize_field_name
10
-
11
- logger = get_logger()
12
-
13
-
14
- @dataclass
15
- class GroupSchemaData(DataclassBase):
16
- title: str | None
17
- description: str | None
18
- icon: str | None
19
- categories: Dict[str, CategorySchemaData]
20
-
21
-
22
- @dataclass
23
- class Group(abc.ABC):
24
- categories: List[Category]
25
- slug: str
26
- title: SupportsStr | None = None
27
- description: SupportsStr | None = None
28
-
29
- # https://pictogrammers.com/library/mdi/
30
- icon: str | None = None
31
-
32
- def __post_init__(self):
33
- for category in self.categories:
34
- if not issubclass(category.__class__, Category):
35
- raise TypeError(f'Category "{category}" is not instance of Category subclass')
36
-
37
- def generate_schema(self, user: UserABC, language_context: LanguageContext) -> GroupSchemaData:
38
- result = GroupSchemaData(
39
- title=language_context.get_text(self.title) or humanize_field_name(self.slug),
40
- description=language_context.get_text(self.description),
41
- icon=self.icon,
42
- categories={},
43
- )
44
- if not self.categories:
45
- logger.warning('Group "%s" %s.categories is empty!', self.slug, type(self).__name__)
46
-
47
- for category in self.categories:
48
-
49
- if not category.slug:
50
- msg = f'Category {type(category).__name__}.slug is empty'
51
- raise AttributeError(msg)
52
-
53
- if category.slug in result.categories:
54
- exists = result.categories[category.slug]
55
- msg = f'Category {type(category).__name__}.slug "{self.slug}" already registered by "{exists.title}"'
56
- raise KeyError(msg)
57
-
58
- result.categories[category.slug] = category.generate_schema(user, language_context)
59
-
60
- return result
61
-
62
- def get_category(self, category_slug: str) -> Category | None:
63
- for category in self.categories:
64
- if category.slug == category_slug:
65
- return category
66
-
67
- return None
@@ -1,17 +0,0 @@
1
- GNU AFFERO GENERAL PUBLIC LICENSE
2
- Version 3, 19 November 2007
3
-
4
- Copyright (C) 2025 Your Name
5
-
6
- This program is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Affero General Public License as published
8
- by the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- This program is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Affero General Public License for more details.
15
-
16
- You should have received a copy of the GNU Affero General Public License
17
- along with this program. If not, see <https://www.gnu.org/licenses/>.