amsdal 0.0.41__cp310-cp310-win_amd64.whl → 0.1.1__cp310-cp310-win_amd64.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 (99) hide show
  1. amsdal/__about__.py +1 -1
  2. amsdal/__migrations__/0000_initial.py +203 -0
  3. amsdal/cloud/__init__.cp310-win_amd64.pyd +0 -0
  4. amsdal/cloud/client.cp310-win_amd64.pyd +0 -0
  5. amsdal/cloud/constants.cp310-win_amd64.pyd +0 -0
  6. amsdal/cloud/enums.cp310-win_amd64.pyd +0 -0
  7. amsdal/cloud/models/__init__.cp310-win_amd64.pyd +0 -0
  8. amsdal/cloud/models/base.cp310-win_amd64.pyd +0 -0
  9. amsdal/cloud/services/__init__.cp310-win_amd64.pyd +0 -0
  10. amsdal/cloud/services/actions/__init__.cp310-win_amd64.pyd +0 -0
  11. amsdal/cloud/services/actions/add_dependency.cp310-win_amd64.pyd +0 -0
  12. amsdal/cloud/services/actions/add_secret.cp310-win_amd64.pyd +0 -0
  13. amsdal/cloud/services/actions/base.cp310-win_amd64.pyd +0 -0
  14. amsdal/cloud/services/actions/create_deploy.cp310-win_amd64.pyd +0 -0
  15. amsdal/cloud/services/actions/create_session.cp310-win_amd64.pyd +0 -0
  16. amsdal/cloud/services/actions/delete_dependency.cp310-win_amd64.pyd +0 -0
  17. amsdal/cloud/services/actions/delete_secret.cp310-win_amd64.pyd +0 -0
  18. amsdal/cloud/services/actions/destroy_deploy.cp310-win_amd64.pyd +0 -0
  19. amsdal/cloud/services/actions/expose_db.cp310-win_amd64.pyd +0 -0
  20. amsdal/cloud/services/actions/list_dependencies.cp310-win_amd64.pyd +0 -0
  21. amsdal/cloud/services/actions/list_deploys.cp310-win_amd64.pyd +0 -0
  22. amsdal/cloud/services/actions/list_secrets.cp310-win_amd64.pyd +0 -0
  23. amsdal/cloud/services/actions/manager.cp310-win_amd64.pyd +0 -0
  24. amsdal/cloud/services/actions/signup_action.cp310-win_amd64.pyd +0 -0
  25. amsdal/cloud/services/actions/update_deploy.cp310-win_amd64.pyd +0 -0
  26. amsdal/cloud/services/auth/__init__.cp310-win_amd64.pyd +0 -0
  27. amsdal/cloud/services/auth/base.cp310-win_amd64.pyd +0 -0
  28. amsdal/cloud/services/auth/credentials.cp310-win_amd64.pyd +0 -0
  29. amsdal/cloud/services/auth/manager.cp310-win_amd64.pyd +0 -0
  30. amsdal/cloud/services/auth/signup_service.cp310-win_amd64.pyd +0 -0
  31. amsdal/cloud/services/auth/token.cp310-win_amd64.pyd +0 -0
  32. amsdal/configs/constants.py +2 -0
  33. amsdal/configs/constants.pyi +1 -0
  34. amsdal/configs/main.py +6 -0
  35. amsdal/configs/main.pyi +3 -0
  36. amsdal/contrib/__init__.cp310-win_amd64.pyd +0 -0
  37. amsdal/contrib/auth/migrations/0000_initial.py +49 -0
  38. amsdal/contrib/frontend_configs/migrations/0000_initial.py +255 -0
  39. amsdal/fixtures/__init__.cp310-win_amd64.pyd +0 -0
  40. amsdal/fixtures/manager.cp310-win_amd64.pyd +0 -0
  41. amsdal/manager.cp310-win_amd64.pyd +0 -0
  42. amsdal/manager.pyi +9 -3
  43. amsdal/migration/__init__.cp310-win_amd64.pyd +0 -0
  44. amsdal/migration/base_migration_schemas.cp310-win_amd64.pyd +0 -0
  45. amsdal/migration/base_migration_schemas.pyi +44 -0
  46. amsdal/migration/data_classes.cp310-win_amd64.pyd +0 -0
  47. amsdal/migration/data_classes.pyi +78 -0
  48. amsdal/migration/executors/__init__.cp310-win_amd64.pyd +0 -0
  49. amsdal/migration/executors/base.cp310-win_amd64.pyd +0 -0
  50. amsdal/migration/executors/base.pyi +21 -0
  51. amsdal/migration/executors/default_executor.cp310-win_amd64.pyd +0 -0
  52. amsdal/migration/executors/default_executor.pyi +20 -0
  53. amsdal/migration/executors/state_executor.cp310-win_amd64.pyd +0 -0
  54. amsdal/migration/executors/state_executor.pyi +14 -0
  55. amsdal/migration/file_migration_executor.cp310-win_amd64.pyd +0 -0
  56. amsdal/migration/file_migration_executor.pyi +35 -0
  57. amsdal/migration/file_migration_generator.cp310-win_amd64.pyd +0 -0
  58. amsdal/migration/file_migration_generator.pyi +49 -0
  59. amsdal/migration/file_migration_store.cp310-win_amd64.pyd +0 -0
  60. amsdal/migration/file_migration_store.pyi +33 -0
  61. amsdal/migration/file_migration_writer.cp310-win_amd64.pyd +0 -0
  62. amsdal/migration/file_migration_writer.pyi +18 -0
  63. amsdal/migration/migrations.cp310-win_amd64.pyd +0 -0
  64. amsdal/migration/migrations.pyi +57 -0
  65. amsdal/migration/migrations_loader.cp310-win_amd64.pyd +0 -0
  66. amsdal/migration/migrations_loader.pyi +17 -0
  67. amsdal/migration/schemas_loaders.cp310-win_amd64.pyd +0 -0
  68. amsdal/migration/schemas_loaders.pyi +24 -0
  69. amsdal/migration/utils.cp310-win_amd64.pyd +0 -0
  70. amsdal/migration/utils.pyi +5 -0
  71. amsdal/mixins/__init__.cp310-win_amd64.pyd +0 -0
  72. amsdal/mixins/build_mixin.cp310-win_amd64.pyd +0 -0
  73. amsdal/mixins/build_mixin.pyi +2 -0
  74. amsdal/mixins/class_versions_mixin.cp310-win_amd64.pyd +0 -0
  75. amsdal/mixins/class_versions_mixin.pyi +1 -1
  76. amsdal/operations/__init__.cp310-win_amd64.pyd +0 -0
  77. amsdal/operations/manager.cp310-win_amd64.pyd +0 -0
  78. amsdal/operations/manager.pyi +3 -1
  79. amsdal/schemas/core/class_object/model.json +5 -58
  80. amsdal/schemas/core/class_object_meta/model.json +55 -0
  81. amsdal/schemas/core/class_property/model.json +0 -19
  82. amsdal/schemas/core/class_property_meta/model.json +23 -0
  83. amsdal/schemas/manager.cp310-win_amd64.pyd +0 -0
  84. amsdal/schemas/manager.py +15 -4
  85. amsdal/schemas/manager.pyi +2 -0
  86. amsdal/schemas/types/object/model.json +12 -2
  87. amsdal/services/__init__.cp310-win_amd64.pyd +0 -0
  88. amsdal/services/transaction_execution.cp310-win_amd64.pyd +0 -0
  89. {amsdal-0.0.41.dist-info → amsdal-0.1.1.dist-info}/METADATA +14 -14
  90. {amsdal-0.0.41.dist-info → amsdal-0.1.1.dist-info}/RECORD +94 -69
  91. amsdal/contrib/auth/models/__init__.py +0 -0
  92. amsdal/contrib/frontend_configs/models/__init__.py +0 -0
  93. amsdal/contrib/frontend_configs/models/__init__.pyi +0 -0
  94. amsdal/migration/manager.cp310-win_amd64.pyd +0 -0
  95. amsdal/migration/manager.pyi +0 -20
  96. /amsdal/{contrib/auth/models → migration/executors}/__init__.pyi +0 -0
  97. {amsdal-0.0.41.dist-info → amsdal-0.1.1.dist-info}/LICENSE.txt +0 -0
  98. {amsdal-0.0.41.dist-info → amsdal-0.1.1.dist-info}/WHEEL +0 -0
  99. {amsdal-0.0.41.dist-info → amsdal-0.1.1.dist-info}/top_level.txt +0 -0
