amsdal 0.3.3__cp311-cp311-macosx_10_9_universal2.whl → 0.5.29__cp311-cp311-macosx_10_9_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.
Files changed (244) hide show
  1. amsdal/Third-Party Materials - AMSDAL Dependencies - License Notices.md +56 -2
  2. amsdal/__about__.py +1 -1
  3. amsdal/__init__.py +20 -0
  4. amsdal/__init__.pyi +9 -0
  5. amsdal/__migrations__/0000_initial.py +23 -190
  6. amsdal/__migrations__/0001_create_class_file.py +61 -0
  7. amsdal/__migrations__/0002_create_class_file.py +109 -0
  8. amsdal/__migrations__/0003_update_class_file.py +91 -0
  9. amsdal/__migrations__/0004_update_class_file.py +45 -0
  10. amsdal/cloud/__init__.cpython-311-darwin.so +0 -0
  11. amsdal/cloud/client.cpython-311-darwin.so +0 -0
  12. amsdal/cloud/constants.cpython-311-darwin.so +0 -0
  13. amsdal/cloud/enums.cpython-311-darwin.so +0 -0
  14. amsdal/cloud/models/__init__.cpython-311-darwin.so +0 -0
  15. amsdal/cloud/models/base.cpython-311-darwin.so +0 -0
  16. amsdal/cloud/services/__init__.cpython-311-darwin.so +0 -0
  17. amsdal/cloud/services/actions/__init__.cpython-311-darwin.so +0 -0
  18. amsdal/cloud/services/actions/add_allowlist_ip.cpython-311-darwin.so +0 -0
  19. amsdal/cloud/services/actions/add_basic_auth.cpython-311-darwin.so +0 -0
  20. amsdal/cloud/services/actions/add_dependency.cpython-311-darwin.so +0 -0
  21. amsdal/cloud/services/actions/add_secret.cpython-311-darwin.so +0 -0
  22. amsdal/cloud/services/actions/base.cpython-311-darwin.so +0 -0
  23. amsdal/cloud/services/actions/create_deploy.cpython-311-darwin.so +0 -0
  24. amsdal/cloud/services/actions/create_env.cpython-311-darwin.so +0 -0
  25. amsdal/cloud/services/actions/create_session.cpython-311-darwin.so +0 -0
  26. amsdal/cloud/services/actions/delete_allowlist_ip.cpython-311-darwin.so +0 -0
  27. amsdal/cloud/services/actions/delete_basic_auth.cpython-311-darwin.so +0 -0
  28. amsdal/cloud/services/actions/delete_dependency.cpython-311-darwin.so +0 -0
  29. amsdal/cloud/services/actions/delete_env.cpython-311-darwin.so +0 -0
  30. amsdal/cloud/services/actions/delete_secret.cpython-311-darwin.so +0 -0
  31. amsdal/cloud/services/actions/destroy_deploy.cpython-311-darwin.so +0 -0
  32. amsdal/cloud/services/actions/expose_db.cpython-311-darwin.so +0 -0
  33. amsdal/cloud/services/actions/get_basic_auth_credentials.cpython-311-darwin.so +0 -0
  34. amsdal/cloud/services/actions/get_monitoring_info.cpython-311-darwin.so +0 -0
  35. amsdal/cloud/services/actions/list_dependencies.cpython-311-darwin.so +0 -0
  36. amsdal/cloud/services/actions/list_deploys.cpython-311-darwin.so +0 -0
  37. amsdal/cloud/services/actions/list_envs.cpython-311-darwin.so +0 -0
  38. amsdal/cloud/services/actions/list_secrets.cpython-311-darwin.so +0 -0
  39. amsdal/cloud/services/actions/manager.cpython-311-darwin.so +0 -0
  40. amsdal/cloud/services/actions/signup_action.cpython-311-darwin.so +0 -0
  41. amsdal/cloud/services/actions/update_deploy.cpython-311-darwin.so +0 -0
  42. amsdal/cloud/services/auth/__init__.cpython-311-darwin.so +0 -0
  43. amsdal/cloud/services/auth/base.cpython-311-darwin.so +0 -0
  44. amsdal/cloud/services/auth/credentials.cpython-311-darwin.so +0 -0
  45. amsdal/cloud/services/auth/credentials.pyi +0 -1
  46. amsdal/cloud/services/auth/manager.cpython-311-darwin.so +0 -0
  47. amsdal/cloud/services/auth/signup_service.cpython-311-darwin.so +0 -0
  48. amsdal/cloud/services/auth/token.cpython-311-darwin.so +0 -0
  49. amsdal/cloud/services/auth/token.pyi +0 -1
  50. amsdal/configs/main.py +40 -20
  51. amsdal/configs/main.pyi +19 -18
  52. amsdal/contrib/__init__.cpython-311-darwin.so +0 -0
  53. amsdal/contrib/auth/errors.py +36 -0
  54. amsdal/contrib/auth/errors.pyi +12 -0
  55. amsdal/contrib/auth/fixtures/basic_permissions.json +64 -0
  56. amsdal/contrib/auth/lifecycle/consumer.py +13 -13
  57. amsdal/contrib/auth/lifecycle/consumer.pyi +3 -0
  58. amsdal/contrib/auth/migrations/0000_initial.py +69 -31
  59. amsdal/contrib/auth/migrations/0001_add_mfa_support.py +188 -0
  60. amsdal/contrib/auth/models/__init__.py +1 -0
  61. amsdal/contrib/auth/models/backup_code.py +85 -0
  62. amsdal/contrib/auth/models/email_mfa_device.py +108 -0
  63. amsdal/contrib/auth/models/login_session.py +235 -0
  64. amsdal/contrib/auth/models/mfa_device.py +86 -0
  65. amsdal/contrib/auth/models/permission.py +23 -0
  66. amsdal/contrib/auth/models/sms_device.py +113 -0
  67. amsdal/contrib/auth/models/totp_device.py +58 -0
  68. amsdal/contrib/auth/models/user.py +156 -0
  69. amsdal/contrib/auth/services/__init__.py +1 -0
  70. amsdal/contrib/auth/services/mfa_device_service.py +544 -0
  71. amsdal/contrib/auth/services/mfa_device_service.pyi +216 -0
  72. amsdal/contrib/auth/services/totp_service.py +358 -0
  73. amsdal/contrib/auth/services/totp_service.pyi +158 -0
  74. amsdal/contrib/auth/settings.py +8 -0
  75. amsdal/contrib/auth/settings.pyi +8 -0
  76. amsdal/contrib/auth/transactions/__init__.py +1 -0
  77. amsdal/contrib/auth/transactions/mfa_device_transactions.py +463 -0
  78. amsdal/contrib/auth/transactions/mfa_device_transactions.pyi +226 -0
  79. amsdal/contrib/auth/transactions/totp_transactions.py +206 -0
  80. amsdal/contrib/auth/transactions/totp_transactions.pyi +113 -0
  81. amsdal/contrib/auth/utils/__init__.py +0 -0
  82. amsdal/contrib/auth/utils/__init__.pyi +0 -0
  83. amsdal/contrib/auth/utils/mfa.py +257 -0
  84. amsdal/contrib/auth/utils/mfa.pyi +119 -0
  85. amsdal/contrib/frontend_configs/conversion/convert.py +85 -25
  86. amsdal/contrib/frontend_configs/conversion/convert.pyi +0 -1
  87. amsdal/contrib/frontend_configs/lifecycle/consumer.py +32 -13
  88. amsdal/contrib/frontend_configs/lifecycle/consumer.pyi +1 -1
  89. amsdal/contrib/frontend_configs/migrations/0000_initial.py +167 -195
  90. amsdal/contrib/frontend_configs/migrations/0001_update_frontend_control_config.py +245 -0
  91. amsdal/contrib/frontend_configs/migrations/0002_add_button_and_invoke_actions.py +352 -0
  92. amsdal/contrib/frontend_configs/migrations/0003_create_class_frontendconfigdashboardelement.py +145 -0
  93. amsdal/contrib/frontend_configs/models/__init__.py +0 -0
  94. amsdal/contrib/frontend_configs/models/frontend_activator_config.py +22 -0
  95. amsdal/contrib/frontend_configs/models/frontend_config_async_validator.py +11 -0
  96. amsdal/contrib/frontend_configs/models/frontend_config_control_action.py +110 -0
  97. amsdal/contrib/frontend_configs/models/frontend_config_dashboard.py +51 -0
  98. amsdal/contrib/frontend_configs/models/frontend_config_group_validator.py +21 -0
  99. amsdal/contrib/frontend_configs/models/frontend_config_option.py +12 -0
  100. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base.py +17 -0
  101. amsdal/contrib/frontend_configs/models/frontend_config_slider_option.py +13 -0
  102. amsdal/contrib/frontend_configs/models/frontend_config_text_mask.py +14 -0
  103. amsdal/contrib/frontend_configs/models/frontend_config_validator.py +28 -0
  104. amsdal/contrib/frontend_configs/models/frontend_control_config.py +110 -0
  105. amsdal/contrib/frontend_configs/models/frontend_model_config.py +14 -0
  106. amsdal/errors.py +0 -3
  107. amsdal/errors.pyi +0 -1
  108. amsdal/fixtures/__init__.cpython-311-darwin.so +0 -0
  109. amsdal/fixtures/manager.cpython-311-darwin.so +0 -0
  110. amsdal/fixtures/manager.pyi +73 -123
  111. amsdal/fixtures/utils.cpython-311-darwin.so +0 -0
  112. amsdal/fixtures/utils.pyi +9 -0
  113. amsdal/manager.cpython-311-darwin.so +0 -0
  114. amsdal/manager.pyi +9 -96
  115. amsdal/mixins/__init__.cpython-311-darwin.so +0 -0
  116. amsdal/mixins/class_versions_mixin.cpython-311-darwin.so +0 -0
  117. amsdal/models/__init__.py +19 -0
  118. amsdal/models/core/__init__.py +0 -0
  119. amsdal/models/core/class_object.py +38 -0
  120. amsdal/models/core/class_property.py +26 -0
  121. amsdal/models/core/file.py +243 -0
  122. amsdal/models/core/fixture.py +25 -0
  123. amsdal/models/core/option.py +11 -0
  124. amsdal/models/core/storage_metadata.py +15 -0
  125. amsdal/models/core/validator.py +12 -0
  126. amsdal/models/mixins.py +31 -0
  127. amsdal/models/types/__init__.py +0 -0
  128. amsdal/models/types/object.py +26 -0
  129. amsdal/queryset/__init__.py +21 -0
  130. amsdal/queryset/__init__.pyi +6 -0
  131. amsdal/schemas/core/class_object/model.json +20 -0
  132. amsdal/schemas/core/class_property/model.json +19 -0
  133. amsdal/schemas/core/file/properties/from_file.py +1 -1
  134. amsdal/schemas/core/file/properties/validate_data.py +3 -4
  135. amsdal/schemas/core/storage_metadata/model.json +52 -0
  136. amsdal/schemas/interfaces.py +25 -0
  137. amsdal/schemas/interfaces.pyi +20 -0
  138. amsdal/schemas/manager.cpython-311-darwin.so +0 -0
  139. amsdal/schemas/manager.py +0 -116
  140. amsdal/schemas/manager.pyi +0 -65
  141. amsdal/schemas/mixins/__init__.py +0 -0
  142. amsdal/schemas/mixins/__init__.pyi +0 -0
  143. amsdal/schemas/mixins/check_dependencies_mixin.py +130 -0
  144. amsdal/schemas/mixins/check_dependencies_mixin.pyi +45 -0
  145. amsdal/schemas/mixins/verify_schemas_mixin.py +96 -0
  146. amsdal/schemas/mixins/verify_schemas_mixin.pyi +33 -0
  147. amsdal/schemas/repository.py +84 -0
  148. amsdal/schemas/repository.pyi +22 -0
  149. amsdal/schemas/utils.py +16 -0
  150. amsdal/schemas/utils.pyi +10 -0
  151. amsdal/services/__init__.py +11 -0
  152. amsdal/services/__init__.pyi +4 -0
  153. amsdal/services/external_connections.py +262 -0
  154. amsdal/services/external_connections.pyi +190 -0
  155. amsdal/services/external_model_generator.py +350 -0
  156. amsdal/services/external_model_generator.pyi +134 -0
  157. amsdal/services/transaction_execution.cpython-311-darwin.so +0 -0
  158. amsdal/services/transaction_execution.pyi +2 -1
  159. amsdal/storages/__init__.py +20 -0
  160. amsdal/storages/__init__.pyi +8 -0
  161. amsdal/storages/file_system.py +214 -0
  162. amsdal/storages/file_system.pyi +36 -0
  163. amsdal/transactions/__init__.py +13 -0
  164. amsdal/transactions/__init__.pyi +4 -0
  165. amsdal/utils/rollback/__init__.py +99 -54
  166. amsdal/utils/rollback/__init__.pyi +6 -0
  167. amsdal/utils/tests/enums.py +0 -2
  168. amsdal/utils/tests/helpers.py +253 -231
  169. amsdal/utils/tests/migrations.py +157 -0
  170. {amsdal-0.3.3.dist-info → amsdal-0.5.29.dist-info}/METADATA +17 -10
  171. amsdal-0.5.29.dist-info/RECORD +276 -0
  172. {amsdal-0.3.3.dist-info → amsdal-0.5.29.dist-info}/WHEEL +1 -1
  173. amsdal/__migrations__/0001_datetime_type.py +0 -18
  174. amsdal/__migrations__/0002_fixture_order.py +0 -40
  175. amsdal/__migrations__/0003_schema_type_in_class_meta.py +0 -56
  176. amsdal/contrib/auth/models/login_session/hooks/pre_init.py +0 -68
  177. amsdal/contrib/auth/models/login_session/model.json +0 -23
  178. amsdal/contrib/auth/models/login_session/modifiers/display_name.py +0 -11
  179. amsdal/contrib/auth/models/permission/fixtures/basic_permissions.json +0 -62
  180. amsdal/contrib/auth/models/permission/model.json +0 -18
  181. amsdal/contrib/auth/models/permission/modifiers/display_name.py +0 -11
  182. amsdal/contrib/auth/models/user/hooks/post_init.py +0 -76
  183. amsdal/contrib/auth/models/user/hooks/pre_create.py +0 -8
  184. amsdal/contrib/auth/models/user/model.json +0 -25
  185. amsdal/contrib/auth/models/user/modifiers/display_name.py +0 -19
  186. amsdal/contrib/frontend_configs/models/frontend_activator_config/model.json +0 -11
  187. amsdal/contrib/frontend_configs/models/frontend_config_async_validator/model.json +0 -11
  188. amsdal/contrib/frontend_configs/models/frontend_config_group_validator/model.json +0 -52
  189. amsdal/contrib/frontend_configs/models/frontend_config_option/model.json +0 -15
  190. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base/model.json +0 -6
  191. amsdal/contrib/frontend_configs/models/frontend_config_skip_none_base/properties/model_dump.py +0 -13
  192. amsdal/contrib/frontend_configs/models/frontend_config_slider_option/model.json +0 -19
  193. amsdal/contrib/frontend_configs/models/frontend_config_text_mask/model.json +0 -26
  194. amsdal/contrib/frontend_configs/models/frontend_config_validator/model.json +0 -41
  195. amsdal/contrib/frontend_configs/models/frontend_control_config/model.json +0 -250
  196. amsdal/contrib/frontend_configs/models/frontend_model_config/fixtures/permissions.json +0 -24
  197. amsdal/contrib/frontend_configs/models/frontend_model_config/model.json +0 -17
  198. amsdal/contrib/frontend_configs/models/frontent_config_control_action/model.json +0 -54
  199. amsdal/contrib/frontend_configs/models/frontent_config_control_action/properties/action_validate.py +0 -33
  200. amsdal/migration/__init__.cpython-311-darwin.so +0 -0
  201. amsdal/migration/base_migration_schemas.cpython-311-darwin.so +0 -0
  202. amsdal/migration/base_migration_schemas.pyi +0 -120
  203. amsdal/migration/data_classes.cpython-311-darwin.so +0 -0
  204. amsdal/migration/data_classes.pyi +0 -172
  205. amsdal/migration/executors/__init__.cpython-311-darwin.so +0 -0
  206. amsdal/migration/executors/base.cpython-311-darwin.so +0 -0
  207. amsdal/migration/executors/base.pyi +0 -118
  208. amsdal/migration/executors/default_executor.cpython-311-darwin.so +0 -0
  209. amsdal/migration/executors/default_executor.pyi +0 -184
  210. amsdal/migration/executors/state_executor.cpython-311-darwin.so +0 -0
  211. amsdal/migration/executors/state_executor.pyi +0 -78
  212. amsdal/migration/file_migration_executor.cpython-311-darwin.so +0 -0
  213. amsdal/migration/file_migration_executor.pyi +0 -68
  214. amsdal/migration/file_migration_generator.cpython-311-darwin.so +0 -0
  215. amsdal/migration/file_migration_generator.pyi +0 -139
  216. amsdal/migration/file_migration_store.cpython-311-darwin.so +0 -0
  217. amsdal/migration/file_migration_store.pyi +0 -61
  218. amsdal/migration/file_migration_writer.cpython-311-darwin.so +0 -0
  219. amsdal/migration/file_migration_writer.pyi +0 -73
  220. amsdal/migration/migrations.cpython-311-darwin.so +0 -0
  221. amsdal/migration/migrations.pyi +0 -166
  222. amsdal/migration/migrations_loader.cpython-311-darwin.so +0 -0
  223. amsdal/migration/migrations_loader.pyi +0 -32
  224. amsdal/migration/schemas_loaders.cpython-311-darwin.so +0 -0
  225. amsdal/migration/schemas_loaders.pyi +0 -37
  226. amsdal/migration/templates/data_migration.tmpl +0 -18
  227. amsdal/migration/templates/dict_validator.tmpl +0 -4
  228. amsdal/migration/templates/migration.tmpl +0 -6
  229. amsdal/migration/templates/model_class.tmpl +0 -8
  230. amsdal/migration/templates/model_class_layout.tmpl +0 -24
  231. amsdal/migration/templates/options_validator.tmpl +0 -4
  232. amsdal/migration/utils.cpython-311-darwin.so +0 -0
  233. amsdal/migration/utils.pyi +0 -58
  234. amsdal/mixins/build_mixin.cpython-311-darwin.so +0 -0
  235. amsdal/mixins/build_mixin.pyi +0 -78
  236. amsdal/schemas/core/class_object_meta/model.json +0 -59
  237. amsdal/schemas/core/class_property_meta/model.json +0 -23
  238. amsdal/services/__init__.cpython-311-darwin.so +0 -0
  239. amsdal-0.3.3.dist-info/RECORD +0 -257
  240. amsdal-0.3.3.dist-info/licenses/LICENSE.txt +0 -107
  241. /amsdal/{migration → contrib/auth/services}/__init__.pyi +0 -0
  242. /amsdal/{migration/executors → contrib/auth/transactions}/__init__.pyi +0 -0
  243. {amsdal-0.3.3.dist-info → amsdal-0.5.29.dist-info/licenses}/LICENSE.txt +0 -0
  244. {amsdal-0.3.3.dist-info → amsdal-0.5.29.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,45 @@
1
+ from amsdal_models.migration import migrations
2
+ from amsdal_utils.models.enums import ModuleType
3
+
4
+
5
+ class Migration(migrations.Migration):
6
+ operations: list[migrations.Operation] = [
7
+ migrations.UpdateClass(
8
+ module_type=ModuleType.CORE,
9
+ class_name="File",
10
+ old_schema={
11
+ "title": "File",
12
+ "required": ["filename"],
13
+ "properties": {
14
+ "filename": {"type": "string", "title": "Filename"},
15
+ "data": {"type": "binary", "title": "Data"},
16
+ "size": {"type": "number", "title": "Size"},
17
+ "storage_address": {"type": "anything", "title": "Storage Reference"},
18
+ },
19
+ "custom_code": 'import base64\nimport io\nfrom contextlib import suppress\nfrom pathlib import Path\nfrom typing import IO\nfrom typing import Any\nfrom typing import BinaryIO\n\nfrom amsdal_models.storage.backends.db import DBStorage\nfrom amsdal_models.storage.base import Storage\nfrom pydantic import model_validator\n\n\n@classmethod\ndef data_base64_decode(cls, data: Any) -> bytes:\n if isinstance(data, str):\n data = data.encode(\'utf-8\')\n is_base64: bool = False\n with suppress(Exception):\n is_base64 = base64.b64encode(base64.b64decode(data)) == data\n if is_base64:\n return base64.b64decode(data)\n return data\n\n@classmethod\ndef from_bytes(cls, filename: str, data: bytes) -> \'File\':\n """\n Creates a `File` object from a byte string.\n\n Args:\n filename (str): The filename of the file.\n data (bytes): The byte string containing the file data.:\n\n Returns:\n File: The created `File` object.\n """\n obj = cls(filename=filename, data=data, size=len(data))\n obj._needs_persist = True\n return obj\n\n@classmethod\ndef from_file(cls, file_or_path: Path | BinaryIO) -> \'File\':\n """\n Creates a `File` object from a file path or a binary file object.\n\n Args:\n file_or_path (Path | BinaryIO): The file path or binary file object.\n\n Returns:\n File: The created `File` object.\n\n Raises:\n ValueError: If the provided path is a directory.\n """\n f: BinaryIO | io.BufferedReader\n if isinstance(file_or_path, Path):\n if file_or_path.is_dir():\n msg = f\'{file_or_path} is a directory\'\n raise ValueError(msg)\n f = file_or_path.open(\'rb\')\n filename = file_or_path.name\n size = file_or_path.stat().st_size\n else:\n f = file_or_path\n filename = Path(getattr(f, \'name\', \'unnamed\')).name\n try:\n if f.seekable():\n f.seek(0, io.SEEK_END)\n size = f.tell()\n f.seek(0)\n else:\n size = None\n except (OSError, AttributeError):\n size = None\n obj = cls(filename=filename, size=size)\n obj._source = f\n obj._needs_persist = True\n return obj\n\n@model_validator(mode=\'before\')\n@classmethod\ndef validate_model_data(cls, data: Any) -> Any:\n if isinstance(data, dict):\n if \'data\' in data:\n if data[\'data\']:\n data[\'data\'] = cls.data_base64_decode(data[\'data\'])\n data[\'size\'] = len(data[\'data\'])\n else:\n data[\'size\'] = 0\n return data\n\n@property\ndef mimetype(self) -> str | None:\n """\n Returns the MIME type of the file based on its filename.\n\n This method uses the `mimetypes` module to guess the MIME type of the file.\n\n Returns:\n str | None: The guessed MIME type of the file, or None if it cannot be determined.\n """\n import mimetypes\n return mimetypes.guess_type(self.filename)[0]\n\n@property\ndef storage(self) -> Storage:\n from amsdal.storages import default_storage\n if self._storage:\n return self._storage\n if self.storage_address:\n return Storage.from_storage_spec({\'storage_class\': self.storage_address.ref.resource})\n return default_storage()\n\nasync def aopen(self, mode: str=\'rb\') -> Any:\n """\n Async variant of open().\n\n Uses the resolved storage to call aopen(); if the backend does not implement\n async, falls back to the sync open().\n """\n try:\n return await self.storage.aopen(self, mode)\n except NotImplementedError:\n return self.storage.open(self, mode)\n\nasync def apre_create(self) -> None:\n if self._needs_persist:\n from amsdal_models.storage.persistence import apersist_file\n await apersist_file(self, storage=self.storage)\n\nasync def apre_update(self) -> None:\n if self._needs_persist:\n from amsdal_models.storage.persistence import apersist_file\n await apersist_file(self, storage=self.storage)\n\nasync def aread_bytes(self) -> bytes:\n async with await self.aopen() as f:\n return await f.read()\n\nasync def aurl(self) -> str:\n """\n Async variant of url().\n\n Uses the resolved storage to call aurl(); if the backend does not implement\n async, falls back to the sync url().\n """\n try:\n return await self.storage.aurl(self)\n except NotImplementedError:\n return self.storage.url(self)\n\ndef __repr__(self) -> str:\n return f"File<{self.filename}>({self.size or len(self.data or \'\') or 0} bytes)"\n\ndef __str__(self) -> str:\n return repr(self)\n\ndef open(self, mode: str=\'rb\') -> IO[Any]:\n """\n Open a binary stream for reading (or other modes if supported) using storage_address.\n\n Raises StateError if storage_address is missing.\n """\n return self.storage.open(self, mode)\n\ndef pre_create(self) -> None:\n if self._needs_persist:\n from amsdal_models.storage.persistence import persist_file\n persist_file(self, storage=self.storage)\n\ndef pre_update(self) -> None:\n if self._needs_persist:\n from amsdal_models.storage.persistence import persist_file\n persist_file(self, storage=self.storage)\n\ndef read_bytes(self) -> bytes:\n with self.open() as f:\n return f.read()\n\ndef set_data(self, data: bytes | str) -> None:\n if not isinstance(self.storage, DBStorage):\n msg = \'Cannot set data on a file that is not stored in a database. Use `File.from_bytes` instead.\'\n raise ValueError(msg)\n self.data = self.data_base64_decode(data)\n self.size = len(self.data)\n self._needs_persist = True\n\ndef to_file(self, file_or_path: Path | BinaryIO) -> None:\n """\n Writes the object\'s data to a file path or a binary file object.\n\n Args:\n file_or_path (Path | BinaryIO): The file path or binary file object where the data will be written.\n\n Returns:\n None\n\n Raises:\n ValueError: If the provided path is a directory.\n """\n with self.open() as f:\n if isinstance(file_or_path, Path):\n if file_or_path.is_dir():\n file_or_path = file_or_path / self.name\n file_or_path.write_bytes(f.read())\n else:\n file_or_path.write(f.read())\n file_or_path.seek(0)\n\ndef url(self) -> str:\n """\n Return a URL for this file using its storage_address.\n\n Raises StateError if storage_address is missing.\n """\n return self.storage.url(self)',
20
+ "storage_metadata": {
21
+ "table_name": "File",
22
+ "db_fields": {},
23
+ "primary_key": ["partition_key"],
24
+ "foreign_keys": {},
25
+ },
26
+ },
27
+ new_schema={
28
+ "title": "File",
29
+ "required": ["filename"],
30
+ "properties": {
31
+ "filename": {"type": "string", "title": "Filename"},
32
+ "data": {"type": "binary", "title": "Data"},
33
+ "size": {"type": "number", "title": "Size"},
34
+ "storage_address": {"type": "anything", "title": "Storage Reference"},
35
+ },
36
+ "custom_code": 'import base64\nimport io\nfrom contextlib import suppress\nfrom pathlib import Path\nfrom typing import IO\nfrom typing import Any\nfrom typing import BinaryIO\n\nfrom amsdal_models.storage.backends.db import AsyncFileWrapper\nfrom amsdal_models.storage.backends.db import DBStorage\nfrom amsdal_models.storage.base import Storage\nfrom pydantic import model_validator\n\n\n@classmethod\ndef data_base64_decode(cls, data: Any) -> bytes:\n if isinstance(data, str):\n data = data.encode(\'utf-8\')\n is_base64: bool = False\n with suppress(Exception):\n is_base64 = base64.b64encode(base64.b64decode(data)) == data\n if is_base64:\n return base64.b64decode(data)\n return data\n\n@classmethod\ndef from_bytes(cls, filename: str, data: bytes) -> \'File\':\n """\n Creates a `File` object from a byte string.\n\n Args:\n filename (str): The filename of the file.\n data (bytes): The byte string containing the file data.:\n\n Returns:\n File: The created `File` object.\n """\n obj = cls(filename=filename, data=data, size=len(data))\n return obj\n\n@classmethod\ndef from_file(cls, file_or_path: Path | BinaryIO) -> \'File\':\n """\n Creates a `File` object from a file path or a binary file object.\n\n Args:\n file_or_path (Path | BinaryIO): The file path or binary file object.\n\n Returns:\n File: The created `File` object.\n\n Raises:\n ValueError: If the provided path is a directory.\n """\n f: BinaryIO | io.BufferedReader\n if isinstance(file_or_path, Path):\n if file_or_path.is_dir():\n msg = f\'{file_or_path} is a directory\'\n raise ValueError(msg)\n f = file_or_path.open(\'rb\')\n filename = file_or_path.name\n size = file_or_path.stat().st_size\n else:\n f = file_or_path\n filename = Path(getattr(f, \'name\', \'unnamed\')).name\n try:\n if f.seekable():\n f.seek(0, io.SEEK_END)\n size = f.tell()\n f.seek(0)\n else:\n size = None\n except (OSError, AttributeError):\n size = None\n obj = cls(filename=filename, size=size)\n obj._source = f\n return obj\n\n@model_validator(mode=\'before\')\n@classmethod\ndef validate_model_data(cls, data: Any) -> Any:\n if isinstance(data, dict):\n if \'data\' in data:\n if data[\'data\']:\n data[\'data\'] = cls.data_base64_decode(data[\'data\'])\n data[\'size\'] = len(data[\'data\'])\n else:\n data[\'size\'] = 0\n return data\n\n@property\ndef mimetype(self) -> str | None:\n """\n Returns the MIME type of the file based on its filename.\n\n This method uses the `mimetypes` module to guess the MIME type of the file.\n\n Returns:\n str | None: The guessed MIME type of the file, or None if it cannot be determined.\n """\n import mimetypes\n return mimetypes.guess_type(self.filename)[0]\n\n@property\ndef storage(self) -> Storage:\n from amsdal.storages import default_storage\n if self._storage:\n return self._storage\n if self.storage_address:\n return Storage.from_storage_spec({\'storage_class\': self.storage_address.ref.resource})\n return default_storage()\n\nasync def aopen(self, mode: str=\'rb\') -> Any:\n """\n Async variant of open().\n\n Uses the resolved storage to call aopen(); if the backend does not implement\n async, falls back to the sync open().\n """\n try:\n return await self.storage.aopen(self, mode)\n except NotImplementedError:\n return AsyncFileWrapper(self.storage.open(self, mode))\n\nasync def apre_create(self) -> None:\n from amsdal_models.storage.persistence import apersist_file\n await apersist_file(self, storage=self.storage)\n\nasync def apre_update(self) -> None:\n from amsdal_models.storage.persistence import apersist_file\n await apersist_file(self, storage=self.storage)\n\nasync def aread_bytes(self) -> bytes:\n async with await self.aopen() as f:\n return await f.read()\n\nasync def aurl(self) -> str:\n """\n Async variant of url().\n\n Uses the resolved storage to call aurl(); if the backend does not implement\n async, falls back to the sync url().\n """\n try:\n return await self.storage.aurl(self)\n except NotImplementedError:\n return self.storage.url(self)\n\ndef __repr__(self) -> str:\n return f"File<{self.filename}>({self.size or len(self.data or \'\') or 0} bytes)"\n\ndef __str__(self) -> str:\n return repr(self)\n\ndef open(self, mode: str=\'rb\') -> IO[Any]:\n """\n Open a binary stream for reading (or other modes if supported) using storage_address.\n\n Raises StateError if storage_address is missing.\n """\n return self.storage.open(self, mode)\n\ndef pre_create(self) -> None:\n from amsdal_models.storage.persistence import persist_file\n persist_file(self, storage=self.storage)\n\ndef pre_update(self) -> None:\n from amsdal_models.storage.persistence import persist_file\n persist_file(self, storage=self.storage)\n\ndef read_bytes(self) -> bytes:\n with self.open() as f:\n return f.read()\n\ndef set_data(self, data: bytes | str) -> None:\n if not isinstance(self.storage, DBStorage):\n msg = \'Cannot set data on a file that is not stored in a database. Use `File.from_bytes` instead.\'\n raise ValueError(msg)\n self.data = self.data_base64_decode(data)\n self.size = len(self.data)\n\ndef to_file(self, file_or_path: Path | BinaryIO) -> None:\n """\n Writes the object\'s data to a file path or a binary file object.\n\n Args:\n file_or_path (Path | BinaryIO): The file path or binary file object where the data will be written.\n\n Returns:\n None\n\n Raises:\n ValueError: If the provided path is a directory.\n """\n with self.open() as f:\n if isinstance(file_or_path, Path):\n if file_or_path.is_dir():\n file_or_path = file_or_path / self.name\n file_or_path.write_bytes(f.read())\n else:\n file_or_path.write(f.read())\n file_or_path.seek(0)\n\ndef url(self) -> str:\n """\n Return a URL for this file using its storage_address.\n\n Raises StateError if storage_address is missing.\n """\n return self.storage.url(self)',
37
+ "storage_metadata": {
38
+ "table_name": "File",
39
+ "db_fields": {},
40
+ "primary_key": ["partition_key"],
41
+ "foreign_keys": {},
42
+ },
43
+ },
44
+ ),
45
+ ]
Binary file
Binary file
Binary file
@@ -6,7 +6,6 @@ from amsdal.cloud.services.actions.create_session import CreateSessionAction as
6
6
  from amsdal.cloud.services.auth.base import AuthHandlerBase as AuthHandlerBase
7
7
  from amsdal.cloud.services.auth.token import TokenAuthHandler as TokenAuthHandler
8
8
  from amsdal.errors import AmsdalAuthenticationError as AmsdalAuthenticationError
9
- from amsdal.schemas.manager import SchemaManager as SchemaManager
10
9
 
11
10
  class CredentialsAuthHandler(AuthHandlerBase):
12
11
  """
@@ -2,7 +2,6 @@ from _typeshed import Incomplete
2
2
  from amsdal.cloud.constants import JWT_PUBLIC_KEY as JWT_PUBLIC_KEY
3
3
  from amsdal.cloud.services.auth.base import AuthHandlerBase as AuthHandlerBase
4
4
  from amsdal.errors import AmsdalAuthenticationError as AmsdalAuthenticationError
5
- from amsdal.schemas.manager import SchemaManager as SchemaManager
6
5
 
7
6
  HMAC_KEY: bytes
8
7
 
amsdal/configs/main.py CHANGED
@@ -48,20 +48,33 @@ class Settings(BaseSettings):
48
48
 
49
49
  APP_PATH: Path = Path('.')
50
50
  CONFIG_PATH: Path | None = None
51
- MODELS_MODULE_NAME: str = 'models'
52
- SCHEMAS_MODULE_NAME: str = 'schemas'
51
+ TYPE_MODELS_MODULE: str = 'amsdal.models.types'
52
+ CORE_MODELS_MODULE: str = 'amsdal.models.core'
53
+ USER_MODELS_MODULE_PATH: Path | None = None
54
+ USER_MODELS_MODULE: str = 'models'
55
+ FIXTURES_MODULE_PATH: Path | None = None
53
56
  FIXTURES_MODULE_NAME: str = 'fixtures'
57
+ STATIC_MODULE_PATH: Path | None = None
54
58
  STATIC_MODULE_NAME: str = 'static'
59
+ TRANSACTIONS_MODULE_PATH: Path | None = None
55
60
  TRANSACTIONS_MODULE_NAME: str = 'transactions'
61
+ MIGRATIONS_MODULE_PATH: Path | None = None
56
62
  MIGRATIONS_DIRECTORY_NAME: str = 'migrations'
57
63
  ACCESS_KEY_ID: str | None = None
58
64
  SECRET_ACCESS_KEY: str | None = None
59
65
  ACCESS_TOKEN: str | None = None
60
66
  SANDBOX_ENVIRONMENT: bool | None = None
61
- CONTRIBS: list[str] = [
67
+ CONTRIBS: list[str] | str = [
62
68
  'amsdal.contrib.auth.app.AuthAppConfig',
63
69
  'amsdal.contrib.frontend_configs.app.FrontendConfigAppConfig',
64
70
  ]
71
+ CONTRIB_MODELS_PACKAGE_NAME: str = 'models'
72
+ CONTRIB_MIGRATIONS_DIRECTORY_NAME: str = 'migrations'
73
+
74
+ # File Storage
75
+ MEDIA_ROOT: Path = Path('./media')
76
+ MEDIA_URL: str = '/media/'
77
+ DEFAULT_FILE_STORAGE: str = 'amsdal_models.storage.backends.db.DBStorage'
65
78
 
66
79
  @field_validator('CONTRIBS', mode='after')
67
80
  def load_contrib_modules(cls, value: list[str]) -> list[str]: # noqa: N805
@@ -88,7 +101,7 @@ class Settings(BaseSettings):
88
101
  return value
89
102
 
90
103
  @property
91
- def models_root_path(self) -> Path:
104
+ def user_models_path(self) -> Path:
92
105
  """
93
106
  Returns the root path for models.
94
107
 
@@ -98,20 +111,16 @@ class Settings(BaseSettings):
98
111
  Returns:
99
112
  Path: The root path for the models directory.
100
113
  """
101
- return self.APP_PATH / self.MODELS_MODULE_NAME
114
+ if self.USER_MODELS_MODULE_PATH:
115
+ return self.USER_MODELS_MODULE_PATH
102
116
 
103
- @property
104
- def schemas_root_path(self) -> Path:
105
- """
106
- Returns the root path for schemas.
117
+ if '.' in self.USER_MODELS_MODULE:
118
+ _package, _ = self.USER_MODELS_MODULE.split('.', 1)
119
+ _module = importlib.import_module(_package)
107
120
 
108
- This property constructs and returns the path to the schemas directory
109
- based on the `APP_PATH` and `SCHEMAS_MODULE_NAME` attributes.
121
+ return Path(_module.__path__[0])
110
122
 
111
- Returns:
112
- Path: The root path for the schemas directory.
113
- """
114
- return self.APP_PATH / self.SCHEMAS_MODULE_NAME
123
+ return self.APP_PATH / self.USER_MODELS_MODULE
115
124
 
116
125
  @property
117
126
  def fixtures_root_path(self) -> Path:
@@ -124,7 +133,7 @@ class Settings(BaseSettings):
124
133
  Returns:
125
134
  Path: The root path for the fixtures directory.
126
135
  """
127
- return self.APP_PATH / self.FIXTURES_MODULE_NAME
136
+ return self.FIXTURES_MODULE_PATH or self.APP_PATH / self.FIXTURES_MODULE_NAME
128
137
 
129
138
  @property
130
139
  def static_root_path(self) -> Path:
@@ -137,7 +146,7 @@ class Settings(BaseSettings):
137
146
  Returns:
138
147
  Path: The root path for the static files directory.
139
148
  """
140
- return self.APP_PATH / self.STATIC_MODULE_NAME
149
+ return self.STATIC_MODULE_PATH or self.APP_PATH / self.STATIC_MODULE_NAME
141
150
 
142
151
  @property
143
152
  def transactions_root_path(self) -> Path:
@@ -150,7 +159,7 @@ class Settings(BaseSettings):
150
159
  Returns:
151
160
  Path: The root path for the transactions directory.
152
161
  """
153
- return self.models_root_path / self.TRANSACTIONS_MODULE_NAME
162
+ return self.TRANSACTIONS_MODULE_PATH or self.APP_PATH / self.TRANSACTIONS_MODULE_NAME
154
163
 
155
164
  @property
156
165
  def migrations_root_path(self) -> Path:
@@ -163,10 +172,10 @@ class Settings(BaseSettings):
163
172
  Returns:
164
173
  Path: The root path for the migrations directory.
165
174
  """
166
- return self.models_root_path / self.MIGRATIONS_DIRECTORY_NAME
175
+ return self.MIGRATIONS_MODULE_PATH or self.APP_PATH / self.MIGRATIONS_DIRECTORY_NAME
167
176
 
168
177
  @model_validator(mode='after')
169
- def check_passwords_match(self) -> 'Settings':
178
+ def check_config_path_set(self) -> 'Settings':
170
179
  """
171
180
  Ensures the configuration path is set.
172
181
 
@@ -183,6 +192,17 @@ class Settings(BaseSettings):
183
192
 
184
193
  return self
185
194
 
195
+ @model_validator(mode='before')
196
+ @classmethod
197
+ def normalize_complex_values(cls, data: Any) -> Any:
198
+ if isinstance(data, dict):
199
+ if 'CONTRIBS' in data:
200
+ contribs = data['CONTRIBS']
201
+
202
+ if isinstance(contribs, str) and '[' not in contribs:
203
+ data['CONTRIBS'] = [item.strip() for item in contribs.split(',')]
204
+ return data
205
+
186
206
 
187
207
  if TYPE_CHECKING:
188
208
  base: TypeAlias = Settings
amsdal/configs/main.pyi CHANGED
@@ -33,17 +33,28 @@ class Settings(BaseSettings):
33
33
  model_config: Incomplete
34
34
  APP_PATH: Path
35
35
  CONFIG_PATH: Path | None
36
- MODELS_MODULE_NAME: str
37
- SCHEMAS_MODULE_NAME: str
36
+ TYPE_MODELS_MODULE: str
37
+ CORE_MODELS_MODULE: str
38
+ USER_MODELS_MODULE_PATH: Path | None
39
+ USER_MODELS_MODULE: str
40
+ FIXTURES_MODULE_PATH: Path | None
38
41
  FIXTURES_MODULE_NAME: str
42
+ STATIC_MODULE_PATH: Path | None
39
43
  STATIC_MODULE_NAME: str
44
+ TRANSACTIONS_MODULE_PATH: Path | None
40
45
  TRANSACTIONS_MODULE_NAME: str
46
+ MIGRATIONS_MODULE_PATH: Path | None
41
47
  MIGRATIONS_DIRECTORY_NAME: str
42
48
  ACCESS_KEY_ID: str | None
43
49
  SECRET_ACCESS_KEY: str | None
44
50
  ACCESS_TOKEN: str | None
45
51
  SANDBOX_ENVIRONMENT: bool | None
46
- CONTRIBS: list[str]
52
+ CONTRIBS: list[str] | str
53
+ CONTRIB_MODELS_PACKAGE_NAME: str
54
+ CONTRIB_MIGRATIONS_DIRECTORY_NAME: str
55
+ MEDIA_ROOT: Path
56
+ MEDIA_URL: str
57
+ DEFAULT_FILE_STORAGE: str
47
58
  def load_contrib_modules(cls, value: list[str]) -> list[str]:
48
59
  """
49
60
  Loads and initializes contrib modules.
@@ -58,7 +69,7 @@ class Settings(BaseSettings):
58
69
  list[str]: The same list of contrib module paths after loading and initializing the modules.
59
70
  """
60
71
  @property
61
- def models_root_path(self) -> Path:
72
+ def user_models_path(self) -> Path:
62
73
  """
63
74
  Returns the root path for models.
64
75
 
@@ -69,17 +80,6 @@ class Settings(BaseSettings):
69
80
  Path: The root path for the models directory.
70
81
  """
71
82
  @property
72
- def schemas_root_path(self) -> Path:
73
- """
74
- Returns the root path for schemas.
75
-
76
- This property constructs and returns the path to the schemas directory
77
- based on the `APP_PATH` and `SCHEMAS_MODULE_NAME` attributes.
78
-
79
- Returns:
80
- Path: The root path for the schemas directory.
81
- """
82
- @property
83
83
  def fixtures_root_path(self) -> Path:
84
84
  """
85
85
  Returns the root path for fixtures.
@@ -123,7 +123,7 @@ class Settings(BaseSettings):
123
123
  Returns:
124
124
  Path: The root path for the migrations directory.
125
125
  """
126
- def check_passwords_match(self) -> Settings:
126
+ def check_config_path_set(self) -> Settings:
127
127
  """
128
128
  Ensures the configuration path is set.
129
129
 
@@ -133,8 +133,9 @@ class Settings(BaseSettings):
133
133
  Returns:
134
134
  Settings: The updated settings instance with the `CONFIG_PATH` attribute set.
135
135
  """
136
-
137
- base: TypeAlias
136
+ @classmethod
137
+ def normalize_complex_values(cls, data: Any) -> Any: ...
138
+ base: TypeAlias = Settings
138
139
 
139
140
  class SettingsProxy(base):
140
141
  """
@@ -5,3 +5,39 @@ class UserCreationError(AmsdalError): ...
5
5
 
6
6
 
7
7
  class AuthenticationError(AmsdalError): ...
8
+
9
+
10
+ class MFARequiredError(AuthenticationError):
11
+ """Raised when MFA verification is required but not provided."""
12
+
13
+ ...
14
+
15
+
16
+ class InvalidMFACodeError(AuthenticationError):
17
+ """Raised when the provided MFA code is invalid."""
18
+
19
+ ...
20
+
21
+
22
+ class MFADeviceNotFoundError(AmsdalError):
23
+ """Raised when no valid MFA device is found for the user."""
24
+
25
+ ...
26
+
27
+
28
+ class MFASetupError(AmsdalError):
29
+ """Raised when there's an error during MFA device setup."""
30
+
31
+ ...
32
+
33
+
34
+ class PermissionDeniedError(AmsdalError):
35
+ """Raised when a user lacks permission for an operation."""
36
+
37
+ ...
38
+
39
+
40
+ class UserNotFoundError(AmsdalError):
41
+ """Raised when a target user cannot be found."""
42
+
43
+ ...
@@ -2,3 +2,15 @@ from amsdal_utils.errors import AmsdalError
2
2
 
3
3
  class UserCreationError(AmsdalError): ...
4
4
  class AuthenticationError(AmsdalError): ...
5
+ class MFARequiredError(AuthenticationError):
6
+ """Raised when MFA verification is required but not provided."""
7
+ class InvalidMFACodeError(AuthenticationError):
8
+ """Raised when the provided MFA code is invalid."""
9
+ class MFADeviceNotFoundError(AmsdalError):
10
+ """Raised when no valid MFA device is found for the user."""
11
+ class MFASetupError(AmsdalError):
12
+ """Raised when there's an error during MFA device setup."""
13
+ class PermissionDeniedError(AmsdalError):
14
+ """Raised when a user lacks permission for an operation."""
15
+ class UserNotFoundError(AmsdalError):
16
+ """Raised when a target user cannot be found."""
@@ -0,0 +1,64 @@
1
+ {
2
+ "Permission": [
3
+ {
4
+ "_external_id": "user_delete",
5
+ "model": "User",
6
+ "action": "delete"
7
+ },
8
+ {
9
+ "_external_id": "user_read",
10
+ "model": "User",
11
+ "action": "read"
12
+ },
13
+ {
14
+ "_external_id": "user_update",
15
+ "model": "User",
16
+ "action": "update"
17
+ },
18
+ {
19
+ "_external_id": "user_all_actions",
20
+ "model": "User",
21
+ "action": "*"
22
+ },
23
+ {
24
+ "_external_id": "all_models_all_actions",
25
+ "model": "*",
26
+ "action": "*"
27
+ },
28
+ {
29
+ "_external_id": "login_session_delete",
30
+ "model": "LoginSession",
31
+ "action": "delete"
32
+ },
33
+ {
34
+ "_external_id": "login_session_read",
35
+ "model": "LoginSession",
36
+ "action": "read"
37
+ },
38
+ {
39
+ "_external_id": "login_session_update",
40
+ "model": "LoginSession",
41
+ "action": "update"
42
+ },
43
+ {
44
+ "_external_id": "permission_delete",
45
+ "model": "Permission",
46
+ "action": "delete"
47
+ },
48
+ {
49
+ "_external_id": "permission_read",
50
+ "model": "Permission",
51
+ "action": "read"
52
+ },
53
+ {
54
+ "_external_id": "permission_update",
55
+ "model": "Permission",
56
+ "action": "update"
57
+ },
58
+ {
59
+ "_external_id": "permission_create",
60
+ "model": "Permission",
61
+ "action": "create"
62
+ }
63
+ ]
64
+ }
@@ -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
 
@@ -63,9 +63,9 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
63
63
  .execute()
64
64
  )
