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.
- zrb/__main__.py +0 -3
- zrb/builtin/__init__.py +3 -0
- zrb/builtin/group.py +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +66 -21
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +67 -41
- 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
- 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
- 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
- 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
- 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
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +63 -28
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +1 -0
- 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
- 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
- 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
- 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
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +4 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +185 -101
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +99 -108
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +163 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +5 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +75 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +59 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +105 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +42 -13
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +38 -17
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +69 -17
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +2 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +198 -28
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +50 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +52 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +30 -5
- zrb/builtin/random.py +61 -0
- zrb/cmd/cmd_val.py +6 -5
- zrb/runner/cli.py +10 -1
- zrb/runner/web_util/token.py +7 -3
- zrb/task/base_task.py +24 -2
- zrb/task/cmd_task.py +7 -5
- zrb/util/cmd/command.py +1 -0
- zrb/util/file.py +7 -1
- {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/METADATA +1 -1
- {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/RECORD +80 -61
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -5
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -57
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
- /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{view.py → util/view.py} +0 -0
- {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/WHEEL +0 -0
- {zrb-1.0.0b1.dist-info → zrb-1.0.0b2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
from logging import Logger
|
2
|
+
|
3
|
+
from my_app_name.common.base_service import BaseService
|
4
|
+
from my_app_name.module.auth.service.permission.repository.permission_repository import (
|
5
|
+
PermissionRepository,
|
6
|
+
)
|
7
|
+
from my_app_name.schema.permission import (
|
8
|
+
MultiplePermissionResponse,
|
9
|
+
PermissionCreateWithAudit,
|
10
|
+
PermissionResponse,
|
11
|
+
PermissionUpdateWithAudit,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
class PermissionService(BaseService):
|
16
|
+
|
17
|
+
def __init__(self, logger: Logger, permission_repository: PermissionRepository):
|
18
|
+
super().__init__(logger)
|
19
|
+
self.permission_repository = permission_repository
|
20
|
+
|
21
|
+
@BaseService.route(
|
22
|
+
"/api/v1/permissions/{permission_id}",
|
23
|
+
methods=["get"],
|
24
|
+
response_model=PermissionResponse,
|
25
|
+
)
|
26
|
+
async def get_permission_by_id(self, permission_id: str) -> PermissionResponse:
|
27
|
+
return await self.permission_repository.get_by_id(permission_id)
|
28
|
+
|
29
|
+
@BaseService.route(
|
30
|
+
"/api/v1/permissions",
|
31
|
+
methods=["get"],
|
32
|
+
response_model=MultiplePermissionResponse,
|
33
|
+
)
|
34
|
+
async def get_permissions(
|
35
|
+
self,
|
36
|
+
page: int = 1,
|
37
|
+
page_size: int = 10,
|
38
|
+
sort: str | None = None,
|
39
|
+
filter: str | None = None,
|
40
|
+
) -> MultiplePermissionResponse:
|
41
|
+
permissions = await self.permission_repository.get(
|
42
|
+
page, page_size, filter, sort
|
43
|
+
)
|
44
|
+
count = await self.permission_repository.count(filter)
|
45
|
+
return MultiplePermissionResponse(data=permissions, count=count)
|
46
|
+
|
47
|
+
@BaseService.route(
|
48
|
+
"/api/v1/permissions/bulk",
|
49
|
+
methods=["post"],
|
50
|
+
response_model=list[PermissionResponse],
|
51
|
+
)
|
52
|
+
async def create_permission_bulk(
|
53
|
+
self, data: list[PermissionCreateWithAudit]
|
54
|
+
) -> list[PermissionResponse]:
|
55
|
+
permissions = await self.permission_repository.create_bulk(data)
|
56
|
+
return await self.permission_repository.get_by_ids(
|
57
|
+
[permission.id for permission in permissions]
|
58
|
+
)
|
59
|
+
|
60
|
+
@BaseService.route(
|
61
|
+
"/api/v1/permissions",
|
62
|
+
methods=["post"],
|
63
|
+
response_model=PermissionResponse,
|
64
|
+
)
|
65
|
+
async def create_permission(
|
66
|
+
self, data: PermissionCreateWithAudit
|
67
|
+
) -> PermissionResponse:
|
68
|
+
permission = await self.permission_repository.create(data)
|
69
|
+
return await self.permission_repository.get_by_id(permission.id)
|
70
|
+
|
71
|
+
@BaseService.route(
|
72
|
+
"/api/v1/permissions/bulk",
|
73
|
+
methods=["put"],
|
74
|
+
response_model=PermissionResponse,
|
75
|
+
)
|
76
|
+
async def update_permission_bulk(
|
77
|
+
self, permission_ids: list[str], data: PermissionUpdateWithAudit
|
78
|
+
) -> PermissionResponse:
|
79
|
+
permissions = await self.permission_repository.update_bulk(permission_ids, data)
|
80
|
+
return await self.permission_repository.get_by_ids(
|
81
|
+
[permission.id for permission in permissions]
|
82
|
+
)
|
83
|
+
|
84
|
+
@BaseService.route(
|
85
|
+
"/api/v1/permissions/{permission_id}",
|
86
|
+
methods=["put"],
|
87
|
+
response_model=PermissionResponse,
|
88
|
+
)
|
89
|
+
async def update_permission(
|
90
|
+
self, permission_id: str, data: PermissionUpdateWithAudit
|
91
|
+
) -> PermissionResponse:
|
92
|
+
permission = await self.permission_repository.update(permission_id, data)
|
93
|
+
return await self.permission_repository.get_by_id(permission.id)
|
94
|
+
|
95
|
+
@BaseService.route(
|
96
|
+
"/api/v1/permissions/{permission_id}",
|
97
|
+
methods=["delete"],
|
98
|
+
response_model=PermissionResponse,
|
99
|
+
)
|
100
|
+
async def delete_permission_bulk(
|
101
|
+
self, permission_ids: list[str], deleted_by: str
|
102
|
+
) -> PermissionResponse:
|
103
|
+
permissions = await self.permission_repository.delete_bulk(permission_ids)
|
104
|
+
return await self.permission_repository.get_by_ids(
|
105
|
+
[permission.id for permission in permissions]
|
106
|
+
)
|
107
|
+
|
108
|
+
@BaseService.route(
|
109
|
+
"/api/v1/permissions/{permission_id}",
|
110
|
+
methods=["delete"],
|
111
|
+
response_model=PermissionResponse,
|
112
|
+
)
|
113
|
+
async def delete_permission(
|
114
|
+
self, permission_id: str, deleted_by: str
|
115
|
+
) -> PermissionResponse:
|
116
|
+
permission = await self.permission_repository.delete(permission_id)
|
117
|
+
return await self.permission_repository.get_by_id(permission.id)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from my_app_name.common.logger_factory import logger
|
2
|
+
from my_app_name.module.auth.service.permission.permission_service import (
|
3
|
+
PermissionService,
|
4
|
+
)
|
5
|
+
from my_app_name.module.auth.service.permission.repository.permission_repository_factory import (
|
6
|
+
permission_repository,
|
7
|
+
)
|
8
|
+
|
9
|
+
permission_service = PermissionService(
|
10
|
+
logger, permission_repository=permission_repository
|
11
|
+
)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from my_app_name.common.base_db_repository import BaseDBRepository
|
2
|
+
from my_app_name.module.auth.service.permission.repository.permission_repository import (
|
3
|
+
PermissionRepository,
|
4
|
+
)
|
5
|
+
from my_app_name.schema.permission import (
|
6
|
+
Permission,
|
7
|
+
PermissionCreateWithAudit,
|
8
|
+
PermissionResponse,
|
9
|
+
PermissionUpdateWithAudit,
|
10
|
+
)
|
11
|
+
|
12
|
+
|
13
|
+
class PermissionDBRepository(
|
14
|
+
BaseDBRepository[
|
15
|
+
Permission,
|
16
|
+
PermissionResponse,
|
17
|
+
PermissionCreateWithAudit,
|
18
|
+
PermissionUpdateWithAudit,
|
19
|
+
],
|
20
|
+
PermissionRepository,
|
21
|
+
):
|
22
|
+
db_model = Permission
|
23
|
+
response_model = PermissionResponse
|
24
|
+
create_model = PermissionCreateWithAudit
|
25
|
+
update_model = PermissionUpdateWithAudit
|
26
|
+
entity_name = "permission"
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
from my_app_name.schema.permission import (
|
4
|
+
Permission,
|
5
|
+
PermissionCreateWithAudit,
|
6
|
+
PermissionResponse,
|
7
|
+
PermissionUpdateWithAudit,
|
8
|
+
)
|
9
|
+
|
10
|
+
|
11
|
+
class PermissionRepository(ABC):
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
async def get_by_id(self, id: str) -> PermissionResponse:
|
15
|
+
"""Get permission by id"""
|
16
|
+
|
17
|
+
@abstractmethod
|
18
|
+
async def get_by_ids(self, id_list: list[str]) -> PermissionResponse:
|
19
|
+
"""Get permissions by ids"""
|
20
|
+
|
21
|
+
@abstractmethod
|
22
|
+
async def get(
|
23
|
+
self,
|
24
|
+
page: int = 1,
|
25
|
+
page_size: int = 10,
|
26
|
+
filter: str | None = None,
|
27
|
+
sort: str | None = None,
|
28
|
+
) -> list[Permission]:
|
29
|
+
"""Get permissions by filter and sort"""
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
async def count(self, filter: str | None = None) -> int:
|
33
|
+
"""Count permissions by filter"""
|
34
|
+
|
35
|
+
@abstractmethod
|
36
|
+
async def create(self, data: PermissionCreateWithAudit) -> Permission:
|
37
|
+
"""Create a new permission"""
|
38
|
+
|
39
|
+
@abstractmethod
|
40
|
+
async def create_bulk(
|
41
|
+
self, data: list[PermissionCreateWithAudit]
|
42
|
+
) -> list[Permission]:
|
43
|
+
"""Create some permissions"""
|
44
|
+
|
45
|
+
@abstractmethod
|
46
|
+
async def delete(self, id: str) -> Permission:
|
47
|
+
"""Delete a permission"""
|
48
|
+
|
49
|
+
@abstractmethod
|
50
|
+
async def delete_bulk(self, id_list: list[str]) -> list[Permission]:
|
51
|
+
"""Delete some permissions"""
|
52
|
+
|
53
|
+
@abstractmethod
|
54
|
+
async def update(self, id: str, data: PermissionUpdateWithAudit) -> Permission:
|
55
|
+
"""Update a permission"""
|
56
|
+
|
57
|
+
@abstractmethod
|
58
|
+
async def update_bulk(
|
59
|
+
self, id_list: list[str], data: PermissionUpdateWithAudit
|
60
|
+
) -> list[Permission]:
|
61
|
+
"""Update some permissions"""
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from my_app_name.common.db_engine_factory import db_engine
|
2
|
+
from my_app_name.config import APP_REPOSITORY_TYPE
|
3
|
+
from my_app_name.module.auth.service.permission.repository.permission_db_repository import (
|
4
|
+
PermissionDBRepository,
|
5
|
+
)
|
6
|
+
from my_app_name.module.auth.service.permission.repository.permission_repository import (
|
7
|
+
PermissionRepository,
|
8
|
+
)
|
9
|
+
|
10
|
+
if APP_REPOSITORY_TYPE == "db":
|
11
|
+
permission_repository: PermissionRepository = PermissionDBRepository(db_engine)
|
12
|
+
else:
|
13
|
+
permission_repository: PermissionRepository = None
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py
ADDED
File without changes
|
@@ -0,0 +1,75 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from my_app_name.common.base_db_repository import BaseDBRepository
|
4
|
+
from my_app_name.module.auth.service.role.repository.role_repository import (
|
5
|
+
RoleRepository,
|
6
|
+
)
|
7
|
+
from my_app_name.schema.permission import Permission
|
8
|
+
from my_app_name.schema.role import (
|
9
|
+
Role,
|
10
|
+
RoleCreateWithAudit,
|
11
|
+
RolePermission,
|
12
|
+
RoleResponse,
|
13
|
+
RoleUpdateWithAudit,
|
14
|
+
)
|
15
|
+
from sqlalchemy.sql import Select
|
16
|
+
from sqlmodel import select
|
17
|
+
|
18
|
+
|
19
|
+
class RoleDBRepository(
|
20
|
+
BaseDBRepository[
|
21
|
+
Role,
|
22
|
+
RoleResponse,
|
23
|
+
RoleCreateWithAudit,
|
24
|
+
RoleUpdateWithAudit,
|
25
|
+
],
|
26
|
+
RoleRepository,
|
27
|
+
):
|
28
|
+
db_model = Role
|
29
|
+
response_model = RoleResponse
|
30
|
+
create_model = RoleCreateWithAudit
|
31
|
+
update_model = RoleUpdateWithAudit
|
32
|
+
entity_name = "role"
|
33
|
+
|
34
|
+
def _select(self) -> Select:
|
35
|
+
return (
|
36
|
+
select(Role, Permission)
|
37
|
+
.join(RolePermission, RolePermission.role_id == Role.id, isouter=True)
|
38
|
+
.join(Permission, Permission.id == RolePermission.role_id, isouter=True)
|
39
|
+
)
|
40
|
+
|
41
|
+
def _rows_to_responses(self, rows: list[tuple[Role, Permission]]) -> RoleResponse:
|
42
|
+
role_map: dict[str, dict[str, Any]] = {}
|
43
|
+
for role, permission in rows:
|
44
|
+
if role.id not in role_map:
|
45
|
+
role_map[role.id] = {"role": role, "permissions": set()}
|
46
|
+
if permission:
|
47
|
+
role_map[role.id]["permissions"].add(permission)
|
48
|
+
return [
|
49
|
+
RoleResponse(
|
50
|
+
**data["role"].model_dump(), permissions=list(data["permissions"])
|
51
|
+
)
|
52
|
+
for data in role_map.values()
|
53
|
+
]
|
54
|
+
|
55
|
+
async def add_permissions(self, role_id, permission_names: list[str]) -> Role:
|
56
|
+
# TODO: complete this
|
57
|
+
select_statement = self._select().where(self.db_model.id == role_id)
|
58
|
+
rows = await self._execute_select_statement(select_statement)
|
59
|
+
responses = self._rows_to_responses(rows)
|
60
|
+
return self._ensure_one(responses)
|
61
|
+
|
62
|
+
async def remove_permissions(self, role_id, permission_names: list[str]) -> Role:
|
63
|
+
# TODO: complete this
|
64
|
+
select_statement = self._select().where(self.db_model.id == role_id)
|
65
|
+
rows = await self._execute_select_statement(select_statement)
|
66
|
+
responses = self._rows_to_responses(rows)
|
67
|
+
return self._ensure_one(responses)
|
68
|
+
|
69
|
+
|
70
|
+
def _remove_create_model_additional_property(
|
71
|
+
data: RoleCreateWithAudit,
|
72
|
+
) -> RoleCreateWithAudit:
|
73
|
+
return RoleCreateWithAudit(
|
74
|
+
**{key: val for key, val in data.model_dump().items() if key != "permissions"}
|
75
|
+
)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
from my_app_name.schema.role import (
|
4
|
+
Role,
|
5
|
+
RoleCreateWithAudit,
|
6
|
+
RoleResponse,
|
7
|
+
RoleUpdateWithAudit,
|
8
|
+
)
|
9
|
+
|
10
|
+
|
11
|
+
class RoleRepository(ABC):
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
async def get_by_id(self, id: str) -> RoleResponse:
|
15
|
+
"""Get role by id"""
|
16
|
+
|
17
|
+
@abstractmethod
|
18
|
+
async def get_by_ids(self, id_list: list[str]) -> RoleResponse:
|
19
|
+
"""Get roles by ids"""
|
20
|
+
|
21
|
+
@abstractmethod
|
22
|
+
async def get(
|
23
|
+
self,
|
24
|
+
page: int = 1,
|
25
|
+
page_size: int = 10,
|
26
|
+
filter: str | None = None,
|
27
|
+
sort: str | None = None,
|
28
|
+
) -> list[Role]:
|
29
|
+
"""Get roles by filter and sort"""
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
async def count(self, filter: str | None = None) -> int:
|
33
|
+
"""Count roles by filter"""
|
34
|
+
|
35
|
+
@abstractmethod
|
36
|
+
async def create(self, data: RoleCreateWithAudit) -> Role:
|
37
|
+
"""Create a new role"""
|
38
|
+
|
39
|
+
@abstractmethod
|
40
|
+
async def create_bulk(self, data: list[RoleCreateWithAudit]) -> list[Role]:
|
41
|
+
"""Create some roles"""
|
42
|
+
|
43
|
+
@abstractmethod
|
44
|
+
async def delete(self, id: str) -> Role:
|
45
|
+
"""Delete a role"""
|
46
|
+
|
47
|
+
@abstractmethod
|
48
|
+
async def delete_bulk(self, id_list: list[str]) -> list[Role]:
|
49
|
+
"""Delete some roles"""
|
50
|
+
|
51
|
+
@abstractmethod
|
52
|
+
async def update(self, id: str, data: RoleUpdateWithAudit) -> Role:
|
53
|
+
"""Update a role"""
|
54
|
+
|
55
|
+
@abstractmethod
|
56
|
+
async def update_bulk(
|
57
|
+
self, id_list: list[str], data: RoleUpdateWithAudit
|
58
|
+
) -> list[Role]:
|
59
|
+
"""Update some roles"""
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from my_app_name.common.db_engine_factory import db_engine
|
2
|
+
from my_app_name.config import APP_REPOSITORY_TYPE
|
3
|
+
from my_app_name.module.auth.service.role.repository.role_db_repository import (
|
4
|
+
RoleDBRepository,
|
5
|
+
)
|
6
|
+
from my_app_name.module.auth.service.role.repository.role_repository import (
|
7
|
+
RoleRepository,
|
8
|
+
)
|
9
|
+
|
10
|
+
if APP_REPOSITORY_TYPE == "db":
|
11
|
+
role_repository: RoleRepository = RoleDBRepository(db_engine)
|
12
|
+
else:
|
13
|
+
role_repository: RoleRepository = None
|
@@ -0,0 +1,105 @@
|
|
1
|
+
from logging import Logger
|
2
|
+
|
3
|
+
from my_app_name.common.base_service import BaseService
|
4
|
+
from my_app_name.module.auth.service.role.repository.role_repository import (
|
5
|
+
RoleRepository,
|
6
|
+
)
|
7
|
+
from my_app_name.schema.role import (
|
8
|
+
MultipleRoleResponse,
|
9
|
+
RoleCreateWithAudit,
|
10
|
+
RoleResponse,
|
11
|
+
RoleUpdateWithAudit,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
class RoleService(BaseService):
|
16
|
+
|
17
|
+
def __init__(self, logger: Logger, role_repository: RoleRepository):
|
18
|
+
super().__init__(logger)
|
19
|
+
self.role_repository = role_repository
|
20
|
+
|
21
|
+
@BaseService.route(
|
22
|
+
"/api/v1/roles/{role_id}",
|
23
|
+
methods=["get"],
|
24
|
+
response_model=RoleResponse,
|
25
|
+
)
|
26
|
+
async def get_role_by_id(self, role_id: str) -> RoleResponse:
|
27
|
+
return await self.role_repository.get_by_id(role_id)
|
28
|
+
|
29
|
+
@BaseService.route(
|
30
|
+
"/api/v1/roles",
|
31
|
+
methods=["get"],
|
32
|
+
response_model=MultipleRoleResponse,
|
33
|
+
)
|
34
|
+
async def get_roles(
|
35
|
+
self,
|
36
|
+
page: int = 1,
|
37
|
+
page_size: int = 10,
|
38
|
+
sort: str | None = None,
|
39
|
+
filter: str | None = None,
|
40
|
+
) -> MultipleRoleResponse:
|
41
|
+
roles = await self.role_repository.get(page, page_size, filter, sort)
|
42
|
+
count = await self.role_repository.count(filter)
|
43
|
+
return MultipleRoleResponse(data=roles, count=count)
|
44
|
+
|
45
|
+
@BaseService.route(
|
46
|
+
"/api/v1/roles",
|
47
|
+
methods=["post"],
|
48
|
+
response_model=RoleResponse,
|
49
|
+
)
|
50
|
+
async def create_role(self, data: RoleCreateWithAudit) -> RoleResponse:
|
51
|
+
role = await self.role_repository.create(data)
|
52
|
+
return await self.role_repository.get_by_id(role.id)
|
53
|
+
|
54
|
+
@BaseService.route(
|
55
|
+
"/api/v1/roles/bulk",
|
56
|
+
methods=["post"],
|
57
|
+
response_model=list[RoleResponse],
|
58
|
+
)
|
59
|
+
async def create_role_bulk(
|
60
|
+
self, data: list[RoleCreateWithAudit]
|
61
|
+
) -> list[RoleResponse]:
|
62
|
+
roles = await self.role_repository.create_bulk(data)
|
63
|
+
return await self.role_repository.get_by_ids([role.id for role in roles])
|
64
|
+
|
65
|
+
@BaseService.route(
|
66
|
+
"/api/v1/roles/bulk",
|
67
|
+
methods=["put"],
|
68
|
+
response_model=RoleResponse,
|
69
|
+
)
|
70
|
+
async def update_role_bulk(
|
71
|
+
self, role_ids: list[str], data: RoleUpdateWithAudit
|
72
|
+
) -> RoleResponse:
|
73
|
+
roles = await self.role_repository.update_bulk(role_ids, data)
|
74
|
+
return await self.role_repository.get_by_ids([role.id for role in roles])
|
75
|
+
|
76
|
+
@BaseService.route(
|
77
|
+
"/api/v1/roles/{role_id}",
|
78
|
+
methods=["put"],
|
79
|
+
response_model=RoleResponse,
|
80
|
+
)
|
81
|
+
async def update_role(
|
82
|
+
self, role_id: str, data: RoleUpdateWithAudit
|
83
|
+
) -> RoleResponse:
|
84
|
+
role = await self.role_repository.update(role_id, data)
|
85
|
+
return await self.role_repository.get_by_id(role.id)
|
86
|
+
|
87
|
+
@BaseService.route(
|
88
|
+
"/api/v1/roles/{role_id}",
|
89
|
+
methods=["delete"],
|
90
|
+
response_model=RoleResponse,
|
91
|
+
)
|
92
|
+
async def delete_role_bulk(
|
93
|
+
self, role_ids: list[str], deleted_by: str
|
94
|
+
) -> RoleResponse:
|
95
|
+
roles = await self.role_repository.delete_bulk(role_ids)
|
96
|
+
return await self.role_repository.get_by_ids([role.id for role in roles])
|
97
|
+
|
98
|
+
@BaseService.route(
|
99
|
+
"/api/v1/roles/{role_id}",
|
100
|
+
methods=["delete"],
|
101
|
+
response_model=RoleResponse,
|
102
|
+
)
|
103
|
+
async def delete_role(self, role_id: str, deleted_by: str) -> RoleResponse:
|
104
|
+
role = await self.role_repository.delete(role_id)
|
105
|
+
return await self.role_repository.get_by_id(role.id)
|
@@ -0,0 +1,7 @@
|
|
1
|
+
from my_app_name.common.logger_factory import logger
|
2
|
+
from my_app_name.module.auth.service.role.repository.role_repository_factory import (
|
3
|
+
role_repository,
|
4
|
+
)
|
5
|
+
from my_app_name.module.auth.service.role.role_service import RoleService
|
6
|
+
|
7
|
+
role_service = RoleService(logger, role_repository=role_repository)
|
@@ -1,17 +1,21 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
1
3
|
from my_app_name.common.base_db_repository import BaseDBRepository
|
2
|
-
from my_app_name.common.error import NotFoundError
|
3
4
|
from my_app_name.module.auth.service.user.repository.user_repository import (
|
4
5
|
UserRepository,
|
5
6
|
)
|
7
|
+
from my_app_name.schema.permission import Permission
|
8
|
+
from my_app_name.schema.role import Role, RolePermission
|
6
9
|
from my_app_name.schema.user import (
|
7
10
|
User,
|
8
11
|
UserCreateWithAudit,
|
9
12
|
UserResponse,
|
13
|
+
UserRole,
|
10
14
|
UserUpdateWithAudit,
|
11
15
|
)
|
12
16
|
from passlib.context import CryptContext
|
13
|
-
from sqlalchemy.
|
14
|
-
from sqlmodel import
|
17
|
+
from sqlalchemy.sql import Select
|
18
|
+
from sqlmodel import select
|
15
19
|
|
16
20
|
# Password hashing context
|
17
21
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
@@ -32,14 +36,39 @@ class UserDBRepository(
|
|
32
36
|
entity_name = "user"
|
33
37
|
column_preprocessors = {"password": hash_password}
|
34
38
|
|
39
|
+
def _select(self) -> Select:
|
40
|
+
return (
|
41
|
+
select(User, Role, Permission)
|
42
|
+
.join(UserRole, UserRole.user_id == User.id, isouter=True)
|
43
|
+
.join(Role, Role.id == UserRole.role_id, isouter=True)
|
44
|
+
.join(RolePermission, RolePermission.role_id == Role.id, isouter=True)
|
45
|
+
.join(Permission, Permission.id == RolePermission.role_id, isouter=True)
|
46
|
+
)
|
47
|
+
|
48
|
+
def _rows_to_responses(
|
49
|
+
self, rows: list[tuple[User, Role, Permission]]
|
50
|
+
) -> UserResponse:
|
51
|
+
user_map: dict[str, dict[str, Any]] = {}
|
52
|
+
for user, role, permission in rows:
|
53
|
+
if user.id not in user_map:
|
54
|
+
user_map[user.id] = {"user": user, "roles": set(), "permissions": set()}
|
55
|
+
if role:
|
56
|
+
user_map[user.id]["roles"].add(role)
|
57
|
+
if permission:
|
58
|
+
user_map[user.id]["permissions"].add(permission)
|
59
|
+
return [
|
60
|
+
UserResponse(
|
61
|
+
**data["user"].model_dump(),
|
62
|
+
roles=list(data["roles"]),
|
63
|
+
permissions=list(data["permissions"])
|
64
|
+
)
|
65
|
+
for data in user_map.values()
|
66
|
+
]
|
67
|
+
|
35
68
|
async def get_by_credentials(self, username: str, password: str) -> UserResponse:
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
user = session.exec(statement).first()
|
43
|
-
if not user or not pwd_context.verify(password, user.hashed_password):
|
44
|
-
raise NotFoundError(f"{self.entity_name} not found")
|
45
|
-
return self._to_response(user)
|
69
|
+
select_statement = self._select().where(
|
70
|
+
User.username == username, User.password == hash_password(password)
|
71
|
+
)
|
72
|
+
rows = await self._execute_select_statement(select_statement)
|
73
|
+
responses = self._rows_to_responses(rows)
|
74
|
+
return self._ensure_one(responses)
|
@@ -9,34 +9,55 @@ from my_app_name.schema.user import (
|
|
9
9
|
|
10
10
|
|
11
11
|
class UserRepository(ABC):
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
async def get_by_id(self, id: str) -> UserResponse:
|
15
|
+
"""Get user by id"""
|
16
|
+
|
17
|
+
@abstractmethod
|
18
|
+
async def get_by_ids(self, id_list: list[str]) -> UserResponse:
|
19
|
+
"""Get users by ids"""
|
20
|
+
|
21
|
+
@abstractmethod
|
22
|
+
async def get(
|
23
|
+
self,
|
24
|
+
page: int = 1,
|
25
|
+
page_size: int = 10,
|
26
|
+
filter: str | None = None,
|
27
|
+
sort: str | None = None,
|
28
|
+
) -> list[User]:
|
29
|
+
"""Get users by filter and sort"""
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
async def count(self, filter: str | None = None) -> int:
|
33
|
+
"""Count users by filter"""
|
34
|
+
|
12
35
|
@abstractmethod
|
13
|
-
async def create(self,
|
14
|
-
|
36
|
+
async def create(self, data: UserCreateWithAudit) -> User:
|
37
|
+
"""Create a new user"""
|
15
38
|
|
16
39
|
@abstractmethod
|
17
|
-
async def
|
18
|
-
|
40
|
+
async def create_bulk(self, data: list[UserCreateWithAudit]) -> list[User]:
|
41
|
+
"""Create some users"""
|
19
42
|
|
20
43
|
@abstractmethod
|
21
|
-
async def
|
22
|
-
|
44
|
+
async def delete(self, id: str) -> User:
|
45
|
+
"""Delete a user"""
|
23
46
|
|
24
47
|
@abstractmethod
|
25
|
-
async def
|
26
|
-
|
27
|
-
) -> UserResponse:
|
28
|
-
pass
|
48
|
+
async def delete_bulk(self, id_list: list[str]) -> list[User]:
|
49
|
+
"""Delete some users"""
|
29
50
|
|
30
51
|
@abstractmethod
|
31
|
-
async def
|
32
|
-
|
52
|
+
async def update(self, id: str, data: UserUpdateWithAudit) -> User:
|
53
|
+
"""Update a user"""
|
33
54
|
|
34
55
|
@abstractmethod
|
35
|
-
async def
|
36
|
-
self,
|
37
|
-
) -> list[
|
38
|
-
|
56
|
+
async def update_bulk(
|
57
|
+
self, id_list: list[str], data: UserUpdateWithAudit
|
58
|
+
) -> list[User]:
|
59
|
+
"""Update some users"""
|
39
60
|
|
40
61
|
@abstractmethod
|
41
62
|
async def get_by_credentials(self, username: str, password: str) -> UserResponse:
|
42
|
-
|
63
|
+
"""Get user by credential"""
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from my_app_name.common.
|
1
|
+
from my_app_name.common.db_engine_factory import db_engine
|
2
2
|
from my_app_name.config import APP_REPOSITORY_TYPE
|
3
3
|
from my_app_name.module.auth.service.user.repository.user_db_repository import (
|
4
4
|
UserDBRepository,
|
@@ -8,6 +8,6 @@ from my_app_name.module.auth.service.user.repository.user_repository import (
|
|
8
8
|
)
|
9
9
|
|
10
10
|
if APP_REPOSITORY_TYPE == "db":
|
11
|
-
user_repository: UserRepository = UserDBRepository(
|
11
|
+
user_repository: UserRepository = UserDBRepository(db_engine)
|
12
12
|
else:
|
13
13
|
user_repository: UserRepository = None
|