amsdal/__about__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2023-present
2
2
  #
3
3
  # SPDX-License-Identifier: AMSDAL End User License Agreement
4
- __version__ = '0.0.41'
4
+ __version__ = '0.1.1'
@@ -0,0 +1,203 @@
1
+ from amsdal_utils.models.enums import SchemaTypes
2
+
3
+ from amsdal.migration import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ operations: list[migrations.Operation] = [
8
+ migrations.CreateClass(
9
+ schema_type=SchemaTypes.TYPE,
10
+ class_name='Object',
11
+ new_schema={
12
+ 'title': 'Object',
13
+ 'properties': {
14
+ 'title': {'type': 'string', 'title': 'Title'},
15
+ 'type': {'type': 'string', 'title': 'Type'},
16
+ 'default': {'type': 'anything', 'title': 'Default'},
17
+ 'properties': {
18
+ 'type': 'dictionary',
19
+ 'items': {'key': {'type': 'string'}, 'value': {'type': 'anything'}},
20
+ 'title': 'Properties',
21
+ },
22
+ 'required': {'type': 'array', 'items': {'type': 'string'}, 'title': 'Required'},
23
+ 'unique': {
24
+ 'type': 'array',
25
+ 'items': {'type': 'array', 'items': {'type': 'string'}},
26
+ 'title': 'Unique Fields',
27
+ },
28
+ 'custom_code': {'type': 'string', 'title': 'Custom Code'},
29
+ 'meta_class': {'type': 'string', 'title': 'Meta Class'},
30
+ },
31
+ },
32
+ ),
33
+ migrations.CreateClass(
34
+ schema_type=SchemaTypes.TYPE,
35
+ class_name='Binary',
36
+ new_schema={'title': 'Binary', 'properties': {}, 'meta_class': 'TypeMeta'},
37
+ ),
38
+ migrations.CreateClass(
39
+ schema_type=SchemaTypes.TYPE,
40
+ class_name='Dictionary',
41
+ new_schema={'title': 'Dictionary', 'properties': {}, 'meta_class': 'TypeMeta'},
42
+ ),
43
+ migrations.CreateClass(
44
+ schema_type=SchemaTypes.TYPE,
45
+ class_name='Anything',
46
+ new_schema={'title': 'Anything', 'properties': {}, 'meta_class': 'TypeMeta'},
47
+ ),
48
+ migrations.CreateClass(
49
+ schema_type=SchemaTypes.TYPE,
50
+ class_name='String',
51
+ new_schema={'title': 'String', 'default': '', 'properties': {}, 'meta_class': 'TypeMeta'},
52
+ ),
53
+ migrations.CreateClass(
54
+ schema_type=SchemaTypes.TYPE,
55
+ class_name='Array',
56
+ new_schema={'title': 'Array', 'properties': {}, 'meta_class': 'TypeMeta'},
57
+ ),
58
+ migrations.CreateClass(
59
+ schema_type=SchemaTypes.TYPE,
60
+ class_name='Number',
61
+ new_schema={'title': 'Number', 'properties': {}, 'meta_class': 'TypeMeta'},
62
+ ),
63
+ migrations.CreateClass(
64
+ schema_type=SchemaTypes.TYPE,
65
+ class_name='Boolean',
66
+ new_schema={
67
+ 'title': 'Boolean',
68
+ 'properties': {},
69
+ 'options': [{'key': 'true', 'value': True}, {'key': 'false', 'value': False}],
70
+ 'meta_class': 'TypeMeta',
71
+ },
72
+ ),
73
+ migrations.CreateClass(
74
+ schema_type=SchemaTypes.CORE,
75
+ class_name='Option',
76
+ new_schema={
77
+ 'title': 'Option',
78
+ 'required': ['key', 'value'],
79
+ 'properties': {
80
+ 'key': {'type': 'string', 'title': 'Key'},
81
+ 'value': {'type': 'string', 'title': 'Value Type'},
82
+ },
83
+ 'meta_class': 'TypeMeta',
84
+ },
85
+ ),
86
+ migrations.CreateClass(
87
+ schema_type=SchemaTypes.CORE,
88
+ class_name='Validator',
89
+ new_schema={
90
+ 'title': 'Validator',
91
+ 'required': ['name', 'data'],
92
+ 'properties': {
93
+ 'name': {'type': 'string', 'title': 'Validator Name'},
94
+ 'data': {'type': 'anything', 'title': 'Validator Data'},
95
+ },
96
+ 'meta_class': 'TypeMeta',
97
+ },
98
+ ),
99
+ migrations.CreateClass(
100
+ schema_type=SchemaTypes.CORE,
101
+ class_name='ClassPropertyMeta',
102
+ new_schema={
103
+ 'title': 'ClassPropertyMeta',
104
+ 'properties': {
105
+ 'title': {'type': 'string', 'title': 'Title'},
106
+ 'default': {'type': 'anything', 'title': 'Default'},
107
+ 'options': {'type': 'array', 'items': {'type': 'Option'}, 'title': 'Options'},
108
+ },
109
+ 'meta_class': 'TypeMeta',
110
+ },
111
+ ),
112
+ migrations.CreateClass(
113
+ schema_type=SchemaTypes.CORE,
114
+ class_name='ClassProperty',
115
+ new_schema={
116
+ 'title': 'ClassProperty',
117
+ 'required': ['type'],
118
+ 'properties': {
119
+ 'type': {'type': 'string', 'title': 'Type'},
120
+ 'items': {
121
+ 'type': 'dictionary',
122
+ 'items': {'key': {'type': 'string'}, 'value': {'type': 'anything'}},
123
+ 'title': 'Items',
124
+ },
125
+ },
126
+ 'meta_class': 'TypeMeta',
127
+ },
128
+ ),
129
+ migrations.CreateClass(
130
+ schema_type=SchemaTypes.CORE,
131
+ class_name='ClassObject',
132
+ new_schema={
133
+ 'title': 'ClassObject',
134
+ 'properties': {
135
+ 'properties': {
136
+ 'type': 'dictionary',
137
+ 'items': {'key': {'type': 'string'}, 'value': {'type': 'ClassProperty'}},
138
+ 'title': 'Properties',
139
+ },
140
+ 'required': {'type': 'array', 'items': {'type': 'string'}, 'title': 'Required'},
141
+ 'meta_class': {'type': 'string', 'default': 'ClassObject', 'title': 'Meta Class'},
142
+ },
143
+ 'custom_code': '@property # type: ignore[misc]\ndef display_name(self) -> str: # type: ignore[no-untyped-def]\n return self.title',
144
+ },
145
+ ),
146
+ migrations.CreateClass(
147
+ schema_type=SchemaTypes.CORE,
148
+ class_name='ClassObjectMeta',
149
+ new_schema={
150
+ 'title': 'ClassObjectMeta',
151
+ 'required': ['title', 'type'],
152
+ 'properties': {
153
+ 'title': {'type': 'string', 'title': 'Title'},
154
+ 'type': {'type': 'string', 'title': 'Type'},
155
+ 'default': {'type': 'anything', 'title': 'Default'},
156
+ 'properties': {
157
+ 'type': 'dictionary',
158
+ 'items': {'key': {'type': 'string'}, 'value': {'type': 'ClassPropertyMeta'}},
159
+ 'title': 'Properties',
160
+ },
161
+ 'indexed': {'type': 'array', 'items': {'type': 'string'}, 'title': 'Indexed'},
162
+ 'unique': {
163
+ 'type': 'array',
164
+ 'items': {'type': 'array', 'items': {'type': 'string'}},
165
+ 'title': 'Unique Fields',
166
+ },
167
+ 'custom_code': {'type': 'string', 'title': 'Custom Code'},
168
+ },
169
+ },
170
+ ),
171
+ migrations.CreateClass(
172
+ schema_type=SchemaTypes.CORE,
173
+ class_name='Fixture',
174
+ new_schema={
175
+ 'title': 'Fixture',
176
+ 'required': ['data', 'external_id'],
177
+ 'properties': {
178
+ 'class_name': {'type': 'string', 'title': 'Class Name'},
179
+ 'external_id': {'type': 'string', 'title': 'External ID'},
180
+ 'data': {
181
+ 'type': 'dictionary',
182
+ 'items': {'key': {'type': 'string'}, 'value': {'type': 'anything'}},
183
+ 'title': 'Data',
184
+ },
185
+ },
186
+ 'unique_properties': [['external_id']],
187
+ },
188
+ ),
189
+ migrations.CreateClass(
190
+ schema_type=SchemaTypes.CORE,
191
+ class_name='File',
192
+ new_schema={
193
+ 'title': 'File',
194
+ 'required': ['filename', 'data'],
195
+ 'properties': {
196
+ 'filename': {'type': 'string', 'title': 'Filename'},
197
+ 'data': {'type': 'binary', 'title': 'Data'},
198
+ 'size': {'type': 'number', 'title': 'Size'},
199
+ },
200
+ 'custom_code': "def pre_update(self): # type: ignore[no-untyped-def]\n self.size = len(self.data or b'')\n\ndef pre_create(self) -> None: # type: ignore[no-untyped-def]\n self.size = len(self.data or b'')\n\nfrom pathlib import Path\nfrom typing import BinaryIO\n\n\ndef to_file(self, file_or_path: Path | BinaryIO) -> None: # type: ignore[no-untyped-def]\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(self.data) # type: ignore[union-attr]\n else:\n file_or_path.write(self.data)\n file_or_path.seek(0)\n\nfrom pathlib import Path\nfrom typing import BinaryIO\n\n\n@classmethod # type: ignore[misc, no-untyped-def]\ndef from_file(\n cls,\n file_or_path: Path | BinaryIO,\n) -> 'File': # type: ignore[name-defined] # noqa: F821\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\n data = file_or_path.read_bytes()\n filename = file_or_path.name\n else:\n file_or_path.seek(0)\n data = file_or_path.read()\n filename = Path(file_or_path.name).name\n\n return cls(data=data, filename=filename)\n\nimport base64\n\nfrom pydantic import field_validator\n\n\n@field_validator('data') # type: ignore[misc]\n@classmethod\ndef data_base64_decode(cls, v: bytes) -> bytes: # type: ignore[no-untyped-def] # noqa: ARG001\n is_base64: bool = False\n\n try:\n is_base64 = base64.b64encode(base64.b64decode(v)) == v\n except Exception:\n ...\n\n if is_base64:\n return base64.b64decode(v)\n\n return v\n\n@property # type: ignore[misc]\ndef mimetype(self) -> str | None: # type: ignore[no-untyped-def]\n import mimetypes\n\n return mimetypes.guess_type(self.filename)[0]",
201
+ },
202
+ ),
203
+ ]
Binary file
Binary file
Binary file
Binary file
@@ -6,6 +6,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent
6
6
  TYPE_SCHEMAS_PATH: Path = BASE_DIR / 'schemas' / 'types'
