amsdal 0.3.5__cp312-cp312-macosx_10_13_universal2.whl → 0.4.0__cp312-cp312-macosx_10_13_universal2.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.
Potentially problematic release.
This version of amsdal might be problematic. Click here for more details.
- amsdal/__about__.py +1 -1
- amsdal/__migrations__/0000_initial.py +34 -25
- amsdal/__migrations__/0001_datetime_type.py +4 -4
- amsdal/__migrations__/0002_fixture_order.py +7 -3
- amsdal/__migrations__/0003_schema_type_in_class_meta.py +3 -15
- amsdal/cloud/__init__.cpython-312-darwin.so +0 -0
- amsdal/cloud/client.cpython-312-darwin.so +0 -0
- amsdal/cloud/constants.cpython-312-darwin.so +0 -0
- amsdal/cloud/enums.cpython-312-darwin.so +0 -0
- amsdal/cloud/models/__init__.cpython-312-darwin.so +0 -0
- amsdal/cloud/models/base.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/__init__.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/__init__.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/add_allowlist_ip.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/add_basic_auth.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/add_dependency.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/add_secret.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/base.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/create_deploy.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/create_env.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/create_session.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/delete_allowlist_ip.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/delete_basic_auth.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/delete_dependency.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/delete_env.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/delete_secret.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/destroy_deploy.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/expose_db.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/get_monitoring_info.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/list_dependencies.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/list_deploys.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/list_envs.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/list_secrets.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/manager.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/signup_action.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/actions/update_deploy.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/__init__.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/base.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/credentials.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/credentials.pyi +0 -1
- amsdal/cloud/services/auth/manager.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/signup_service.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/token.cpython-312-darwin.so +0 -0
- amsdal/cloud/services/auth/token.pyi +0 -1
- amsdal/configs/main.py +23 -19
- amsdal/configs/main.pyi +12 -15
- amsdal/contrib/__init__.cpython-312-darwin.so +0 -0
- amsdal/contrib/auth/lifecycle/consumer.py +10 -10
- amsdal/contrib/auth/migrations/0000_initial.py +41 -7
- amsdal/contrib/auth/models/login_session.py +66 -0
- amsdal/contrib/auth/models/login_session.pyi +33 -0
- amsdal/contrib/auth/models/permission.py +23 -0
- amsdal/contrib/auth/models/permission.pyi +18 -0
- amsdal/contrib/auth/models/user.py +106 -0
- amsdal/contrib/auth/models/user.pyi +46 -0
- amsdal/contrib/frontend_configs/conversion/convert.py +47 -15
- amsdal/contrib/frontend_configs/conversion/convert.pyi +0 -1
- amsdal/contrib/frontend_configs/lifecycle/consumer.py +32 -13
- amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +1 -1
- amsdal/contrib/frontend_configs/migrations/0000_initial.py +15 -14
- amsdal/contrib/frontend_configs/models/__init__.py +0 -0
- amsdal/contrib/frontend_configs/models/__init__.pyi +0 -0
- amsdal/contrib/frontend_configs/models/frontend_activator_config.py +22 -0
- amsdal/contrib/frontend_configs/models/frontend_activator_config.pyi +12 -0
- amsdal/contrib/frontend_configs/models/frontend_config_async_validator.py +11 -0
- amsdal/contrib/frontend_configs/models/frontend_config_async_validator.pyi +7 -0
- amsdal/contrib/frontend_configs/models/frontend_config_control_action.py +54 -0
- amsdal/contrib/frontend_configs/models/frontend_config_control_action.pyi +32 -0
- amsdal/contrib/frontend_configs/models/frontend_config_group_validator.py +21 -0
- amsdal/contrib/frontend_configs/models/frontend_config_group_validator.pyi +11 -0
- amsdal/contrib/frontend_configs/models/frontend_config_option.py +12 -0
- amsdal/contrib/frontend_configs/models/frontend_config_option.pyi +8 -0
- amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.py +17 -0
- amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.pyi +8 -0
- amsdal/contrib/frontend_configs/models/frontend_config_slider_option.py +13 -0
- amsdal/contrib/frontend_configs/models/frontend_config_slider_option.pyi +9 -0
- amsdal/contrib/frontend_configs/models/frontend_config_text_mask.py +14 -0
- amsdal/contrib/frontend_configs/models/frontend_config_text_mask.pyi +10 -0
- amsdal/contrib/frontend_configs/models/frontend_config_validator.py +28 -0
- amsdal/contrib/frontend_configs/models/frontend_config_validator.pyi +15 -0
- amsdal/contrib/frontend_configs/models/frontend_control_config.py +87 -0
- amsdal/contrib/frontend_configs/models/frontend_control_config.pyi +35 -0
- amsdal/contrib/frontend_configs/models/frontend_model_config.py +14 -0
- amsdal/contrib/frontend_configs/models/frontend_model_config.pyi +9 -0
- amsdal/errors.py +0 -3
- amsdal/errors.pyi +0 -1
- amsdal/fixtures/__init__.cpython-312-darwin.so +0 -0
- amsdal/fixtures/manager.cpython-312-darwin.so +0 -0
- amsdal/fixtures/manager.pyi +73 -123
- amsdal/fixtures/utils.cpython-312-darwin.so +0 -0
- amsdal/fixtures/utils.pyi +9 -0
- amsdal/manager.cpython-312-darwin.so +0 -0
- amsdal/manager.pyi +4 -96
- amsdal/mixins/__init__.cpython-312-darwin.so +0 -0
- amsdal/mixins/class_versions_mixin.cpython-312-darwin.so +0 -0
- amsdal/models/__init__.py +0 -0
- amsdal/models/__init__.pyi +0 -0
- amsdal/models/core/__init__.py +0 -0
- amsdal/models/core/__init__.pyi +0 -0
- amsdal/models/core/class_object.py +37 -0
- amsdal/models/core/class_object.pyi +24 -0
- amsdal/models/core/class_object_meta.py +26 -0
- amsdal/models/core/class_object_meta.pyi +15 -0
- amsdal/models/core/class_property.py +19 -0
- amsdal/models/core/class_property.pyi +10 -0
- amsdal/models/core/class_property_meta.py +15 -0
- amsdal/models/core/class_property_meta.pyi +10 -0
- amsdal/models/core/file.py +156 -0
- amsdal/models/core/file.pyi +104 -0
- amsdal/models/core/fixture.py +25 -0
- amsdal/models/core/fixture.pyi +14 -0
- amsdal/models/core/option.py +11 -0
- amsdal/models/core/option.pyi +8 -0
- amsdal/models/core/validator.py +12 -0
- amsdal/models/core/validator.pyi +8 -0
- amsdal/models/types/__init__.py +0 -0
- amsdal/models/types/__init__.pyi +0 -0
- amsdal/models/types/object.py +26 -0
- amsdal/models/types/object.pyi +16 -0
- amsdal/schemas/core/file/properties/from_file.py +1 -1
- amsdal/schemas/core/file/properties/validate_data.py +1 -1
- amsdal/schemas/interfaces.py +25 -0
- amsdal/schemas/interfaces.pyi +20 -0
- amsdal/schemas/manager.cpython-312-darwin.so +0 -0
- amsdal/schemas/manager.py +0 -116
- amsdal/schemas/manager.pyi +0 -65
- amsdal/schemas/mixins/__init__.py +0 -0
- amsdal/schemas/mixins/__init__.pyi +0 -0
- amsdal/schemas/mixins/check_dependencies_mixin.py +115 -0
- amsdal/schemas/mixins/check_dependencies_mixin.pyi +42 -0
- amsdal/schemas/mixins/verify_schemas_mixin.py +96 -0
- amsdal/schemas/mixins/verify_schemas_mixin.pyi +33 -0
- amsdal/schemas/repository.py +84 -0
- amsdal/schemas/repository.pyi +22 -0
- amsdal/schemas/utils.py +16 -0
- amsdal/schemas/utils.pyi +10 -0
- amsdal/services/__init__.cpython-312-darwin.so +0 -0
- amsdal/services/transaction_execution.cpython-312-darwin.so +0 -0
- amsdal/services/transaction_execution.pyi +1 -1
- amsdal/utils/rollback/__init__.py +99 -54
- amsdal/utils/tests/helpers.py +185 -36
- {amsdal-0.3.5.dist-info → amsdal-0.4.0.dist-info}/METADATA +8 -8
- {amsdal-0.3.5.dist-info → amsdal-0.4.0.dist-info}/RECORD +150 -142
- {amsdal-0.3.5.dist-info → amsdal-0.4.0.dist-info}/WHEEL +1 -1
- amsdal/contrib/auth/models/login_session/hooks/pre_init.py +0 -68
- amsdal/contrib/auth/models/login_session/model.json +0 -23
- amsdal/contrib/auth/models/login_session/modifiers/display_name.py +0 -11
- amsdal/contrib/auth/models/permission/fixtures/basic_permissions.json +0 -62
- amsdal/contrib/auth/models/permission/model.json +0 -18
- amsdal/contrib/auth/models/permission/modifiers/display_name.py +0 -11
- amsdal/contrib/auth/models/user/hooks/post_init.py +0 -76
- amsdal/contrib/auth/models/user/hooks/pre_create.py +0 -8
- amsdal/contrib/auth/models/user/model.json +0 -25
- amsdal/contrib/auth/models/user/modifiers/display_name.py +0 -19
- amsdal/contrib/frontend_configs/models/frontend_activator_config/model.json +0 -11
- amsdal/contrib/frontend_configs/models/frontend_config_async_validator/model.json +0 -11
- amsdal/contrib/frontend_configs/models/frontend_config_group_validator/model.json +0 -52
- amsdal/contrib/frontend_configs/models/frontend_config_option/model.json +0 -15
- amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base/model.json +0 -6
- amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base/properties/model_dump.py +0 -13
- amsdal/contrib/frontend_configs/models/frontend_config_slider_option/model.json +0 -19
- amsdal/contrib/frontend_configs/models/frontend_config_text_mask/model.json +0 -26
- amsdal/contrib/frontend_configs/models/frontend_config_validator/model.json +0 -41
- amsdal/contrib/frontend_configs/models/frontend_control_config/model.json +0 -250
- amsdal/contrib/frontend_configs/models/frontend_model_config/fixtures/permissions.json +0 -24
- amsdal/contrib/frontend_configs/models/frontend_model_config/model.json +0 -17
- amsdal/contrib/frontend_configs/models/frontent_config_control_action/model.json +0 -54
- amsdal/contrib/frontend_configs/models/frontent_config_control_action/properties/action_validate.py +0 -33
- amsdal/migration/__init__.cpython-312-darwin.so +0 -0
- amsdal/migration/base_migration_schemas.cpython-312-darwin.so +0 -0
- amsdal/migration/base_migration_schemas.pyi +0 -120
- amsdal/migration/data_classes.cpython-312-darwin.so +0 -0
- amsdal/migration/data_classes.pyi +0 -172
- amsdal/migration/executors/__init__.cpython-312-darwin.so +0 -0
- amsdal/migration/executors/base.cpython-312-darwin.so +0 -0
- amsdal/migration/executors/base.pyi +0 -118
- amsdal/migration/executors/default_executor.cpython-312-darwin.so +0 -0
- amsdal/migration/executors/default_executor.pyi +0 -184
- amsdal/migration/executors/state_executor.cpython-312-darwin.so +0 -0
- amsdal/migration/executors/state_executor.pyi +0 -151
- amsdal/migration/file_migration_executor.cpython-312-darwin.so +0 -0
- amsdal/migration/file_migration_executor.pyi +0 -122
- amsdal/migration/file_migration_generator.cpython-312-darwin.so +0 -0
- amsdal/migration/file_migration_generator.pyi +0 -229
- amsdal/migration/file_migration_store.cpython-312-darwin.so +0 -0
- amsdal/migration/file_migration_store.pyi +0 -114
- amsdal/migration/file_migration_writer.cpython-312-darwin.so +0 -0
- amsdal/migration/file_migration_writer.pyi +0 -73
- amsdal/migration/migrations.cpython-312-darwin.so +0 -0
- amsdal/migration/migrations.pyi +0 -166
- amsdal/migration/migrations_loader.cpython-312-darwin.so +0 -0
- amsdal/migration/migrations_loader.pyi +0 -32
- amsdal/migration/schemas_loaders.cpython-312-darwin.so +0 -0
- amsdal/migration/schemas_loaders.pyi +0 -37
- amsdal/migration/templates/data_migration.tmpl +0 -18
- amsdal/migration/templates/dict_validator.tmpl +0 -4
- amsdal/migration/templates/migration.tmpl +0 -6
- amsdal/migration/templates/model_class.tmpl +0 -8
- amsdal/migration/templates/model_class_layout.tmpl +0 -24
- amsdal/migration/templates/options_validator.tmpl +0 -4
- amsdal/migration/utils.cpython-312-darwin.so +0 -0
- amsdal/migration/utils.pyi +0 -58
- amsdal/mixins/build_mixin.cpython-312-darwin.so +0 -0
- amsdal/mixins/build_mixin.pyi +0 -78
- /amsdal/{migration/__init__.pyi → contrib/auth/models/__init__.py} +0 -0
- /amsdal/{migration/executors → contrib/auth/models}/__init__.pyi +0 -0
- {amsdal-0.3.5.dist-info → amsdal-0.4.0.dist-info}/LICENSE.txt +0 -0
- {amsdal-0.3.5.dist-info → amsdal-0.4.0.dist-info}/licenses/LICENSE.txt +0 -0
- {amsdal-0.3.5.dist-info → amsdal-0.4.0.dist-info}/top_level.txt +0 -0
|
@@ -32,9 +32,9 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
|
|
|
32
32
|
in the authentication settings. If the super user does not exist, it creates one
|
|
33
33
|
with the necessary permissions.
|
|
34
34
|
"""
|
|
35
|
+
from amsdal.contrib.auth.models.permission import Permission
|
|
36
|
+
from amsdal.contrib.auth.models.user import User
|
|
35
37
|
from amsdal.contrib.auth.settings import auth_settings
|
|
36
|
-
from models.contrib.permission import Permission # type: ignore[import-not-found]
|
|
37
|
-
from models.contrib.user import User # type: ignore[import-not-found]
|
|
38
38
|
|
|
39
39
|
logger.info('Ensure super user exists')
|
|
40
40
|
|
|
@@ -65,7 +65,7 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
|
|
|
65
65
|
|
|
66
66
|
instance = User(
|
|
67
67
|
email=auth_settings.ADMIN_USER_EMAIL,
|
|
68
|
-
password=auth_settings.ADMIN_USER_PASSWORD,
|
|
68
|
+
password=auth_settings.ADMIN_USER_PASSWORD.encode(),
|
|
69
69
|
permissions=[access_all_permission],
|
|
70
70
|
)
|
|
71
71
|
instance.save(force_insert=True)
|
|
@@ -80,9 +80,9 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
|
|
|
80
80
|
in the authentication settings. If the super user does not exist, it creates one
|
|
81
81
|
with the necessary permissions.
|
|
82
82
|
"""
|
|
83
|
+
from amsdal.contrib.auth.models.permission import Permission # type: ignore[import-not-found]
|
|
84
|
+
from amsdal.contrib.auth.models.user import User # type: ignore[import-not-found]
|
|
83
85
|
from amsdal.contrib.auth.settings import auth_settings
|
|
84
|
-
from models.contrib.permission import Permission # type: ignore[import-not-found]
|
|
85
|
-
from models.contrib.user import User # type: ignore[import-not-found]
|
|
86
86
|
|
|
87
87
|
logger.info('Ensure super user exists')
|
|
88
88
|
|
|
@@ -113,7 +113,7 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
|
|
|
113
113
|
|
|
114
114
|
instance = User(
|
|
115
115
|
email=auth_settings.ADMIN_USER_EMAIL,
|
|
116
|
-
password=auth_settings.ADMIN_USER_PASSWORD,
|
|
116
|
+
password=auth_settings.ADMIN_USER_PASSWORD.encode(),
|
|
117
117
|
permissions=[access_all_permission],
|
|
118
118
|
)
|
|
119
119
|
await instance.asave(force_insert=True)
|
|
@@ -141,8 +141,8 @@ class AuthenticateUserConsumer(LifecycleConsumer):
|
|
|
141
141
|
auth_header (str): The JWT token from the authorization header.
|
|
142
142
|
authentication_info (Any): The authentication information object to update with the user.
|
|
143
143
|
"""
|
|
144
|
+
from amsdal.contrib.auth.models.user import User # type: ignore[import-not-found]
|
|
144
145
|
from amsdal.contrib.auth.settings import auth_settings
|
|
145
|
-
from models.contrib.user import User # type: ignore[import-not-found]
|
|
146
146
|
|
|
147
147
|
authentication_info.user = None
|
|
148
148
|
email: str | None
|
|
@@ -181,8 +181,8 @@ class AuthenticateUserConsumer(LifecycleConsumer):
|
|
|
181
181
|
auth_header (str): The JWT token from the authorization header.
|
|
182
182
|
authentication_info (Any): The authentication information object to update with the user.
|
|
183
183
|
"""
|
|
184
|
+
from amsdal.contrib.auth.models.user import User # type: ignore[import-not-found]
|
|
184
185
|
from amsdal.contrib.auth.settings import auth_settings
|
|
185
|
-
from models.contrib.user import User # type: ignore[import-not-found]
|
|
186
186
|
|
|
187
187
|
authentication_info.user = None
|
|
188
188
|
email: str | None
|
|
@@ -219,8 +219,8 @@ class CheckPermissionConsumer(LifecycleConsumer):
|
|
|
219
219
|
"""
|
|
220
220
|
|
|
221
221
|
def _prepopulate_default_permissions(self, object_class: type[Model], permissions_info: Any) -> None:
|
|
222
|
+
from amsdal.contrib.auth.models.permission import Permission
|
|
222
223
|
from amsdal.contrib.auth.settings import auth_settings
|
|
223
|
-
from models.contrib.permission import Permission # type: ignore[import-not-found]
|
|
224
224
|
|
|
225
225
|
permissions_info.has_read_permission = not auth_settings.REQUIRE_DEFAULT_AUTHORIZATION
|
|
226
226
|
permissions_info.has_create_permission = (
|
|
@@ -245,8 +245,8 @@ class CheckPermissionConsumer(LifecycleConsumer):
|
|
|
245
245
|
permissions_info.has_delete_permission = False
|
|
246
246
|
|
|
247
247
|
async def _async_prepopulate_default_permissions(self, object_class: type[Model], permissions_info: Any) -> None:
|
|
248
|
+
from amsdal.contrib.auth.models.permission import Permission # type: ignore[import-not-found]
|
|
248
249
|
from amsdal.contrib.auth.settings import auth_settings
|
|
249
|
-
from models.contrib.permission import Permission # type: ignore[import-not-found]
|
|
250
250
|
|
|
251
251
|
permissions_info.has_read_permission = not auth_settings.REQUIRE_DEFAULT_AUTHORIZATION
|
|
252
252
|
permissions_info.has_create_permission = (
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from amsdal.migration import migrations
|
|
1
|
+
from amsdal_models.migration import migrations
|
|
2
|
+
from amsdal_utils.models.enums import ModuleType
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
class Migration(migrations.Migration):
|
|
7
6
|
operations: list[migrations.Operation] = [
|
|
8
7
|
migrations.CreateClass(
|
|
9
|
-
|
|
8
|
+
module_type=ModuleType.CONTRIB,
|
|
10
9
|
class_name='Permission',
|
|
11
10
|
new_schema={
|
|
12
11
|
'title': 'Permission',
|
|
@@ -15,11 +14,13 @@ class Migration(migrations.Migration):
|
|
|
15
14
|
'model': {'type': 'string', 'title': 'Model'},
|
|
16
15
|
'action': {'type': 'string', 'title': 'Action'},
|
|
17
16
|
},
|
|
17
|
+
"primary_key": {"partition_key": ["partition_key"]},
|
|
18
|
+
"table_name": "Permission",
|
|
18
19
|
'custom_code': "@property # type: ignore[misc]\ndef display_name(self) -> str: # type: ignore[no-untyped-def]\n return f'{self.model}:{self.action}'",
|
|
19
20
|
},
|
|
20
21
|
),
|
|
21
22
|
migrations.CreateClass(
|
|
22
|
-
|
|
23
|
+
module_type=ModuleType.CONTRIB,
|
|
23
24
|
class_name='User',
|
|
24
25
|
new_schema={
|
|
25
26
|
'title': 'User',
|
|
@@ -29,11 +30,42 @@ class Migration(migrations.Migration):
|
|
|
29
30
|
'password': {'type': 'binary', 'title': 'Password (hash)'},
|
|
30
31
|
'permissions': {'type': 'array', 'items': {'type': 'Permission'}, 'title': 'Permissions'},
|
|
31
32
|
},
|
|
33
|
+
"primary_key": {"partition_key": ["partition_key"]},
|
|
34
|
+
"table_name": "User",
|
|
32
35
|
'custom_code': "from typing import Any\n\n\ndef pre_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None: # type: ignore[no-untyped-def] # noqa: ARG001\n import bcrypt\n\n from amsdal.contrib.auth.errors import UserCreationError\n\n email = kwargs.get('email', None)\n password = kwargs.get('password', None)\n\n if email is None or email == '':\n msg = \"Email can't be empty\"\n raise UserCreationError(msg)\n\n if password is None or password == '':\n msg = \"Password can't be empty\"\n raise UserCreationError(msg)\n\n kwargs['email'] = email.lower()\n\n if is_new_object and '_metadata' not in kwargs:\n hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())\n kwargs['password'] = hashed_password\n kwargs['_object_id'] = email.lower()\n\ndef pre_create(self) -> None: # type: ignore[no-untyped-def] # noqa: ARG001\n pass\n\n@property # type: ignore[misc]\ndef display_name(self) -> str: # type: ignore[no-untyped-def]\n return self.email",
|
|
33
36
|
},
|
|
34
37
|
),
|
|
35
38
|
migrations.CreateClass(
|
|
36
|
-
|
|
39
|
+
module_type=ModuleType.CONTRIB,
|
|
40
|
+
class_name='UserPermission',
|
|
41
|
+
new_schema={
|
|
42
|
+
'title': 'UserPermission',
|
|
43
|
+
'required': ['user', 'permission'],
|
|
44
|
+
'properties': {
|
|
45
|
+
'user': {'type': 'User', 'title': 'User'},
|
|
46
|
+
'permission': {'type': 'Permission', 'title': 'Permission'},
|
|
47
|
+
},
|
|
48
|
+
"primary_key": {
|
|
49
|
+
"user": ["user_partition_key"],
|
|
50
|
+
"permission": ["permission_partition_key"],
|
|
51
|
+
},
|
|
52
|
+
"foreign_keys": {
|
|
53
|
+
"user": [
|
|
54
|
+
{"user_partition_key": "string"},
|
|
55
|
+
"User",
|
|
56
|
+
["partition_key"],
|
|
57
|
+
],
|
|
58
|
+
"permission": [
|
|
59
|
+
{"permission_partition_key": "string"},
|
|
60
|
+
"Permission",
|
|
61
|
+
["partition_key"],
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
"table_name": "UserPermission",
|
|
65
|
+
},
|
|
66
|
+
),
|
|
67
|
+
migrations.CreateClass(
|
|
68
|
+
module_type=ModuleType.CONTRIB,
|
|
37
69
|
class_name='LoginSession',
|
|
38
70
|
new_schema={
|
|
39
71
|
'title': 'LoginSession',
|
|
@@ -43,7 +75,9 @@ class Migration(migrations.Migration):
|
|
|
43
75
|
'password': {'type': 'string', 'title': 'Password (hash)'},
|
|
44
76
|
'token': {'type': 'string', 'title': 'Token', 'mark_as_read_only': True},
|
|
45
77
|
},
|
|
46
|
-
|
|
78
|
+
"primary_key": {"partition_key": ["partition_key"]},
|
|
79
|
+
"table_name": "LoginSession",
|
|
80
|
+
'custom_code': "from datetime import datetime\nfrom datetime import timedelta\nfrom datetime import timezone\nfrom typing import Any\n\nimport bcrypt\nimport jwt\nfrom amsdal_utils.models.enums import Versions\n\n\ndef pre_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None: # type: ignore[no-untyped-def] # noqa: ARG001\n if not is_new_object or '_metadata' in kwargs:\n return\n\n from amsdal.contrib.auth.errors import AuthenticationError\n from amsdal.contrib.auth.settings import auth_settings\n\n email = kwargs.get('email', None)\n password = kwargs.get('password', None)\n\n if not email:\n msg = \"Email can't be empty\"\n raise AuthenticationError(msg)\n\n if not password:\n msg = \"Password can't be empty\"\n raise AuthenticationError(msg)\n\n lowercased_email = email.lower()\n\n from amsdal.contrib.auth.models.user import User # type: ignore[import-not-found]\n\n user = User.objects.filter(email=lowercased_email, _address__object_version=Versions.LATEST).get_or_none().execute()\n\n if not user:\n msg = 'Invalid email / password'\n raise AuthenticationError(msg)\n\n if not bcrypt.checkpw(password.encode('utf-8') if isinstance(password, str) else password, user.password):\n msg = 'Invalid email / password'\n raise AuthenticationError(msg)\n\n kwargs['password'] = 'validated'\n expiration_time = datetime.now(tz=timezone.utc) + timedelta(seconds=1200)\n token = jwt.encode(\n {'email': lowercased_email, 'exp': expiration_time},\n key=auth_settings.AUTH_JWT_KEY, # type: ignore[arg-type]\n algorithm='HS256',\n )\n\n kwargs['token'] = token\n\n@property # type: ignore[misc]\ndef display_name(self) -> str: # type: ignore[no-untyped-def]\n return self.email",
|
|
47
81
|
},
|
|
48
82
|
),
|
|
49
83
|
]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from datetime import UTC
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from typing import Any
|
|
5
|
+
from typing import ClassVar
|
|
6
|
+
|
|
7
|
+
import jwt
|
|
8
|
+
from amsdal_models.classes.model import Model
|
|
9
|
+
from amsdal_utils.models.enums import ModuleType
|
|
10
|
+
from pydantic.fields import Field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LoginSession(Model):
|
|
14
|
+
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
15
|
+
email: str = Field(title='Email')
|
|
16
|
+
password: str = Field(title='Password (hash)')
|
|
17
|
+
token: str | None = Field(None, title='Token')
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def display_name(self) -> str:
|
|
21
|
+
"""
|
|
22
|
+
Returns the display name of the user.
|
|
23
|
+
|
|
24
|
+
This method returns the email of the user as their display name.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
str: The email of the user.
|
|
28
|
+
"""
|
|
29
|
+
return self.email
|
|
30
|
+
|
|
31
|
+
def pre_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Pre-initializes a user object by validating email and password, and generating a JWT token.
|
|
34
|
+
|
|
35
|
+
This method checks if the object is new and validates the provided email and password.
|
|
36
|
+
If the email and password are valid, it generates a JWT token and adds it to the kwargs.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
is_new_object (bool): Indicates if the object is new.
|
|
40
|
+
kwargs (dict[str, Any]): The keyword arguments containing user details.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
AuthenticationError: If the email or password is invalid.
|
|
44
|
+
"""
|
|
45
|
+
if not is_new_object or '_metadata' in kwargs:
|
|
46
|
+
return
|
|
47
|
+
from amsdal.contrib.auth.errors import AuthenticationError
|
|
48
|
+
from amsdal.contrib.auth.settings import auth_settings
|
|
49
|
+
|
|
50
|
+
email = kwargs.get('email', None)
|
|
51
|
+
password = kwargs.get('password', None)
|
|
52
|
+
if not email:
|
|
53
|
+
msg = "Email can't be empty"
|
|
54
|
+
raise AuthenticationError(msg)
|
|
55
|
+
if not password:
|
|
56
|
+
msg = "Password can't be empty"
|
|
57
|
+
raise AuthenticationError(msg)
|
|
58
|
+
lowercased_email = email.lower()
|
|
59
|
+
kwargs['password'] = 'validated'
|
|
60
|
+
expiration_time = datetime.now(tz=UTC) + timedelta(seconds=auth_settings.AUTH_TOKEN_EXPIRATION)
|
|
61
|
+
token = jwt.encode(
|
|
62
|
+
{'email': lowercased_email, 'exp': expiration_time},
|
|
63
|
+
key=auth_settings.AUTH_JWT_KEY, # type: ignore[arg-type]
|
|
64
|
+
algorithm='HS256',
|
|
65
|
+
)
|
|
66
|
+
kwargs['token'] = token
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from amsdal_models.classes.model import Model
|
|
2
|
+
from amsdal_utils.models.enums import ModuleType
|
|
3
|
+
from typing import Any, ClassVar
|
|
4
|
+
|
|
5
|
+
class LoginSession(Model):
|
|
6
|
+
__module_type__: ClassVar[ModuleType] = ...
|
|
7
|
+
email: str = ...
|
|
8
|
+
password: str = ...
|
|
9
|
+
token: str | None = ...
|
|
10
|
+
@property
|
|
11
|
+
def display_name(self) -> str:
|
|
12
|
+
"""
|
|
13
|
+
Returns the display name of the user.
|
|
14
|
+
|
|
15
|
+
This method returns the email of the user as their display name.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
str: The email of the user.
|
|
19
|
+
"""
|
|
20
|
+
def pre_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Pre-initializes a user object by validating email and password, and generating a JWT token.
|
|
23
|
+
|
|
24
|
+
This method checks if the object is new and validates the provided email and password.
|
|
25
|
+
If the email and password are valid, it generates a JWT token and adds it to the kwargs.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
is_new_object (bool): Indicates if the object is new.
|
|
29
|
+
kwargs (dict[str, Any]): The keyword arguments containing user details.
|
|
30
|
+
|
|
31
|
+
Raises:
|
|
32
|
+
AuthenticationError: If the email or password is invalid.
|
|
33
|
+
"""
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import ClassVar
|
|
2
|
+
|
|
3
|
+
from amsdal_models.classes.model import Model
|
|
4
|
+
from amsdal_utils.models.enums import ModuleType
|
|
5
|
+
from pydantic.fields import Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Permission(Model):
|
|
9
|
+
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
10
|
+
model: str = Field(title='Model')
|
|
11
|
+
action: str = Field(title='Action')
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def display_name(self) -> str:
|
|
15
|
+
"""
|
|
16
|
+
Returns the display name of the user.
|
|
17
|
+
|
|
18
|
+
This method returns a formatted string combining the model and action of the user.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
str: The formatted display name in the format 'model:action'.
|
|
22
|
+
"""
|
|
23
|
+
return f'{self.model}:{self.action}'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from amsdal_models.classes.model import Model
|
|
2
|
+
from amsdal_utils.models.enums import ModuleType
|
|
3
|
+
from typing import ClassVar
|
|
4
|
+
|
|
5
|
+
class Permission(Model):
|
|
6
|
+
__module_type__: ClassVar[ModuleType] = ...
|
|
7
|
+
model: str = ...
|
|
8
|
+
action: str = ...
|
|
9
|
+
@property
|
|
10
|
+
def display_name(self) -> str:
|
|
11
|
+
"""
|
|
12
|
+
Returns the display name of the user.
|
|
13
|
+
|
|
14
|
+
This method returns a formatted string combining the model and action of the user.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
str: The formatted display name in the format 'model:action'.
|
|
18
|
+
"""
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
from amsdal_models.classes.model import Model
|
|
5
|
+
from amsdal_utils.models.enums import ModuleType
|
|
6
|
+
from pydantic.fields import Field
|
|
7
|
+
|
|
8
|
+
from amsdal.contrib.auth.models.permission import * # noqa: F403
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class User(Model):
|
|
12
|
+
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
13
|
+
email: str = Field(title='Email')
|
|
14
|
+
password: bytes = Field(title='Password (hash)')
|
|
15
|
+
permissions: list['Permission'] | None = Field(None, title='Permissions') # noqa: F405
|
|
16
|
+
|
|
17
|
+
def __repr__(self) -> str:
|
|
18
|
+
return str(self)
|
|
19
|
+
|
|
20
|
+
def __str__(self) -> str:
|
|
21
|
+
return f'User(email={self.email})'
|
|
22
|
+
|
|
23
|
+
async def apre_update(self) -> None:
|
|
24
|
+
import bcrypt
|
|
25
|
+
|
|
26
|
+
original_object = await self.arefetch_from_db()
|
|
27
|
+
password = self.password
|
|
28
|
+
if original_object.password and password is not None:
|
|
29
|
+
if isinstance(password, str):
|
|
30
|
+
password = password.encode('utf-8')
|
|
31
|
+
try:
|
|
32
|
+
if not bcrypt.checkpw(password, original_object.password):
|
|
33
|
+
self.password = password
|
|
34
|
+
except ValueError:
|
|
35
|
+
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
|
|
36
|
+
self.password = hashed_password
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def display_name(self) -> str:
|
|
40
|
+
"""
|
|
41
|
+
Returns the display name of the user.
|
|
42
|
+
|
|
43
|
+
This method returns the email of the user as their display name.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: The email of the user.
|
|
47
|
+
"""
|
|
48
|
+
return self.email
|
|
49
|
+
|
|
50
|
+
def post_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Post-initializes a user object by validating email and password, and hashing the password.
|
|
53
|
+
|
|
54
|
+
This method checks if the email and password are provided and valid. If the object is new,
|
|
55
|
+
it hashes the password and sets the object ID to the lowercased email.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
is_new_object (bool): Indicates if the object is new.
|
|
59
|
+
kwargs (dict[str, Any]): The keyword arguments containing user details.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
UserCreationError: If the email or password is invalid.
|
|
63
|
+
"""
|
|
64
|
+
import bcrypt
|
|
65
|
+
|
|
66
|
+
from amsdal.contrib.auth.errors import UserCreationError
|
|
67
|
+
|
|
68
|
+
email = kwargs.get('email', None)
|
|
69
|
+
password = kwargs.get('password', None)
|
|
70
|
+
if email is None or email == '':
|
|
71
|
+
msg = "Email can't be empty"
|
|
72
|
+
raise UserCreationError(msg)
|
|
73
|
+
if password is None or password == '':
|
|
74
|
+
msg = "Password can't be empty"
|
|
75
|
+
raise UserCreationError(msg)
|
|
76
|
+
kwargs['email'] = email.lower()
|
|
77
|
+
if is_new_object and '_metadata' not in kwargs:
|
|
78
|
+
if isinstance(password, str):
|
|
79
|
+
password = password.encode('utf-8')
|
|
80
|
+
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
|
|
81
|
+
self.password = hashed_password
|
|
82
|
+
self._object_id = email.lower()
|
|
83
|
+
|
|
84
|
+
def pre_create(self) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Pre-creates a user object.
|
|
87
|
+
|
|
88
|
+
This method is a placeholder for any pre-creation logic that needs to be executed
|
|
89
|
+
before a user object is created.
|
|
90
|
+
"""
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
def pre_update(self) -> None:
|
|
94
|
+
import bcrypt
|
|
95
|
+
|
|
96
|
+
original_object = self.refetch_from_db()
|
|
97
|
+
password = self.password
|
|
98
|
+
if original_object.password and password is not None:
|
|
99
|
+
if isinstance(password, str):
|
|
100
|
+
password = password.encode('utf-8')
|
|
101
|
+
try:
|
|
102
|
+
if not bcrypt.checkpw(password, original_object.password):
|
|
103
|
+
self.password = password
|
|
104
|
+
except ValueError:
|
|
105
|
+
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())
|
|
106
|
+
self.password = hashed_password
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from amsdal.contrib.auth.models.permission import *
|
|
2
|
+
from amsdal_models.classes.model import Model
|
|
3
|
+
from amsdal_utils.models.enums import ModuleType
|
|
4
|
+
from typing import Any, ClassVar
|
|
5
|
+
|
|
6
|
+
class User(Model):
|
|
7
|
+
__module_type__: ClassVar[ModuleType] = ...
|
|
8
|
+
email: str = ...
|
|
9
|
+
password: bytes = ...
|
|
10
|
+
permissions: list['Permission'] | None = ...
|
|
11
|
+
def __repr__(self) -> str: ...
|
|
12
|
+
def __str__(self) -> str: ...
|
|
13
|
+
async def apre_update(self) -> None: ...
|
|
14
|
+
@property
|
|
15
|
+
def display_name(self) -> str:
|
|
16
|
+
"""
|
|
17
|
+
Returns the display name of the user.
|
|
18
|
+
|
|
19
|
+
This method returns the email of the user as their display name.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
str: The email of the user.
|
|
23
|
+
"""
|
|
24
|
+
_object_id = ...
|
|
25
|
+
def post_init(self, *, is_new_object: bool, kwargs: dict[str, Any]) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Post-initializes a user object by validating email and password, and hashing the password.
|
|
28
|
+
|
|
29
|
+
This method checks if the email and password are provided and valid. If the object is new,
|
|
30
|
+
it hashes the password and sets the object ID to the lowercased email.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
is_new_object (bool): Indicates if the object is new.
|
|
34
|
+
kwargs (dict[str, Any]): The keyword arguments containing user details.
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
UserCreationError: If the email or password is invalid.
|
|
38
|
+
"""
|
|
39
|
+
def pre_create(self) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Pre-creates a user object.
|
|
42
|
+
|
|
43
|
+
This method is a placeholder for any pre-creation logic that needs to be executed
|
|
44
|
+
before a user object is created.
|
|
45
|
+
"""
|
|
46
|
+
def pre_update(self) -> None: ...
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
1
2
|
from datetime import date
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
from enum import Enum
|
|
@@ -9,15 +10,20 @@ from typing import Any
|
|
|
9
10
|
from typing import ClassVar
|
|
10
11
|
from typing import ForwardRef
|
|
11
12
|
from typing import Union
|
|
13
|
+
from typing import get_args
|
|
14
|
+
from typing import get_origin
|
|
12
15
|
|
|
13
|
-
from amsdal_models.classes.
|
|
16
|
+
from amsdal_models.classes.class_manager import ClassManager
|
|
14
17
|
from amsdal_models.classes.model import LegacyModel
|
|
15
18
|
from amsdal_models.classes.model import Model
|
|
19
|
+
from amsdal_models.classes.model import TypeModel
|
|
20
|
+
from amsdal_models.classes.relationships.constants import MANY_TO_MANY_FIELDS
|
|
21
|
+
from amsdal_models.schemas.object_schema import model_to_object_schema
|
|
16
22
|
from amsdal_utils.models.data_models.reference import Reference
|
|
17
23
|
from pydantic import BaseModel
|
|
18
24
|
from pydantic_core import PydanticUndefined
|
|
19
25
|
|
|
20
|
-
from amsdal.schemas.manager import SchemaManager
|
|
26
|
+
# from amsdal.schemas.manager import SchemaManager
|
|
21
27
|
|
|
22
28
|
default_types_map = {
|
|
23
29
|
int: 'number',
|
|
@@ -32,11 +38,19 @@ default_types_map = {
|
|
|
32
38
|
|
|
33
39
|
def _process_union(value: UnionType, *, is_transaction: bool = False) -> dict[str, Any]:
|
|
34
40
|
arg_type = {'required': True}
|
|
35
|
-
|
|
41
|
+
|
|
42
|
+
for arg in get_args(value):
|
|
36
43
|
if arg is type(None):
|
|
37
44
|
arg_type['required'] = False
|
|
38
45
|
continue
|
|
39
46
|
|
|
47
|
+
if not is_transaction:
|
|
48
|
+
with suppress(TypeError):
|
|
49
|
+
if issubclass(arg, Model):
|
|
50
|
+
arg_type['type'] = 'object_latest' # type: ignore[assignment]
|
|
51
|
+
arg_type['entityType'] = arg.__name__
|
|
52
|
+
continue
|
|
53
|
+
|
|
40
54
|
control = convert_to_frontend_config(arg, is_transaction=is_transaction)
|
|
41
55
|
if control:
|
|
42
56
|
arg_type.update(control)
|
|
@@ -59,9 +73,10 @@ def convert_to_frontend_config(value: Any, *, is_transaction: bool = False) -> d
|
|
|
59
73
|
Returns:
|
|
60
74
|
dict[str, Any]: A dictionary representing the frontend configuration for the given value.
|
|
61
75
|
"""
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
schema = None
|
|
77
|
+
origin_class = get_origin(value)
|
|
64
78
|
|
|
79
|
+
if origin_class:
|
|
65
80
|
if origin_class in [ClassVar]:
|
|
66
81
|
return {}
|
|
67
82
|
|
|
@@ -100,7 +115,7 @@ def convert_to_frontend_config(value: Any, *, is_transaction: bool = False) -> d
|
|
|
100
115
|
|
|
101
116
|
if isinstance(value, ForwardRef):
|
|
102
117
|
class_name = value.__forward_arg__
|
|
103
|
-
_class = ClassManager().import_class(class_name
|
|
118
|
+
_class = ClassManager().import_class(class_name)
|
|
104
119
|
|
|
105
120
|
if issubclass(_class, Model):
|
|
106
121
|
return {
|
|
@@ -163,7 +178,8 @@ def convert_to_frontend_config(value: Any, *, is_transaction: bool = False) -> d
|
|
|
163
178
|
control['value'] = _param.default
|
|
164
179
|
control['required'] = False
|
|
165
180
|
|
|
166
|
-
|
|
181
|
+
if not control['name'].startswith('_'):
|
|
182
|
+
function_controls.append(control)
|
|
167
183
|
|
|
168
184
|
return {
|
|
169
185
|
'type': 'group',
|
|
@@ -194,23 +210,26 @@ def convert_to_frontend_config(value: Any, *, is_transaction: bool = False) -> d
|
|
|
194
210
|
model_controls = []
|
|
195
211
|
|
|
196
212
|
try:
|
|
197
|
-
|
|
213
|
+
if issubclass(value, Model | TypeModel):
|
|
214
|
+
schema = model_to_object_schema(value)
|
|
198
215
|
except FileNotFoundError:
|
|
199
216
|
schema = None
|
|
200
217
|
|
|
201
|
-
|
|
202
|
-
|
|
218
|
+
if value.__name__ == 'File':
|
|
219
|
+
return {
|
|
220
|
+
'type': 'file',
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
for field_name, field in value.model_fields.items():
|
|
224
|
+
control = convert_to_frontend_config(field.annotation, is_transaction=is_transaction)
|
|
203
225
|
|
|
204
226
|
if not control:
|
|
205
227
|
continue
|
|
206
228
|
|
|
207
229
|
control.setdefault('required', True)
|
|
208
230
|
|
|
209
|
-
if
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if _field.default is not PydanticUndefined:
|
|
213
|
-
control['value'] = _field.default
|
|
231
|
+
if field.default is not PydanticUndefined:
|
|
232
|
+
control['value'] = field.default
|
|
214
233
|
|
|
215
234
|
control['name'] = field_name
|
|
216
235
|
control['label'] = field_name
|
|
@@ -232,6 +251,19 @@ def convert_to_frontend_config(value: Any, *, is_transaction: bool = False) -> d
|
|
|
232
251
|
if schema_property.title:
|
|
233
252
|
control['label'] = schema_property.title
|
|
234
253
|
|
|
254
|
+
if not control['name'].startswith('_'):
|
|
255
|
+
model_controls.append(control)
|
|
256
|
+
|
|
257
|
+
for m2m, (m2m_ref, _, _, field_info) in (getattr(value, MANY_TO_MANY_FIELDS, None) or {}).items():
|
|
258
|
+
pass
|
|
259
|
+
control = convert_to_frontend_config(list[Reference | m2m_ref], is_transaction=is_transaction) # type: ignore[valid-type]
|
|
260
|
+
|
|
261
|
+
if getattr(field_info, 'default', PydanticUndefined) is not PydanticUndefined:
|
|
262
|
+
control['value'] = field_info.default
|
|
263
|
+
|
|
264
|
+
control['name'] = m2m
|
|
265
|
+
control['label'] = m2m
|
|
266
|
+
control['required'] = False
|
|
235
267
|
model_controls.append(control)
|
|
236
268
|
|
|
237
269
|
return {
|