65
65
 
66
- instance = User(
66
+ instance = User( # type: ignore[call-arg]
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
 
@@ -111,12 +111,12 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
111
111
  .aexecute()
112
112
  )
113
113
 
114
- instance = User(
114
+ instance = User( # type: ignore[call-arg]
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
- await instance.asave(force_insert=True)
119
+ await instance.asave(force_insert=True) # type: ignore[misc]
120
120
  logger.info('Super user created successfully')
121
121
 
122
122
 
@@ -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,5 +1,6 @@
1
1
  from _typeshed import Incomplete
2
2
  from amsdal.contrib.auth.errors import AuthenticationError as AuthenticationError
3
+ from amsdal_data.transactions.decorators import async_transaction, transaction
3
4
  from amsdal_models.classes.model import Model
4
5
  from amsdal_utils.lifecycle.consumer import LifecycleConsumer
5
6
  from typing import Any
@@ -13,6 +14,7 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
13
14
  This consumer checks if a super user exists based on the provided email and password
14
15
  in the authentication settings. If the super user does not exist, it creates one.
15
16
  """
17
+ @transaction
16
18
  def on_event(self) -> None:
17
19
  """
18
20
  Checks for the existence of a super user and creates one if necessary.
@@ -21,6 +23,7 @@ class CheckAndCreateSuperUserConsumer(LifecycleConsumer):
21
23
  in the authentication settings. If the super user does not exist, it creates one
22
24
  with the necessary permissions.
23
25
  """
26
+ @async_transaction
24
27
  async def on_event_async(self) -> None:
25
28
  """
26
29
  Checks for the existence of a super user and creates one if necessary.