7
7
  CORE_SCHEMAS_PATH: Path = BASE_DIR / 'schemas' / 'core'
8
8
 
9
+ CORE_MIGRATIONS_PATH: Path = BASE_DIR / '__migrations__'
10
+
9
11
  # Environment
10
12
  TESTING_ENVIRONMENT = 'testing'
11
13
  DEVELOPMENT_ENVIRONMENT = 'development'
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
  BASE_DIR: Incomplete
5
5
  TYPE_SCHEMAS_PATH: Path
6
6
  CORE_SCHEMAS_PATH: Path
7
+ CORE_MIGRATIONS_PATH: Path
7
8
  TESTING_ENVIRONMENT: str
8
9
  DEVELOPMENT_ENVIRONMENT: str
9
10
  PRODUCTION_ENVIRONMENT: str
amsdal/configs/main.py CHANGED
@@ -35,6 +35,8 @@ class Settings(BaseSettings):
35
35
  """The static module name. The static files will be placed in this module."""
36
36
  TRANSACTIONS_MODULE_NAME: str = 'transactions'
37
37
  """The transactions module name. The transactions will be placed in this module."""
38
+ MIGRATIONS_DIRECTORY_NAME: str = 'migrations'
39
+ """The migrations directory name. The migration files will be placed in this folder."""
38
40
 
