amsdal 0.3.6__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.

Files changed (208) hide show
  1. amsdal/__about__.py +1 -1
  2. amsdal/__migrations__/0000_initial.py +34 -25
  3. amsdal/__migrations__/0001_datetime_type.py +4 -4
  4. amsdal/__migrations__/0002_fixture_order.py +7 -3
  5. amsdal/__migrations__/0003_schema_type_in_class_meta.py +3 -15
  6. amsdal/cloud/__init__.cpython-312-darwin.so +0 -0
  7. amsdal/cloud/client.cpython-312-darwin.so +0 -0
  8. amsdal/cloud/constants.cpython-312-darwin.so +0 -0
  9. amsdal/cloud/enums.cpython-312-darwin.so +0 -0
  10. amsdal/cloud/models/__init__.cpython-312-darwin.so +0 -0
  11. amsdal/cloud/models/base.cpython-312-darwin.so +0 -0
  12. amsdal/cloud/services/__init__.cpython-312-darwin.so +0 -0
  13. amsdal/cloud/services/actions/__init__.cpython-312-darwin.so +0 -0
  14. amsdal/cloud/services/actions/add_allowlist_ip.cpython-312-darwin.so +0 -0
  15. amsdal/cloud/services/actions/add_basic_auth.cpython-312-darwin.so +0 -0
  16. amsdal/cloud/services/actions/add_dependency.cpython-312-darwin.so +0 -0
  17. amsdal/cloud/services/actions/add_secret.cpython-312-darwin.so +0 -0
  18. amsdal/cloud/services/actions/base.cpython-312-darwin.so +0 -0
  19. amsdal/cloud/services/actions/create_deploy.cpython-312-darwin.so +0 -0
  20. amsdal/cloud/services/actions/create_env.cpython-312-darwin.so +0 -0
  21. amsdal/cloud/services/actions/create_session.cpython-312-darwin.so +0 -0
  22. amsdal/cloud/services/actions/delete_allowlist_ip.cpython-312-darwin.so +0 -0
  23. amsdal/cloud/services/actions/delete_basic_auth.cpython-312-darwin.so +0 -0
  24. amsdal/cloud/services/actions/delete_dependency.cpython-312-darwin.so +0 -0
  25. amsdal/cloud/services/actions/delete_env.cpython-312-darwin.so +0 -0
  26. amsdal/cloud/services/actions/delete_secret.cpython-312-darwin.so +0 -0
  27. amsdal/cloud/services/actions/destroy_deploy.cpython-312-darwin.so +0 -0
  28. amsdal/cloud/services/actions/expose_db.cpython-312-darwin.so +0 -0
  29. amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-312-darwin.so +0 -0
  30. amsdal/cloud/services/actions/get_monitoring_info.cpython-312-darwin.so +0 -0
  31. amsdal/cloud/services/actions/list_dependencies.cpython-312-darwin.so +0 -0
  32. amsdal/cloud/services/actions/list_deploys.cpython-312-darwin.so +0 -0
  33. amsdal/cloud/services/actions/list_envs.cpython-312-darwin.so +0 -0
  34. amsdal/cloud/services/actions/list_secrets.cpython-312-darwin.so +0 -0
  35. amsdal/cloud/services/actions/manager.cpython-312-darwin.so +0 -0
  36. amsdal/cloud/services/actions/signup_action.cpython-312-darwin.so +0 -0
  37. amsdal/cloud/services/actions/update_deploy.cpython-312-darwin.so +0 -0
  38. amsdal/cloud/services/auth/__init__.cpython-312-darwin.so +0 -0
  39. amsdal/cloud/services/auth/base.cpython-312-darwin.so +0 -0
  40. amsdal/cloud/services/auth/credentials.cpython-312-darwin.so +0 -0
  41. amsdal/cloud/services/auth/credentials.pyi +0 -1
  42. amsdal/cloud/services/auth/manager.cpython-312-darwin.so +0 -0
  43. amsdal/cloud/services/auth/signup_service.cpython-312-darwin.so +0 -0
  44. amsdal/cloud/services/auth/token.cpython-312-darwin.so +0 -0
  45. amsdal/cloud/services/auth/token.pyi +0 -1
  46. amsdal/configs/main.py +23 -19
  47. amsdal/configs/main.pyi +12 -15
  48. amsdal/contrib/__init__.cpython-312-darwin.so +0 -0
  49. amsdal/contrib/auth/lifecycle/consumer.py +10 -10
  50. amsdal/contrib/auth/migrations/0000_initial.py +41 -7
  51. amsdal/contrib/auth/models/login_session.py +66 -0
  52. amsdal/contrib/auth/models/login_session.pyi +33 -0
  53. amsdal/contrib/auth/models/permission.py +23 -0
  54. amsdal/contrib/auth/models/permission.pyi +18 -0
  55. amsdal/contrib/auth/models/user.py +106 -0
  56. amsdal/contrib/auth/models/user.pyi +46 -0
  57. amsdal/contrib/frontend_configs/conversion/convert.py +47 -15
  58. amsdal/contrib/frontend_configs/conversion/convert.pyi +0 -1
  59. amsdal/contrib/frontend_configs/lifecycle/consumer.py +32 -13
  60. amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +1 -1
  61. amsdal/contrib/frontend_configs/migrations/0000_initial.py +15 -14
  62. amsdal/contrib/frontend_configs/models/__init__.py +0 -0
  63. amsdal/contrib/frontend_configs/models/__init__.pyi +0 -0
  64. amsdal/contrib/frontend_configs/models/frontend_activator_config.py +22 -0
  65. amsdal/contrib/frontend_configs/models/frontend_activator_config.pyi +12 -0
  66. amsdal/contrib/frontend_configs/models/frontend_config_async_validator.py +11 -0
  67. amsdal/contrib/frontend_configs/models/frontend_config_async_validator.pyi +7 -0
  68. amsdal/contrib/frontend_configs/models/frontend_config_control_action.py +54 -0
  69. amsdal/contrib/frontend_configs/models/frontend_config_control_action.pyi +32 -0
  70. amsdal/contrib/frontend_configs/models/frontend_config_group_validator.py +21 -0
  71. amsdal/contrib/frontend_configs/models/frontend_config_group_validator.pyi +11 -0
  72. amsdal/contrib/frontend_configs/models/frontend_config_option.py +12 -0
  73. amsdal/contrib/frontend_configs/models/frontend_config_option.pyi +8 -0
  74. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.py +17 -0
  75. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.pyi +8 -0
  76. amsdal/contrib/frontend_configs/models/frontend_config_slider_option.py +13 -0
  77. amsdal/contrib/frontend_configs/models/frontend_config_slider_option.pyi +9 -0
  78. amsdal/contrib/frontend_configs/models/frontend_config_text_mask.py +14 -0
  79. amsdal/contrib/frontend_configs/models/frontend_config_text_mask.pyi +10 -0
  80. amsdal/contrib/frontend_configs/models/frontend_config_validator.py +28 -0
  81. amsdal/contrib/frontend_configs/models/frontend_config_validator.pyi +15 -0
  82. amsdal/contrib/frontend_configs/models/frontend_control_config.py +87 -0
  83. amsdal/contrib/frontend_configs/models/frontend_control_config.pyi +35 -0
  84. amsdal/contrib/frontend_configs/models/frontend_model_config.py +14 -0
  85. amsdal/contrib/frontend_configs/models/frontend_model_config.pyi +9 -0
  86. amsdal/errors.py +0 -3
  87. amsdal/errors.pyi +0 -1
  88. amsdal/fixtures/__init__.cpython-312-darwin.so +0 -0
  89. amsdal/fixtures/manager.cpython-312-darwin.so +0 -0
  90. amsdal/fixtures/manager.pyi +72 -123
  91. amsdal/fixtures/utils.cpython-312-darwin.so +0 -0
  92. amsdal/fixtures/utils.pyi +9 -0
  93. amsdal/manager.cpython-312-darwin.so +0 -0
  94. amsdal/manager.pyi +4 -96
  95. amsdal/mixins/__init__.cpython-312-darwin.so +0 -0
  96. amsdal/mixins/class_versions_mixin.cpython-312-darwin.so +0 -0
  97. amsdal/models/__init__.py +0 -0
  98. amsdal/models/__init__.pyi +0 -0
  99. amsdal/models/core/__init__.py +0 -0
  100. amsdal/models/core/__init__.pyi +0 -0
  101. amsdal/models/core/class_object.py +37 -0
  102. amsdal/models/core/class_object.pyi +24 -0
  103. amsdal/models/core/class_object_meta.py +26 -0
  104. amsdal/models/core/class_object_meta.pyi +15 -0
  105. amsdal/models/core/class_property.py +19 -0
  106. amsdal/models/core/class_property.pyi +10 -0
  107. amsdal/models/core/class_property_meta.py +15 -0
  108. amsdal/models/core/class_property_meta.pyi +10 -0
  109. amsdal/models/core/file.py +156 -0
  110. amsdal/models/core/file.pyi +104 -0
  111. amsdal/models/core/fixture.py +25 -0
  112. amsdal/models/core/fixture.pyi +14 -0
  113. amsdal/models/core/option.py +11 -0
  114. amsdal/models/core/option.pyi +8 -0
  115. amsdal/models/core/validator.py +12 -0
  116. amsdal/models/core/validator.pyi +8 -0
  117. amsdal/models/types/__init__.py +0 -0
  118. amsdal/models/types/__init__.pyi +0 -0
  119. amsdal/models/types/object.py +26 -0
  120. amsdal/models/types/object.pyi +16 -0
  121. amsdal/schemas/core/file/properties/validate_data.py +1 -1
  122. amsdal/schemas/interfaces.py +25 -0
  123. amsdal/schemas/interfaces.pyi +20 -0
  124. amsdal/schemas/manager.cpython-312-darwin.so +0 -0
  125. amsdal/schemas/manager.py +0 -116
  126. amsdal/schemas/manager.pyi +0 -65
  127. amsdal/schemas/mixins/__init__.py +0 -0
  128. amsdal/schemas/mixins/__init__.pyi +0 -0
  129. amsdal/schemas/mixins/check_dependencies_mixin.py +115 -0
  130. amsdal/schemas/mixins/check_dependencies_mixin.pyi +42 -0
  131. amsdal/schemas/mixins/verify_schemas_mixin.py +96 -0
  132. amsdal/schemas/mixins/verify_schemas_mixin.pyi +33 -0
  133. amsdal/schemas/repository.py +84 -0
  134. amsdal/schemas/repository.pyi +22 -0
  135. amsdal/schemas/utils.py +16 -0
  136. amsdal/schemas/utils.pyi +10 -0
  137. amsdal/services/__init__.cpython-312-darwin.so +0 -0
  138. amsdal/services/transaction_execution.cpython-312-darwin.so +0 -0
  139. amsdal/utils/rollback/__init__.py +99 -54
  140. amsdal/utils/tests/helpers.py +46 -37
  141. {amsdal-0.3.6.dist-info → amsdal-0.4.0.dist-info}/METADATA +8 -8
  142. {amsdal-0.3.6.dist-info → amsdal-0.4.0.dist-info}/RECORD +148 -140
  143. amsdal/contrib/auth/models/login_session/hooks/pre_init.py +0 -68
  144. amsdal/contrib/auth/models/login_session/model.json +0 -23
  145. amsdal/contrib/auth/models/login_session/modifiers/display_name.py +0 -11
  146. amsdal/contrib/auth/models/permission/fixtures/basic_permissions.json +0 -62
  147. amsdal/contrib/auth/models/permission/model.json +0 -18
  148. amsdal/contrib/auth/models/permission/modifiers/display_name.py +0 -11
  149. amsdal/contrib/auth/models/user/hooks/post_init.py +0 -76
  150. amsdal/contrib/auth/models/user/hooks/pre_create.py +0 -8
  151. amsdal/contrib/auth/models/user/model.json +0 -25
  152. amsdal/contrib/auth/models/user/modifiers/display_name.py +0 -19
  153. amsdal/contrib/frontend_configs/models/frontend_activator_config/model.json +0 -11
  154. amsdal/contrib/frontend_configs/models/frontend_config_async_validator/model.json +0 -11
  155. amsdal/contrib/frontend_configs/models/frontend_config_group_validator/model.json +0 -52
  156. amsdal/contrib/frontend_configs/models/frontend_config_option/model.json +0 -15
  157. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base/model.json +0 -6
  158. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base/properties/model_dump.py +0 -13
  159. amsdal/contrib/frontend_configs/models/frontend_config_slider_option/model.json +0 -19
  160. amsdal/contrib/frontend_configs/models/frontend_config_text_mask/model.json +0 -26
  161. amsdal/contrib/frontend_configs/models/frontend_config_validator/model.json +0 -41
  162. amsdal/contrib/frontend_configs/models/frontend_control_config/model.json +0 -250
  163. amsdal/contrib/frontend_configs/models/frontend_model_config/fixtures/permissions.json +0 -24
  164. amsdal/contrib/frontend_configs/models/frontend_model_config/model.json +0 -17
  165. amsdal/contrib/frontend_configs/models/frontent_config_control_action/model.json +0 -54
  166. amsdal/contrib/frontend_configs/models/frontent_config_control_action/properties/action_validate.py +0 -33
  167. amsdal/migration/__init__.cpython-312-darwin.so +0 -0
  168. amsdal/migration/base_migration_schemas.cpython-312-darwin.so +0 -0
  169. amsdal/migration/base_migration_schemas.pyi +0 -119
  170. amsdal/migration/data_classes.cpython-312-darwin.so +0 -0
  171. amsdal/migration/data_classes.pyi +0 -165
  172. amsdal/migration/executors/__init__.cpython-312-darwin.so +0 -0
  173. amsdal/migration/executors/base.cpython-312-darwin.so +0 -0
  174. amsdal/migration/executors/base.pyi +0 -117
  175. amsdal/migration/executors/default_executor.cpython-312-darwin.so +0 -0
  176. amsdal/migration/executors/default_executor.pyi +0 -184
  177. amsdal/migration/executors/state_executor.cpython-312-darwin.so +0 -0
  178. amsdal/migration/executors/state_executor.pyi +0 -151
  179. amsdal/migration/file_migration_executor.cpython-312-darwin.so +0 -0
  180. amsdal/migration/file_migration_executor.pyi +0 -122
  181. amsdal/migration/file_migration_generator.cpython-312-darwin.so +0 -0
  182. amsdal/migration/file_migration_generator.pyi +0 -229
  183. amsdal/migration/file_migration_store.cpython-312-darwin.so +0 -0
  184. amsdal/migration/file_migration_store.pyi +0 -114
  185. amsdal/migration/file_migration_writer.cpython-312-darwin.so +0 -0
  186. amsdal/migration/file_migration_writer.pyi +0 -73
  187. amsdal/migration/migrations.cpython-312-darwin.so +0 -0
  188. amsdal/migration/migrations.pyi +0 -166
  189. amsdal/migration/migrations_loader.cpython-312-darwin.so +0 -0
  190. amsdal/migration/migrations_loader.pyi +0 -32
  191. amsdal/migration/schemas_loaders.cpython-312-darwin.so +0 -0
  192. amsdal/migration/schemas_loaders.pyi +0 -37
  193. amsdal/migration/templates/data_migration.tmpl +0 -18
  194. amsdal/migration/templates/dict_validator.tmpl +0 -4
  195. amsdal/migration/templates/migration.tmpl +0 -6
  196. amsdal/migration/templates/model_class.tmpl +0 -8
  197. amsdal/migration/templates/model_class_layout.tmpl +0 -24
  198. amsdal/migration/templates/options_validator.tmpl +0 -4
  199. amsdal/migration/utils.cpython-312-darwin.so +0 -0
  200. amsdal/migration/utils.pyi +0 -58
  201. amsdal/mixins/build_mixin.cpython-312-darwin.so +0 -0
  202. amsdal/mixins/build_mixin.pyi +0 -78
  203. /amsdal/{migration/__init__.pyi → contrib/auth/models/__init__.py} +0 -0
  204. /amsdal/{migration/executors → contrib/auth/models}/__init__.pyi +0 -0
  205. {amsdal-0.3.6.dist-info → amsdal-0.4.0.dist-info}/LICENSE.txt +0 -0
  206. {amsdal-0.3.6.dist-info → amsdal-0.4.0.dist-info}/WHEEL +0 -0
  207. {amsdal-0.3.6.dist-info → amsdal-0.4.0.dist-info}/licenses/LICENSE.txt +0 -0
  208. {amsdal-0.3.6.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 amsdal_utils.models.enums import SchemaTypes
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
- schema_type=SchemaTypes.CONTRIB,
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
- schema_type=SchemaTypes.CONTRIB,
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
- schema_type=SchemaTypes.CONTRIB,
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
- '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 models.contrib.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",
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.manager import ClassManager
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
- for arg in value.__args__:
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
- if hasattr(value, '__origin__'):
63
- origin_class = value.__origin__
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, ClassManager().resolve_schema_type(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
- function_controls.append(control)
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
- schema = SchemaManager().get_schema_by_name(value.__name__)
213
+ if issubclass(value, Model | TypeModel):
214
+ schema = model_to_object_schema(value)
198
215
  except FileNotFoundError:
199
216
  schema = None
200
217
 
201
- for field_name, field in value.__annotations__.items():
202
- control = convert_to_frontend_config(field, is_transaction=is_transaction)
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 field_name in value.model_fields:
210
- _field = value.model_fields[field_name]
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 {
@@ -1,5 +1,4 @@
1
1
  from _typeshed import Incomplete
2
- from amsdal.schemas.manager import SchemaManager as SchemaManager
3
2
  from types import UnionType
4
3
  from typing import Any
5
4