zrb 1.0.0b8__py3-none-any.whl → 1.0.0b10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. zrb/__main__.py +3 -0
  2. zrb/builtin/project/add/fastapp/fastapp_task.py +1 -0
  3. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.coveragerc +11 -0
  4. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.gitignore +4 -0
  5. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_task.py +4 -4
  6. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -0
  7. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +108 -1
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +67 -4
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service.py +5 -5
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +1 -0
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_create_my_entity.py +53 -0
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_delete_my_entity.py +62 -0
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_read_my_entity.py +65 -0
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/test/my_module/my_entity/test_update_my_entity.py +61 -0
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +57 -13
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +8 -0
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +2 -2
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +6 -1
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +10 -6
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +65 -14
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task_util.py +106 -0
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +6 -86
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +27 -11
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +140 -51
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +15 -0
  26. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +1 -1
  27. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +22 -4
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +21 -0
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +106 -61
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/8ed025bcc845_create_permissions.py +69 -0
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +3 -4
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +15 -14
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +4 -4
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +24 -5
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +14 -12
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +134 -97
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +28 -11
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +215 -13
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +30 -2
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +216 -41
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/auth.py +57 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +7 -1
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +2 -0
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +13 -12
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +64 -12
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/_util/access_token.py +19 -0
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_create_permission.py +59 -0
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_delete_permission.py +68 -0
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_read_permission.py +71 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_update_permission.py +66 -0
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/test_user_session.py +195 -0
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_health_and_readiness.py +28 -0
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_homepage.py +17 -0
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_not_found_error.py +16 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test.sh +7 -0
  56. zrb/task/base_task.py +10 -10
  57. zrb/task/cmd_task.py +2 -5
  58. zrb/util/cmd/command.py +39 -48
  59. zrb/util/codemod/modification_mode.py +3 -0
  60. zrb/util/codemod/modify_class.py +58 -0
  61. zrb/util/codemod/modify_class_parent.py +68 -0
  62. zrb/util/codemod/modify_class_property.py +128 -0
  63. zrb/util/codemod/modify_dict.py +75 -0
  64. zrb/util/codemod/modify_function.py +65 -0
  65. zrb/util/codemod/modify_function_call.py +68 -0
  66. zrb/util/codemod/modify_method.py +88 -0
  67. zrb/util/codemod/{prepend_code_to_module.py → modify_module.py} +2 -3
  68. zrb/util/file.py +3 -2
  69. {zrb-1.0.0b8.dist-info → zrb-1.0.0b10.dist-info}/METADATA +2 -1
  70. {zrb-1.0.0b8.dist-info → zrb-1.0.0b10.dist-info}/RECORD +72 -55
  71. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/migrate.py +0 -3
  72. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +0 -48
  73. zrb/util/codemod/append_code_to_class.py +0 -35
  74. zrb/util/codemod/append_code_to_function.py +0 -38
  75. zrb/util/codemod/append_code_to_method.py +0 -55
  76. zrb/util/codemod/append_key_to_dict.py +0 -51
  77. zrb/util/codemod/append_param_to_function_call.py +0 -39
  78. zrb/util/codemod/prepend_parent_to_class.py +0 -38
  79. zrb/util/codemod/prepend_property_to_class.py +0 -55
  80. {zrb-1.0.0b8.dist-info → zrb-1.0.0b10.dist-info}/WHEEL +0 -0
  81. {zrb-1.0.0b8.dist-info → zrb-1.0.0b10.dist-info}/entry_points.txt +0 -0
@@ -2,10 +2,10 @@ import inspect
2
2
  from enum import Enum
3
3
  from functools import partial
4
4
  from logging import Logger
5
- from typing import Any, Callable, Sequence
5
+ from typing import Any, Callable, Union, get_args, get_origin
6
6
 
7
7
  import httpx
8
- from fastapi import APIRouter, Depends, params
8
+ from fastapi import APIRouter, Depends
9
9
  from my_app_name.common.error import ClientAPIError
10
10
  from pydantic import BaseModel
11
11
 
@@ -56,7 +56,6 @@ class BaseService:
56
56
  response_model: Any = None,
57
57
  status_code: int | None = None,
58
58
  tags: list[str | Enum] | None = None,
59
- dependencies: Sequence[params.Depends] | None = None,
60
59
  summary: str | None = None,