39
41
  ACCESS_KEY_ID: str | None = None
40
42
  """The access key that you will get during registering process."""
@@ -85,6 +87,10 @@ class Settings(BaseSettings):
85
87
  def transactions_root_path(self) -> Path:
86
88
  return self.models_root_path / self.TRANSACTIONS_MODULE_NAME
87
89
 
90
+ @property
91
+ def migrations_root_path(self) -> Path:
92
+ return self.models_root_path / self.MIGRATIONS_DIRECTORY_NAME
93
+
88
94
  @model_validator(mode='after')
89
95
  def check_passwords_match(self) -> 'Settings':
90
96
  config_path = self.CONFIG_PATH
amsdal/configs/main.pyi CHANGED
@@ -12,6 +12,7 @@ class Settings(BaseSettings):
12
12
  FIXTURES_MODULE_NAME: str
13
13
  STATIC_MODULE_NAME: str
14
14
  TRANSACTIONS_MODULE_NAME: str
15
+ MIGRATIONS_DIRECTORY_NAME: str
15
16
  ACCESS_KEY_ID: str | None
16
17
  SECRET_ACCESS_KEY: str | None
17
18
  ACCESS_TOKEN: str | None
@@ -28,6 +29,8 @@ class Settings(BaseSettings):
28
29
  def static_root_path(self) -> Path: ...
