zrb 1.0.0b1__py3-none-any.whl → 1.0.0b2__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 (90) hide show
  1. zrb/__main__.py +0 -3
  2. zrb/builtin/__init__.py +3 -0
  3. zrb/builtin/group.py +1 -0
  4. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +1 -1
  5. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +66 -21
  6. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +67 -41
  7. 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 +69 -15
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_service_factory.py +2 -1
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_db_repository.py +0 -10
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_repository.py +37 -16
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/my_entity_repository_factory.py +2 -2
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +63 -28
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +1 -0
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_api_client.py +6 -0
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/{any_client.py → my_module_client.py} +1 -1
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_client_factory.py +11 -0
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/my_module_direct_client.py +5 -0
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +1 -1
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +4 -4
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +185 -101
  26. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +99 -108
  27. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +1 -1
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +163 -0
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +5 -1
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +75 -0
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +59 -0
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +105 -0
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +42 -13
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +38 -17
  57. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
  58. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +69 -17
  59. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +2 -1
  60. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +1 -1
  61. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +198 -28
  62. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +1 -1
  63. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -1
  64. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
  65. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +50 -4
  66. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +52 -0
  67. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +30 -5
  68. zrb/builtin/random.py +61 -0
  69. zrb/cmd/cmd_val.py +6 -5
  70. zrb/runner/cli.py +10 -1
  71. zrb/runner/web_util/token.py +7 -3
  72. zrb/task/base_task.py +24 -2
  73. zrb/task/cmd_task.py +7 -5
  74. zrb/util/cmd/command.py +1 -0
  75. zrb/util/file.py +7 -1
  76. {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/METADATA +1 -1
  77. {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/RECORD +80 -61
  78. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
  79. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
  80. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -5
  81. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
  82. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -57
  83. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
  84. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
  85. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
  86. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
  87. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  88. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{view.py → util/view.py} +0 -0
  89. {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/WHEEL +0 -0
  90. {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,47 @@
1
+ import os
2
+ from contextlib import asynccontextmanager
3
+
4
+ from fastapi import FastAPI, HTTPException
5
+ from fastapi.openapi.docs import get_swagger_ui_html
6
+ from fastapi.responses import FileResponse
7
+ from fastapi.staticfiles import StaticFiles
8
+ from sqlalchemy.engine import Engine
9
+ from sqlmodel import SQLModel
10
+ from starlette.types import Lifespan
11
+
12
+
13
+ def get_default_app_title(app_title: str, mode: str, modules: list[str] = []) -> str:
14
+ if mode == "monolith":
15
+ return app_title
16
+ return f"{app_title} - {', '.join(modules)}"
17
+
18
+
19
+ def create_default_app_lifespan(db_engine: Engine) -> Lifespan:
20
+ @asynccontextmanager
21
+ async def default_app_lifespan(app: FastAPI):
22
+ SQLModel.metadata.create_all(db_engine)
23
+ yield
24
+
25
+ return default_app_lifespan
26
+
27
+
28
+ def serve_static_dir(app: FastAPI, static_dir: str):
29
+ app.mount("/static", StaticFiles(directory=static_dir), name="static")
30
+
31
+ # Serve static files
32
+ @app.get("/static/{file_path:path}", include_in_schema=False)
33
+ async def static_files(file_path: str):
34
+ full_path = os.path.join(static_dir, file_path)
35
+ if os.path.isfile(full_path):
36
+ return FileResponse(full_path)
37
+ raise HTTPException(status_code=404, detail="File not found")
38
+
39
+
40
+ def serve_docs(app: FastAPI, app_title: str, favicon_url: str):
41
+ @app.get("/docs", include_in_schema=False)
42
+ async def swagger_ui_html():
43
+ return get_swagger_ui_html(
44
+ openapi_url="/openapi.json",
45
+ title=app_title,
46
+ swagger_favicon_url=favicon_url,
47
+ )
@@ -0,0 +1,105 @@
1
+ import re
2
+ from typing import Callable
3
+
4
+ from sqlalchemy import asc, desc
5
+ from sqlalchemy.sql import ClauseElement, ColumnElement
6
+ from sqlmodel import SQLModel
7
+
8
+
9
+ def create_default_sort_param_parser() -> (
10
+ Callable[[SQLModel, str], list[ColumnElement]]
11
+ ):
12
+ def parse_sort_param(model: SQLModel, query: str) -> list[ColumnElement]:
13
+ """
14
+ Parse the sort parameter and return a list of SQLAlchemy ColumnElement objects.
15
+
16
+ Args:
17
+ model (Type[SQLModel]): The SQLModel class to be queried.
18
+ query (str): A comma-separated string of fields to sort by.
19
+ Prefix a field with '-' for descending order.
20
+
21
+ Returns:
22
+ list[ColumnElement]: A list of SQLAlchemy ColumnElement objects representing the sort order.
23
+
24
+ Example:
25
+ parse_sort_param(UserModel, "name,-age")
26
+ # Returns [asc(UserModel.name), desc(UserModel.age)]
27
+ """
28
+ sorts: list[ColumnElement] = []
29
+ sort_parts = query.split(",")
30
+ for part in sort_parts:
31
+ if part.startswith("-"):
32
+ key = part[1:]
33
+ order = desc
34
+ else:
35
+ key = part
36
+ order = asc
37
+ if hasattr(model, key):
38
+ sorts.append(order(getattr(model, key)))
39
+ return sorts
40
+
41
+ return parse_sort_param
42
+
43
+
44
+ def create_default_filter_param_parser() -> (
45
+ Callable[[SQLModel, str], list[ClauseElement]]
46
+ ):
47
+ def parse_filter_param(model: SQLModel, query: str) -> list[ClauseElement]:
48
+ """
49
+ Parse the filter parameter and return a list of SQLAlchemy ClauseElement objects.
50
+
51
+ Args:
52
+ model (Type[SQLModel]): The SQLModel class to be queried.
53
+ query (str): A comma-separated string of filters.
54
+ Each filter should be in the format "field:operator:value".
55
+ Use '\,' to escape commas within values.
56
+
57
+ Returns:
58
+ list[ClauseElement]: A list of SQLAlchemy ClauseElement objects representing the filters.
59
+
60
+ Supported operators:
61
+ eq: Equal to
62
+ ne: Not equal to
63
+ gt: Greater than
64
+ gte: Greater than or equal to
65
+ lt: Less than
66
+ lte: Less than or equal to
67
+ like: SQL LIKE (use % for wildcards)
68
+ in: In a list of values (semicolon-separated)
69
+
70
+ Example:
71
+ parse_filter_param(UserModel, "age:gte:18,name:like:John%,role:in:admin;user,address:eq:123\, Main St.")
72
+ # Returns [UserModel.age >= 18, UserModel.name.like("John%"), UserModel.role.in_(["admin", "user"]), UserModel.address == "123, Main St."]
73
+ """
74
+ filters: list[ClauseElement] = []
75
+ filter_parts = split_by_comma(query)
76
+ for part in filter_parts:
77
+ match = re.match(r"(.+):(.+):(.+)", part)
78
+ if match:
79
+ key, op, value = match.groups()
80
+ value = value.replace(r"\,", ",") # Unescape commas in the value
81
+ if hasattr(model, key):
82
+ column = getattr(model, key)
83
+ if op == "eq":
84
+ filters.append(column == value)
85
+ elif op == "ne":
86
+ filters.append(column != value)
87
+ elif op == "gt":
88
+ filters.append(column > value)
89
+ elif op == "gte":
90
+ filters.append(column >= value)
91
+ elif op == "lt":
92
+ filters.append(column < value)
93
+ elif op == "lte":
94
+ filters.append(column <= value)
95
+ elif op == "like":
96
+ filters.append(column.like(value))
97
+ elif op == "in":
98
+ filters.append(column.in_(value.split(";")))
99
+ return filters
100
+
101
+ return parse_filter_param
102
+
103
+
104
+ def split_by_comma(s: str, delimiter: str = ",") -> list[str]:
105
+ return re.split(r"(?<!\\)" + re.escape(delimiter), s)
@@ -0,0 +1,58 @@
1
+ import re
2
+
3
+
4
+ def get_os_from_user_agent(user_agent: str) -> str:
5
+ os_patterns = [
6
+ (r"Windows NT (\d+\.\d+)", "Windows"),
7
+ (r"Mac OS X (\d+[_\.]\d+)", "MacOS"),
8
+ (r"Android (\d+[\.\d]*)", "Android"),
9
+ (r"iPhone OS (\d+[_\.]\d+)", "iOS"),
10
+ (r"iPad.*OS (\d+[_\.]\d+)", "iPadOS"),
11
+ (r"Linux", "Linux"),
12
+ ]
13
+ os = "Unknown OS"
14
+ # Match OS
15
+ for pattern, name in os_patterns:
16
+ match = re.search(pattern, user_agent)
17
+ if match:
18
+ os = (
19
+ f"{name} {match.group(1).replace('_', '.')}" if match.groups() else name
20
+ )
21
+ break
22
+ return os
23
+
24
+
25
+ def get_browser_from_user_agent(user_agent: str) -> str:
26
+ browser_patterns = [
27
+ (r"Chrome/([\d\.]+)", "Chrome"),
28
+ (r"Firefox/([\d\.]+)", "Firefox"),
29
+ (r"Edg/([\d\.]+)", "Edge"),
30
+ (r"Safari/([\d\.]+)", "Safari"),
31
+ ]
32
+ browser = "Unknown Browser"
33
+ # Match Browser
34
+ for pattern, name in browser_patterns:
35
+ match = re.search(pattern, user_agent)
36
+ if match:
37
+ browser = f"{name} {match.group(1)}"
38
+ break
39
+ return browser
40
+
41
+
42
+ def get_device_from_user_agent(user_agent: str):
43
+ device_patterns = [
44
+ (r"iPhone", "iPhone"),
45
+ (r"iPad", "iPad"),
46
+ (r"Android.*Mobile", "Android Phone"),
47
+ (r"Android", "Android Tablet"),
48
+ (r"Macintosh", "Mac"),
49
+ (r"Windows NT", "Windows PC"),
50
+ (r"Linux", "Linux Device"),
51
+ ]
52
+ device = "Unknown Device"
53
+ # Match Device
54
+ for pattern, name in device_patterns:
55
+ if re.search(pattern, user_agent):
56
+ device = name
57
+ break
58
+ return device
@@ -39,7 +39,7 @@ APP_COMMUNICATION = os.getenv(
39
39
  )
40
40
  APP_REPOSITORY_TYPE = os.getenv("APP_REPOSITORY_TYPE", "db")
41
41
  APP_DB_URL = os.getenv(
42
- "APP_DB_URL",
42
+ "MY_APP_NAME_DB_URL",
43
43
  (
44
44
  f"sqlite:///{APP_PATH}/monolith.db"
45
45
  if APP_MODE == "monolith" or len(APP_MODULES) == 0
@@ -1,4 +1,4 @@
1
- from my_app_name.common.app import app
1
+ from my_app_name.common.app_factory import app
2
2
  from my_app_name.module.auth import route as auth_route
3
3
  from my_app_name.module.gateway import route as gateway_route
4
4
 
@@ -0,0 +1,16 @@
1
+ from my_app_name.config import APP_AUTH_BASE_URL
2
+ from my_app_name.module.auth.client.auth_client import AuthClient
3
+ from my_app_name.module.auth.service.permission.permission_service_factory import (
4
+ permission_service,
5
+ )
6
+ from my_app_name.module.auth.service.role.role_service_factory import role_service
7
+ from my_app_name.module.auth.service.user.user_service_factory import user_service
8
+
9
+
10
+ class AuthAPIClient(
11
+ permission_service.as_api_client(base_url=APP_AUTH_BASE_URL),
12
+ role_service.as_api_client(base_url=APP_AUTH_BASE_URL),
13
+ user_service.as_api_client(base_url=APP_AUTH_BASE_URL),
14
+ AuthClient,
15
+ ):
16
+ pass
@@ -0,0 +1,163 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from my_app_name.schema.permission import (
4
+ MultiplePermissionResponse,
5
+ PermissionCreateWithAudit,
6
+ PermissionResponse,
7
+ PermissionUpdateWithAudit,
8
+ )
9
+ from my_app_name.schema.role import (
10
+ MultipleRoleResponse,
11
+ RoleCreateWithAudit,
12
+ RoleResponse,
13
+ RoleUpdateWithAudit,
14
+ )
15
+ from my_app_name.schema.user import (
16
+ MultipleUserResponse,
17
+ UserCreateWithAudit,
18
+ UserResponse,
19
+ UserUpdateWithAudit,
20
+ )
21
+
22
+
23
+ class AuthClient(ABC):
24
+
25
+ # Permission related methods
26
+
27
+ @abstractmethod
28
+ async def get_permission_by_id(self, permission_id: str) -> PermissionResponse:
29
+ """Get permission by id"""
30
+
31
+ @abstractmethod
32
+ async def get_permissions(
33
+ self,
34
+ page: int = 1,
35
+ page_size: int = 10,
36
+ sort: str | None = None,
37
+ filter: str | None = None,
38
+ ) -> MultiplePermissionResponse:
39
+ """Get permissions by filter and sort"""
40
+
41
+ @abstractmethod
42
+ async def create_permission(
43
+ self, data: PermissionCreateWithAudit
44
+ ) -> PermissionResponse:
45
+ """Create a new permission"""
46
+
47
+ @abstractmethod
48
+ async def create_permission(
49
+ self, data: list[PermissionCreateWithAudit]
50
+ ) -> list[PermissionResponse]:
51
+ """Create new permissions"""
52
+
53
+ @abstractmethod
54
+ async def update_permission_bulk(
55
+ self, permission_ids: list[str], data: PermissionUpdateWithAudit
56
+ ) -> PermissionResponse:
57
+ """Update some permissions"""
58
+
59
+ @abstractmethod
60
+ async def update_permission(
61
+ self, permission_id: str, data: PermissionUpdateWithAudit
62
+ ) -> PermissionResponse:
63
+ """Update a permission"""
64
+
65
+ @abstractmethod
66
+ async def delete_permission_bulk(
67
+ self, permission_ids: str, deleted_by: str
68
+ ) -> PermissionResponse:
69
+ """Delete some permissions"""
70
+
71
+ @abstractmethod
72
+ async def delete_permission(
73
+ self, permission_id: str, deleted_by: str
74
+ ) -> PermissionResponse:
75
+ """Delete a permission"""
76
+
77
+ # Role related methods
78
+
79
+ @abstractmethod
80
+ async def get_role_by_id(self, role_id: str) -> RoleResponse:
81
+ """Get role by id"""
82
+
83
+ @abstractmethod
84
+ async def get_roles(
85
+ self,
86
+ page: int = 1,
87
+ page_size: int = 10,
88
+ sort: str | None = None,
89
+ filter: str | None = None,
90
+ ) -> MultipleRoleResponse:
91
+ """Get roles by filter and sort"""
92
+
93
+ @abstractmethod
94
+ async def create_role(self, data: RoleCreateWithAudit) -> RoleResponse:
95
+ """Create a new role"""
96
+
97
+ @abstractmethod
98
+ async def create_role(self, data: list[RoleCreateWithAudit]) -> list[RoleResponse]:
99
+ """Create new roles"""
100
+
101
+ @abstractmethod
102
+ async def update_role_bulk(
103
+ self, role_ids: list[str], data: RoleUpdateWithAudit
104
+ ) -> RoleResponse:
105
+ """Update some roles"""
106
+
107
+ @abstractmethod
108
+ async def update_role(
109
+ self, role_id: str, data: RoleUpdateWithAudit
110
+ ) -> RoleResponse:
111
+ """Update a role"""
112
+
113
+ @abstractmethod
114
+ async def delete_role_bulk(self, role_ids: str, deleted_by: str) -> RoleResponse:
115
+ """Delete some roles"""
116
+
117
+ @abstractmethod
118
+ async def delete_role(self, role_id: str, deleted_by: str) -> RoleResponse:
119
+ """Delete a role"""
120
+
121
+ # User related methods
122
+
123
+ @abstractmethod
124
+ async def get_user_by_id(self, user_id: str) -> UserResponse:
125
+ """Get user by id"""
126
+
127
+ @abstractmethod
128
+ async def get_users(
129
+ self,
130
+ page: int = 1,
131
+ page_size: int = 10,
132
+ sort: str | None = None,
133
+ filter: str | None = None,
134
+ ) -> MultipleUserResponse:
135
+ """Get users by filter and sort"""
136
+
137
+ @abstractmethod
138
+ async def create_user(self, data: UserCreateWithAudit) -> UserResponse:
139
+ """Create a new user"""
140
+
141
+ @abstractmethod
142
+ async def create_user(self, data: list[UserCreateWithAudit]) -> list[UserResponse]:
143
+ """Create new users"""
144
+
145
+ @abstractmethod
146
+ async def update_user_bulk(
147
+ self, user_ids: list[str], data: UserUpdateWithAudit
148
+ ) -> UserResponse:
149
+ """Update some users"""
150
+
151
+ @abstractmethod
152
+ async def update_user(
153
+ self, user_id: str, data: UserUpdateWithAudit
154
+ ) -> UserResponse:
155
+ """Update a user"""
156
+
157
+ @abstractmethod
158
+ async def delete_user_bulk(self, user_ids: str, deleted_by: str) -> UserResponse:
159
+ """Delete some users"""
160
+
161
+ @abstractmethod
162
+ async def delete_user(self, user_id: str, deleted_by: str) -> UserResponse:
163
+ """Delete a user"""
@@ -0,0 +1,9 @@
1
+ from my_app_name.config import APP_COMMUNICATION
2
+ from my_app_name.module.auth.client.auth_api_client import AuthAPIClient
3
+ from my_app_name.module.auth.client.auth_client import AuthClient
4
+ from my_app_name.module.auth.client.auth_direct_client import AuthDirectClient
5
+
6
+ if APP_COMMUNICATION == "direct":
7
+ auth_client: AuthClient = AuthDirectClient()
8
+ elif APP_COMMUNICATION == "api":
9
+ auth_client: AuthClient = AuthAPIClient()
@@ -0,0 +1,15 @@
1
+ from my_app_name.module.auth.client.auth_client import AuthClient
2
+ from my_app_name.module.auth.service.permission.permission_service_factory import (
3
+ permission_service,
4
+ )
5
+ from my_app_name.module.auth.service.role.role_service_factory import role_service
6
+ from my_app_name.module.auth.service.user.user_service_factory import user_service
7
+
8
+
9
+ class AuthDirectClient(
10
+ permission_service.as_direct_client(),
11
+ role_service.as_direct_client(),
12
+ user_service.as_direct_client(),
13
+ AuthClient,
14
+ ):
15
+ pass
@@ -0,0 +1,160 @@
1
+ """Add user table
2
+
3
+ Revision ID: 3093c7336477
4
+ Revises:
5
+ Create Date: 2024-11-20 05:57:01.684118
6
+
7
+ """
8
+
9
+ from typing import Sequence, Union
10
+
11
+ import sqlalchemy as sa
12
+ import sqlmodel
13
+ from alembic import op
14
+
15
+ # revision identifiers, used by Alembic.
16
+ revision: str = "3093c7336477"
17
+ down_revision: Union[str, None] = None
18
+ branch_labels: Union[str, Sequence[str], None] = None
19
+ depends_on: Union[str, Sequence[str], None] = None
20
+
21
+
22
+ def upgrade() -> None:
23
+ # ### commands auto generated by Alembic - please adjust! ###
24
+ op.create_table(
25
+ "permission",
26
+ sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
27
+ sa.Column("created_at", sa.DateTime(), nullable=True),
28
+ sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
29
+ sa.Column("updated_at", sa.DateTime(), nullable=True),
30
+ sa.Column("updated_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
31
+ sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
32
+ sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
33
+ sa.PrimaryKeyConstraint("id"),
34
+ )
35
+ op.create_index(op.f("ix_permission_name"), "permission", ["name"], unique=False)
36
+ op.create_index(
37
+ op.f("ix_permission_created_at"), "permission", ["created_at"], unique=False
38
+ )
39
+ op.create_index(
40
+ op.f("ix_permission_created_by"), "permission", ["created_by"], unique=False
41
+ )
42
+ op.create_index(
43
+ op.f("ix_permission_updated_at"), "permission", ["updated_at"], unique=False
44
+ )
45
+ op.create_index(
46
+ op.f("ix_permission_updated_by"), "permission", ["updated_by"], unique=False
47
+ )
48
+
49
+ op.create_table(
50
+ "role",
51
+ sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
52
+ sa.Column("created_at", sa.DateTime(), nullable=True),
53
+ sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
54
+ sa.Column("updated_at", sa.DateTime(), nullable=True),
55
+ sa.Column("updated_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
56
+ sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
57
+ sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
58
+ sa.PrimaryKeyConstraint("id"),
59
+ )
60
+ op.create_index(op.f("ix_role_name"), "role", ["name"], unique=False)
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)
65
+
66
+ op.create_table(
67
+ "rolepermission",
68
+ sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
69
+ sa.Column("role_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
70
+ sa.Column("permission_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
71
+ sa.Column("created_at", sa.DateTime(), nullable=True),
72
+ sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
73
+ sa.PrimaryKeyConstraint("id"),
74
+ )
75
+ op.create_index(
76
+ op.f("ix_rolepermission_permission_id"),
77
+ "rolepermission",
78
+ ["permission_id"],
79
+ unique=False,
80
+ )
81
+ op.create_index(
82
+ op.f("ix_rolepermission_role_id"), "rolepermission", ["role_id"], unique=False
83
+ )
84
+
85
+ op.create_table(
86
+ "user",
87
+ sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
88
+ sa.Column("username", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
89
+ sa.Column("password", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
90
+ sa.Column("created_at", sa.DateTime(), nullable=False),
91
+ sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
92
+ sa.Column("updated_at", sa.DateTime(), nullable=True),
93
+ sa.Column("updated_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
94
+ sa.PrimaryKeyConstraint("id"),
95
+ )
96
+ op.create_index(op.f("ix_user_username"), "user", ["username"], unique=False)
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)
101
+
102
+ op.create_table(
103
+ "userrole",
104
+ sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
105
+ sa.Column("user_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
106
+ sa.Column("role_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
107
+ sa.Column("created_at", sa.DateTime(), nullable=True),
108
+ sa.Column("created_by", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
109
+ sa.PrimaryKeyConstraint("id"),
110
+ )
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)
113
+
114
+ op.create_table(
115
+ "session",
116
+ sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
117
+ sa.Column("user_id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
118
+ sa.Column("device", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
119
+ sa.Column("os", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
120
+ sa.Column("browser", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
121
+ sa.PrimaryKeyConstraint("id"),
122
+ )
123
+ op.create_index(op.f("ix_session_user_id"), "session", ["user_id"], unique=False)
124
+ # ### end Alembic commands ###
125
+
126
+
127
+ def downgrade() -> None:
128
+ # ### commands auto generated by Alembic - please adjust! ###
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")
160
+ # ### end Alembic commands ###
@@ -1,6 +1,23 @@
1
- from my_app_name.schema.user import User
1
+ from my_app_name.schema.permission import Permission
2
+ from my_app_name.schema.role import Role, RolePermission
3
+ from my_app_name.schema.session import Session
4
+ from my_app_name.schema.user import User, UserRole
2
5
  from sqlalchemy import MetaData
3
6
 
4
7
  metadata = MetaData()
8
+
9
+ Permission.metadata = metadata
10
+ Permission.__table__.tometadata(metadata)
11
+
12
+ Role.metadata = metadata
13
+ Role.__table__.tometadata(metadata)
14
+ RolePermission.metadata = metadata
15
+ RolePermission.__table__.tometadata(metadata)
16
+
5
17
  User.metadata = metadata
6
18
  User.__table__.tometadata(metadata)
19
+ UserRole.metadata = metadata
20
+ UserRole.__table__.tometadata(metadata)
21
+
22
+ Session.metadata = metadata
23
+ Session.__table__.tometadata(metadata)
@@ -1,7 +1,10 @@
1
1
  from fastapi import FastAPI
2
- from my_app_name.common.app import app
2
+ from my_app_name.common.app_factory import app
3
3
  from my_app_name.common.schema import BasicResponse
4
4
  from my_app_name.config import APP_MAIN_MODULE, APP_MODE, APP_MODULES
5
+ from my_app_name.module.auth.service.permission.permission_service_factory import (
6
+ permission_service,
7
+ )
5
8
  from my_app_name.module.auth.service.user.user_service_factory import user_service
6
9
 
7
10
 
@@ -32,6 +35,7 @@ def serve_route(app: FastAPI):
32
35
 
33
36
  # Serve user endpoints for APIClient
34
37
  user_service.serve_route(app)
38
+ permission_service.serve_route(app)
35
39
 
36
40
 
37
41
  serve_route(app)