61
60
  description: str = None,
62
61
  deprecated: bool | None = None,
@@ -160,56 +159,24 @@ def _create_direct_client_method(logger: Logger, func: Callable, service: BaseSe
160
159
  return client_method
161
160
 
162
161
 
163
- def _create_api_client_method(logger: Logger, param: RouteParam, base_url: str):
162
+ def _create_api_client_method(logger: Logger, route_param: RouteParam, base_url: str):
164
163
  async def client_method(*args, **kwargs):
165
- url = base_url + param.path
166
- method = (
167
- param.methods[0].lower()
168
- if isinstance(param.methods, list)
169
- else param.methods.lower()
164
+ url = base_url + route_param.path
165
+ method = _get_api_client_method(route_param)
166
+ body_param_names = _get_api_client_body_param_names(route_param, method)
167
+ path_params, query_params, body_params = _create_api_client_request_params(
168
+ route_param, body_param_names, args, kwargs
170
169
  )
171
- # Get the signature of the original function
172
- sig = inspect.signature(param.func)
173
- # Bind the arguments to the signature
174
- bound_args = sig.bind(*args, **kwargs)
175
- bound_args.apply_defaults()
176
- # Analyze parameters
177
- params = list(sig.parameters.values())
178
- body_params = [
179
- p
180
- for p in params
181
- if p.name != "self" and p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
182
- ]
183
- # Prepare the request
184
- path_params = {}
185
- query_params = {}
186
- body = {}
187
- for name, value in bound_args.arguments.items():
188
- if name == "self":
189
- continue
190
- if f"{{{name}}}" in param.path:
191
- path_params[name] = value
192
- elif isinstance(value, BaseModel):
193
- body = _parse_api_param(value)
194
- elif method in ["get", "delete"]:
195
- query_params[name] = _parse_api_param(value)
196
- elif len(body_params) == 1 and name == body_params[0].name:
197
- # If there's only one body parameter, use its value directly
198
- body = _parse_api_param(value)
199
- else:
200
- body[name] = _parse_api_param(value)
201
170
  # Format the URL with path parameters
202
171
  url = url.format(**path_params)
172
+ json_body_params = None if method == "get" else body_params
203
173
  logger.info(
204
- f"Sending request to {url} with method {method}, json={body}, params={query_params}" # noqa
174
+ f"Sending request to {url} with method {method}, json={json_body_params}, params={query_params}" # noqa
205
175
  )
206
176
  async with httpx.AsyncClient() as client:
207
- if method in ["get", "delete"]:
208
- response = await getattr(client, method)(url, params=query_params)
209
- else:
210
- response = await getattr(client, method)(
211
- url, json=body, params=query_params
212
- )
177
+ response = await client.request(
178
+ method=method, url=url, params=query_params, json=json_body_params
179
+ )
213
180
  logger.info(
214
181
  f"Received response: status={response.status_code}, content={response.content}"
215
182
  )
@@ -220,17 +187,139 @@ def _create_api_client_method(logger: Logger, param: RouteParam, base_url: str):
220
187
  else response.text
221
188
  )
222
189
  raise ClientAPIError(response.status_code, error_detail)
223
- return response.json()
190
+ return _parse_api_client_response(logger, route_param, response)
224
191
 
225
192
  return client_method
226
193
 
227
194
 
228
- def _parse_api_param(data: Any) -> Any:
195
+ def _parse_api_client_response(
196
+ logger: Logger, route_param: RouteParam, response: Any
197
+ ) -> Any:
198
+ sig = inspect.signature(route_param.func)
199
+ try:
200
+ response_data = response.json()
201
+ except Exception:
202
+ logger.warning("Failed to parse JSON")
203
+ return None
204
+ return_annotation = sig.return_annotation # e.g., list[User]
205
+ if return_annotation is inspect.Signature.empty:
206
+ logger.warning("No return annotation detected, return value as is")
207
+ return response_data # No return type specified, return raw JSON
208
+ origin = get_origin(return_annotation) # e.g., list
209
+ args = get_args(return_annotation) # e.g., (User,)
210
+ try:
211
+ if origin is None: # Not a generic type, so check it directly
212
+ if inspect.isclass(return_annotation) and issubclass(
213
+ return_annotation, BaseModel
214
+ ):
215
+ if response_data:
216
+ return return_annotation.model_validate(response_data)
217
+ return None
218
+ elif origin in {list, set, tuple} and args:
219
+ model_type = args[0]
220
+ if inspect.isclass(model_type) and issubclass(model_type, BaseModel):
221
+ if isinstance(response_data, list):
222
+ return [model_type.model_validate(item) for item in response_data]
223
+ elif isinstance(response_data, tuple):
224
+ return tuple(
225
+ model_type.model_validate(item) for item in response_data
226
+ )
227
+ elif isinstance(response_data, set):
228
+ return {model_type.model_validate(item) for item in response_data}
229
+ return None
230
+ elif origin is Union and len(args) == 2 and type(None) in args:
231
+ model_type = next(
232
+ (
233
+ arg
234
+ for arg in args
235
+ if inspect.isclass(arg) and issubclass(arg, BaseModel)
236
+ ),
237
+ None,
238
+ )
239
+ if response_data and model_type:
240
+ return model_type.model_validate(response_data)
241
+ return None
242
+ elif origin is dict and len(args) == 2:
243
+ key_type, value_type = args
244
+ if inspect.isclass(value_type) and issubclass(value_type, BaseModel):
245
+ if inspect(response_data, dict):
246
+ return {
247
+ k: value_type.model_validate(v)
248
+ for k, v in response_data.items()
249
+ }
250
+ return None
251
+ return response_data
252
+ except Exception:
253
+ logger.warning(
254
+ "Return annotation detected, but parsing error, return value as is"
255
+ )
256
+ return response_data
257
+
258
+
259
+ def _create_api_client_request_params(
260
+ route_param: RouteParam,
261
+ body_param_names: list[str],
262
+ args: list[Any],
263
+ kwargs: dict[str, Any],
264
+ ) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
265
+ # Get the signature of the original function
266
+ sig = inspect.signature(route_param.func)
267
+ # Bind the arguments to the signature
268
+ bound_args = sig.bind(*args, **kwargs)
269
+ bound_args.apply_defaults()
270
+ # Prepare the request
271
+ path_params = {}
272
+ query_params = {}
273
+ body_params = {}
274
+ for name, value in bound_args.arguments.items():
275
+ if name == "self":
276
+ continue
277
+ if f"{{{name}}}" in route_param.path:
278
+ path_params[name] = value
279
+ elif name not in body_param_names:
280
+ query_params[name] = _parse_api_client_param(value)
281
+ elif len(body_param_names) == 1 and name == body_param_names[0]:
282
+ # If there's only one body parameter, use its value directly
283
+ body_params = _parse_api_client_param(value)
284
+ else:
285
+ body_params[name] = _parse_api_client_param(value)
286
+ return path_params, query_params, body_params
287
+
288
+
289
+ def _parse_api_client_param(data: Any) -> Any:
229
290
  if isinstance(data, BaseModel):
230
291
  return data.model_dump()
231
- elif isinstance(data, list):
232
- return [_parse_api_param(item) for item in data]
233
292
  elif isinstance(data, dict):
234
- return {key: _parse_api_param(value) for key, value in data.items()}
293
+ return {key: _parse_api_client_param(value) for key, value in data.items()}
294
+ elif isinstance(data, list):
295
+ return [_parse_api_client_param(item) for item in data]
296
+ elif isinstance(data, tuple):
297
+ return tuple(_parse_api_client_param(item) for item in data)
298
+ elif isinstance(data, set):
299
+ return {_parse_api_client_param(item) for item in data}
235
300
  else:
236
301
  return data
302
+
303
+
304
+ def _get_api_client_method(route_param: RouteParam) -> str:
305
+ if isinstance(route_param.methods, list):
306
+ return route_param.methods[0].lower()
307
+ return route_param.methods.lower()
308
+
309
+
310
+ def _get_api_client_body_param_names(route_param: RouteParam, method: str):
311
+ sig = inspect.signature(route_param.func)
312
+ function_params = list(sig.parameters.values())
313
+ return [
314
+ p.name
315
+ for p in function_params
316
+ if (
317
+ p.name != "self"
318
+ and f"{{{p.name}}}" not in route_param.path
319
+ and p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD
320
+ and (
321
+ method not in ["get", "delete"]
322
+ or (method == "delete" and p.annotation not in [str, float, bool])
323
+ )
324
+ )
325
+ ]
@@ -8,11 +8,26 @@ class NotFoundError(HTTPException):
8
8
  super().__init__(404, {"message": message}, headers)
9
9
 
10
10
 
11
+ class ForbiddenError(HTTPException):
12
+ def __init__(self, message: str, headers: Dict[str, str] | None = None) -> None:
13
+ super().__init__(403, {"message": message}, headers)
14
+
15
+
16
+ class UnauthorizedError(HTTPException):
17
+ def __init__(self, message: str, headers: Dict[str, str] | None = None) -> None:
18
+ super().__init__(401, {"message": message}, headers)
19
+
20
+
11
21
  class InvalidValueError(HTTPException):
12
22
  def __init__(self, message: str, headers: Dict[str, str] | None = None) -> None:
13
23
  super().__init__(422, {"message": message}, headers)
14
24
 
15
25
 
26
+ class InternalServerError(HTTPException):
27
+ def __init__(self, message: str, headers: Dict[str, str] | None = None) -> None:
28
+ super().__init__(500, {"message": message}, headers)
29
+
30
+
16
31
  class ClientAPIError(HTTPException):
17
32
  def __init__(
18
33
  self, status_code: int, message: str, headers: Dict[str, str] | None = None
@@ -45,7 +45,7 @@ def create_default_filter_param_parser() -> (
45
45
  Callable[[SQLModel, str], list[ClauseElement]]
46
46
  ):
47
47
  def parse_filter_param(model: SQLModel, query: str) -> list[ClauseElement]:
48
- """
48
+ r"""
49
49
  Parse the filter parameter and return a list of SQLAlchemy ClauseElement objects.
50
50
 
51
51
  Args:
@@ -1,5 +1,8 @@
1
1
  import os
2
2
 
3
+ TRUE_STRS = ["true", "1", "yes", "y", "active", "on"]
4
+ FALSE_STRS = ["false", "0", "no", "n", "inactive", "off"]
5
+
3
6
  APP_PATH = os.path.dirname(__file__)
4
7
  APP_VERSION = "0.1.0"
5
8
 
@@ -51,16 +54,31 @@ APP_AUTH_SUPER_USER_PASSWORD = os.getenv(
51
54
  "MY_APP_NAME_AUTH_SUPER_USER_PASSWORD", "my-secure-password"
52
55
  )
53
56
  APP_AUTH_GUEST_USER = os.getenv("MY_APP_NAME_AUTH_GUEST_USER", "user")
54
- APP_AUTH_GUEST_USER_PERMISSIONS = (
57
+ APP_AUTH_GUEST_USER_PERMISSIONS = [
55
58
  permission_name.strip()
56
59
  for permission_name in os.getenv(
57
60
  "MY_APP_NAME_AUTH_GUEST_USER_PERMISSIONS", ""
58
61
  ).split(",")
59
62
  if permission_name.strip() != ""
63
+ ]
64
+ APP_AUTH_MAX_PARALLEL_SESSION = int(
65
+ os.getenv("MY_APP_NAME_AUTH_MAX_PARALLEL_SESSION", "1")
66
+ )
67
+ APP_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES = int(
68
+ os.getenv("MY_APP_NAME_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES", "30")
69
+ )
70
+ APP_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES = int(
71
+ os.getenv("MY_APP_NAME_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES", "1440")
72
+ )
73
+ APP_AUTH_ACCESS_TOKEN_COOKIE_NAME = os.getenv(
74
+ "MY_APP_NAME_AUTH_ACCESS_TOKEN_COOKIE_NAME", "access_token"
75
+ )
76
+ APP_AUTH_REFRESH_TOKEN_COOKIE_NAME = os.getenv(
77
+ "MY_APP_NAME_AUTH_REFRESH_TOKEN_COOKIE_NAME", "refresh_token"
60
78
  )
61
- APP_MAX_PARALLEL_SESSION = int(os.getenv("MY_APP_NAME_MAX_PARALLEL_SESSION", "1"))
62
- APP_SESSION_EXPIRE_MINUTES = int(
63
- os.getenv("MY_APP_NAME_SESSION_EXPIRE_MINUTES", "1440")
79
+ APP_AUTH_SECRET_KEY = os.getenv("MY_APP_NAME_AUTH_SECRET_KEY", "my-secret-key")
80
+ APP_AUTH_PRIORITIZE_NEW_SESSION = (
81
+ os.getenv("MY_APP_NAME_AUTH_PRIORITIZE_NEW_SESSION", "1").lower() in TRUE_STRS
64
82
  )
65
83
 
66
84
  APP_AUTH_BASE_URL = os.getenv("MY_APP_NAME_AUTH_BASE_URL", "http://localhost:3001")
@@ -13,15 +13,36 @@ from my_app_name.schema.role import (
13
13
  RoleUpdateWithPermissionsAndAudit,
14
14
  )
15
15
  from my_app_name.schema.user import (
16
+ AuthUserResponse,
16
17
  MultipleUserResponse,
17
18
  UserCreateWithRolesAndAudit,
19
+ UserCredentials,
18
20
  UserResponse,
21
+ UserSessionResponse,
19
22
  UserUpdateWithRolesAndAudit,
20
23
  )
21
24
 
22
25
 
23
26
  class AuthClient(ABC):
24
27
 
28
+ @abstractmethod
29
+ async def get_current_user(self, access_token: str) -> AuthUserResponse:
30
+ """Get current user based on access token"""
31
+
32
+ @abstractmethod
33
+ async def create_user_session(
34
+ self, credential: UserCredentials
35
+ ) -> UserSessionResponse:
36
+ """Create new user session"""
37
+
38
+ @abstractmethod
39
+ async def update_user_session(self, refresh_token: str) -> UserSessionResponse:
40
+ """Update user session"""
41
+
42
+ @abstractmethod
43
+ async def delete_user_session(self, refresh_token: str) -> UserSessionResponse:
44
+ """Delete user session"""
45
+
25
46
  # Permission related methods
26
47
 
27
48
  @abstractmethod
@@ -22,7 +22,7 @@ depends_on: Union[str, Sequence[str], None] = None
22
22
  def upgrade() -> None:
23
23
  # ### commands auto generated by Alembic - please adjust! ###
24
24
  op.create_table(
25
- "permission",
25
+ "permissions",
26
26
  sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
27
27
  sa.Column("created_at", sa.DateTime(), nullable=True),
28
28
  sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
@@ -32,22 +32,22 @@ def upgrade() -> None:
32
32
  sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
33
33
  sa.PrimaryKeyConstraint("id"),
34
34
  )
35
- op.create_index(op.f("ix_permission_name"), "permission", ["name"], unique=True)
35
+ op.create_index(op.f("ix_permissions_name"), "permissions", ["name"], unique=True)
36
36
  op.create_index(
37
- op.f("ix_permission_created_at"), "permission", ["created_at"], unique=False
37
+ op.f("ix_permissions_created_at"), "permissions", ["created_at"], unique=False
38
38
  )
39
39
  op.create_index(
40
- op.f("ix_permission_created_by"), "permission", ["created_by"], unique=False
40
+ op.f("ix_permissions_created_by"), "permissions", ["created_by"], unique=False
41
41
  )
42
42
  op.create_index(
43
- op.f("ix_permission_updated_at"), "permission", ["updated_at"], unique=False
43
+ op.f("ix_permissions_updated_at"), "permissions", ["updated_at"], unique=False
44
44
  )
45
45
  op.create_index(
46
- op.f("ix_permission_updated_by"), "permission", ["updated_by"], unique=False
46
+ op.f("ix_permissions_updated_by"), "permissions", ["updated_by"], unique=False
47
47
  )
48
48
 
49
49
  op.create_table(
50
- "role",
50
+ "roles",
51
51
  sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
52
52
  sa.Column("created_at", sa.DateTime(), nullable=True),
53
53
  sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
@@ -57,14 +57,14 @@ def upgrade() -> None:
57
57
  sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
58
58
  sa.PrimaryKeyConstraint("id"),
59
59
  )
60
- op.create_index(op.f("ix_role_name"), "role", ["name"], unique=True)
61
- op.create_index(op.f("ix_role_created_at"), "role", ["created_at"], unique=False)
62
- op.create_index(op.f("ix_role_created_by"), "role", ["created_by"], unique=False)
63
- op.create_index(op.f("ix_role_updated_at"), "role", ["updated_at"], unique=False)
64
- op.create_index(op.f("ix_role_updated_by"), "role", ["updated_by"], unique=False)
60
+ op.create_index(op.f("ix_roles_name"), "roles", ["name"], unique=True)
61
+ op.create_index(op.f("ix_roles_created_at"), "roles", ["created_at"], unique=False)
62
+ op.create_index(op.f("ix_roles_created_by"), "roles", ["created_by"], unique=False)
63
+ op.create_index(op.f("ix_roles_updated_at"), "roles", ["updated_at"], unique=False)
64
+ op.create_index(op.f("ix_roles_updated_by"), "roles", ["updated_by"], unique=False)
65
65
 
66
66
  op.create_table(
67
- "rolepermission",
67
+ "role_permissions",
68
68
  sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
69
69
  sa.Column("role_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
70
70
  sa.Column("permission_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
@@ -73,34 +73,39 @@ def upgrade() -> None:
73
73
  sa.PrimaryKeyConstraint("id"),
74
74
  )
75
75
  op.create_index(
76
- op.f("ix_rolepermission_permission_id"),
77
- "rolepermission",
76
+ op.f("ix_role_permissions_permission_id"),
77
+ "role_permissions",
78
78
  ["permission_id"],
79
79
  unique=False,
80
80
  )
81
81
  op.create_index(
82
- op.f("ix_rolepermission_role_id"), "rolepermission", ["role_id"], unique=False
82
+ op.f("ix_role_permissions_role_id"),
83
+ "role_permissions",
84
+ ["role_id"],
85
+ unique=False,
83
86
  )
84
87
 
85
88
  op.create_table(
86
- "user",
89
+ "users",
87
90
  sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
88
91
  sa.Column("username", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
89
92
  sa.Column("password", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
93
+ sa.Column("active", sa.Boolean(), nullable=False),
90
94
  sa.Column("created_at", sa.DateTime(), nullable=False),
91
95
  sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
92
96
  sa.Column("updated_at", sa.DateTime(), nullable=True),
93
97
  sa.Column("updated_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
94
98
  sa.PrimaryKeyConstraint("id"),
95
99
  )
96
- op.create_index(op.f("ix_user_username"), "user", ["username"], unique=True)
97
- op.create_index(op.f("ix_user_created_at"), "user", ["created_at"], unique=False)
98
- op.create_index(op.f("ix_user_created_by"), "user", ["created_by"], unique=False)
99
- op.create_index(op.f("ix_user_updated_at"), "user", ["updated_at"], unique=False)
100
- op.create_index(op.f("ix_user_updated_by"), "user", ["updated_by"], unique=False)
100
+ op.create_index(op.f("ix_users_username"), "users", ["username"], unique=True)
101
+ op.create_index(op.f("ix_users_active"), "users", ["active"], unique=False)
102
+ op.create_index(op.f("ix_users_created_at"), "users", ["created_at"], unique=False)
103
+ op.create_index(op.f("ix_users_created_by"), "users", ["created_by"], unique=False)
104
+ op.create_index(op.f("ix_users_updated_at"), "users", ["updated_at"], unique=False)
105
+ op.create_index(op.f("ix_users_updated_by"), "users", ["updated_by"], unique=False)
101
106
 
102
107
  op.create_table(
103
- "userrole",
108
+ "user_roles",
104
109
  sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
105
110
  sa.Column("user_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
106
111
  sa.Column("role_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
@@ -108,53 +113,93 @@ def upgrade() -> None:
108
113
  sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
109
114
  sa.PrimaryKeyConstraint("id"),
110
115
  )
111
- op.create_index(op.f("ix_userrole_role_id"), "userrole", ["role_id"], unique=False)
112
- op.create_index(op.f("ix_userrole_user_id"), "userrole", ["user_id"], unique=False)
116
+ op.create_index(
117
+ op.f("ix_user_roles_role_id"), "user_roles", ["role_id"], unique=False
118
+ )
119
+ op.create_index(
120
+ op.f("ix_user_roles_user_id"), "user_roles", ["user_id"], unique=False
121
+ )
113
122
 
114
123
  op.create_table(
115
- "session",
124
+ "user_sessions",
116
125
  sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
117
126
  sa.Column("user_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
118
- sa.Column("token", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
127
+ sa.Column("access_token", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
128
+ sa.Column("refresh_token", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
129
+ sa.Column("access_token_expired_at", sa.DateTime(), nullable=False),
130
+ sa.Column("refresh_token_expired_at", sa.DateTime(), nullable=False),
119
131
  sa.PrimaryKeyConstraint("id"),
120
132
  )
121
- op.create_index(op.f("ix_session_user_id"), "session", ["user_id"], unique=False)
122
- op.create_index(op.f("ix_session_token"), "session", ["token"], unique=True)
133
+ op.create_index(
134
+ op.f("ix_user_sessions_user_id"), "user_sessions", ["user_id"], unique=False
135
+ )
136
+ op.create_index(
137
+ op.f("ix_user_sessions_access_token"),
138
+ "user_sessions",
139
+ ["access_token"],
140
+ unique=False,
141
+ )
142
+ op.create_index(
143
+ op.f("ix_user_sessions_refresh_token"),
144
+ "user_sessions",
145
+ ["refresh_token"],
146
+ unique=False,
147
+ )
148
+ op.create_index(
149
+ op.f("ix_user_sessions_access_token_expired_at"),
150
+ "user_sessions",
151
+ ["access_token_expired_at"],
152
+ )
153
+ op.create_index(
154
+ op.f("ix_user_sessions_refresh_token_expired_at"),
155
+ "user_sessions",
156
+ ["refresh_token_expired_at"],
157
+ )
123
158
  # ### end Alembic commands ###
124
159
 
125
160
 
126
161
  def downgrade() -> None:
127
162
  # ### commands auto generated by Alembic - please adjust! ###
128
- op.drop_index(op.f("ix_session_token"), table_name="session")
129
- op.drop_index(op.f("ix_session_user_id"), table_name="session")
130
- op.drop_table("session")
131
-
132
- op.drop_index(op.f("ix_userrole_user_id"), table_name="userrole")
133
- op.drop_index(op.f("ix_userrole_role_id"), table_name="userrole")
134
- op.drop_table("userrole")
135
-
136
- op.drop_index(op.f("ix_user_username"), table_name="user")
137
- op.drop_index(op.f("ix_user_updated_by"), table_name="user")
138
- op.drop_index(op.f("ix_user_updated_at"), table_name="user")
139
- op.drop_index(op.f("ix_user_created_by"), table_name="user")
140
- op.drop_index(op.f("ix_user_created_at"), table_name="user")
141
- op.drop_table("user")
142
-
143
- op.drop_index(op.f("ix_rolepermission_role_id"), table_name="rolepermission")
144
- op.drop_index(op.f("ix_rolepermission_permission_id"), table_name="rolepermission")
145
- op.drop_table("rolepermission")
146
-
147
- op.drop_index(op.f("ix_role_name"), table_name="role")
148
- op.drop_index(op.f("ix_role_updated_by"), table_name="role")
149
- op.drop_index(op.f("ix_role_updated_at"), table_name="role")
150
- op.drop_index(op.f("ix_role_created_by"), table_name="role")
151
- op.drop_index(op.f("ix_role_created_at"), table_name="role")
152
- op.drop_table("role")
153
-
154
- op.drop_index(op.f("ix_permission_updated_by"), table_name="permission")
155
- op.drop_index(op.f("ix_permission_updated_at"), table_name="permission")
156
- op.drop_index(op.f("ix_permission_created_by"), table_name="permission")
157
- op.drop_index(op.f("ix_permission_created_at"), table_name="permission")
158
- op.drop_index(op.f("ix_permission_name"), table_name="permission")
159
- op.drop_table("permission")
163
+ op.drop_index(op.f("ix_user_sessions_user_id"), table_name="user_sessions")
164
+ op.drop_index(op.f("ix_user_sessions_access_token"), table_name="user_sessions")
165
+ op.drop_index(op.f("ix_user_sessions_refresh_token"), table_name="user_sessions")
166
+ op.drop_index(
167
+ op.f("ix_user_sessions_access_token_expired_at"), table_name="user_sessions"
168
+ )
169
+ op.drop_index(
170
+ op.f("ix_user_sessions_refresh_token_expired_at"), table_name="user_sessions"
171
+ )
172
+ op.drop_table("user_sessions")
173
+
174
+ op.drop_index(op.f("ix_user_roles_user_id"), table_name="user_roles")
175
+ op.drop_index(op.f("ix_user_roles_role_id"), table_name="user_roles")
176
+ op.drop_table("user_roles")
177
+
178
+ op.drop_index(op.f("ix_users_username"), table_name="users")
179
+ op.drop_index(op.f("ix_users_active"), table_name="users")
180
+ op.drop_index(op.f("ix_users_updated_by"), table_name="users")
181
+ op.drop_index(op.f("ix_users_updated_at"), table_name="users")
182
+ op.drop_index(op.f("ix_users_created_by"), table_name="users")
183
+ op.drop_index(op.f("ix_users_created_at"), table_name="users")
184
+ op.drop_table("users")
185
+
186
+ op.drop_index(op.f("ix_role_permissions_role_id"), table_name="role_permissions")
187
+ op.drop_index(
188
+ op.f("ix_role_permissions_permission_id"), table_name="role_permissions"
189
+ )
190
+ op.drop_table("role_permissions")
191
+
192
+ op.drop_index(op.f("ix_roles_name"), table_name="roles")
193
+ op.drop_index(op.f("ix_roles_updated_by"), table_name="roles")
194
+ op.drop_index(op.f("ix_roles_updated_at"), table_name="roles")
195
+ op.drop_index(op.f("ix_roles_created_by"), table_name="roles")
196
+ op.drop_index(op.f("ix_roles_created_at"), table_name="roles")
197
+ op.drop_table("roles")
198
+
199
+ op.drop_index(op.f("ix_permissions_updated_by"), table_name="permissions")
200
+ op.drop_index(op.f("ix_permissions_updated_at"), table_name="permissions")
201
+ op.drop_index(op.f("ix_permissions_created_by"), table_name="permissions")
202
+ op.drop_index(op.f("ix_permissions_created_at"), table_name="permissions")
203
+ op.drop_index(op.f("ix_permissions_name"), table_name="permissions")
204
+ op.drop_table("permissions")
160
205
  # ### end Alembic commands ###
@@ -0,0 +1,69 @@
1
+ """create_permissions
2
+
3
+ Revision ID: 8ed025bcc845
4
+ Revises: 3093c7336477
5
+ Create Date: 2025-02-08 19:09:14.536559
6
+
7
+ """
8
+
9
+ from typing import Sequence, Union
10
+
11
+ import sqlalchemy as sa
12
+ import sqlmodel # 🔥 FastApp Modification
13
+ from alembic import op
14
+ from module.auth.migration_metadata import metadata
15
+
16
+ # revision identifiers, used by Alembic.
17
+ revision: str = "8ed025bcc845"
18
+ down_revision: Union[str, None] = "3093c7336477"
19
+ branch_labels: Union[str, Sequence[str], None] = None
20
+ depends_on: Union[str, Sequence[str], None] = None
21
+
22
+
23
+ def upgrade() -> None:
24
+ op.bulk_insert(
25
+ metadata.tables["permissions"],
26
+ [
27
+ # permission
28
+ {"name": "permission:create", "description": "create permission"},
29
+ {"name": "permission:read", "description": "read permission"},
30
+ {"name": "permission:update", "description": "update permission"},
31
+ {"name": "permission:delete", "description": "delete permission"},
32
+ # role
33
+ {"name": "role:create", "description": "create role"},
34
+ {"name": "role:read", "description": "read role"},
35
+ {"name": "role:update", "description": "update role"},
36
+ {"name": "role:delete", "description": "delete role"},
37
+ # user
38
+ {"name": "user:create", "description": "create user"},
39
+ {"name": "user:read", "description": "read user"},
40
+ {"name": "user:update", "description": "update user"},
41
+ {"name": "user:delete", "description": "delete user"},
42
+ ],
43
+ )
44
+ # ### end Alembic commands ###
45
+
46
+
47
+ def downgrade() -> None:
48
+ op.execute(
49
+ sa.delete(metadata.tables["permissions"]).where(
50
+ metadata.tables["permissions"].c.name.in_(
51
+ # user
52
+ "user:create",
53
+ "user:read",
54
+ "user:update",
55
+ "user:delete",
56
+ # role
57
+ "role:create",
58
+ "role:read",
59
+ "role:update",
60
+ "role:delete",
61
+ # permission
62
+ "permission:create",
63
+ "permission:read",
64
+ "permission:update",
65
+ "permission:delete",
66
+ )
67
+ )
68
+ )
69
+ # ### end Alembic commands ###