29
30
  @property
30
31
  def transactions_root_path(self) -> Path: ...
32
+ @property
33
+ def migrations_root_path(self) -> Path: ...
31
34
  def check_passwords_match(self) -> Settings: ...
32
35
 
33
36
  base: TypeAlias
Binary file
@@ -0,0 +1,49 @@
1
+ from amsdal_utils.models.enums import SchemaTypes
2
+
3
+ from amsdal.migration import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ operations: list[migrations.Operation] = [
8
+ migrations.CreateClass(
9
+ schema_type=SchemaTypes.CONTRIB,
10
+ class_name='Permission',
11
+ new_schema={
12
+ 'title': 'Permission',
13
+ 'required': ['model', 'action'],
14
+ 'properties': {
15
+ 'model': {'type': 'string', 'title': 'Model'},
16
+ 'action': {'type': 'string', 'title': 'Action'},
17
+ },
18
+ '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
+ ),
21
+ migrations.CreateClass(
22
+ schema_type=SchemaTypes.CONTRIB,
23
+ class_name='User',
24
+ new_schema={
25
+ 'title': 'User',
26
+ 'required': ['email', 'password'],
27
+ 'properties': {
28
+ 'email': {'type': 'string', 'title': 'Email'},
29
+ 'password': {'type': 'binary', 'title': 'Password (hash)'},
30
+ 'permissions': {'type': 'array', 'items': {'type': 'Permission'}, 'title': 'Permissions'},
31
+ },
32
+ '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
+ },
34
+ ),
35
+ migrations.CreateClass(
36
+ schema_type=SchemaTypes.CONTRIB,
37
+ class_name='LoginSession',
38
+ new_schema={
39
+ 'title': 'LoginSession',
40
+ 'required': ['email', 'password'],
41
+ 'properties': {
42
+ 'email': {'type': 'string', 'title': 'Email'},
43
+ 'password': {'type': 'string', 'title': 'Password (hash)'},
44
+ 'token': {'type': 'string', 'title': 'Token', 'mark_as_read_only': True},
45
+ },
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",
47
+ },
48
+ ),
49
+ ]