zrb 1.0.0a21__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 (191) hide show
  1. zrb/__init__.py +2 -1
  2. zrb/__main__.py +0 -3
  3. zrb/builtin/__init__.py +3 -0
  4. zrb/builtin/group.py +1 -0
  5. zrb/builtin/llm/llm_chat.py +2 -2
  6. zrb/builtin/llm/tool/web.py +1 -1
  7. zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -2
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +80 -20
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +150 -42
  11. 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 +113 -0
  12. 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 +9 -0
  13. 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
  14. 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
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/{factory.py → my_entity_repository_factory.py} +2 -2
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +72 -0
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +23 -0
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -0
  24. 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
  25. 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
  26. 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
  27. 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
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +11 -11
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +8 -8
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +185 -101
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +236 -0
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/view.py +37 -0
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +25 -1
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +163 -0
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +7 -3
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
  57. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +75 -0
  58. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +59 -0
  59. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
  60. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +105 -0
  61. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
  62. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +42 -13
  63. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +38 -17
  64. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
  65. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +105 -0
  66. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +7 -0
  67. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -14
  68. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +198 -28
  69. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +74 -0
  70. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
  71. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
  72. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
  73. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
  74. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
  75. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
  76. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
  77. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
  78. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
  79. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
  80. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
  81. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
  82. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
  83. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
  84. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
  85. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
  86. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
  87. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
  88. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
  89. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
  90. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
  91. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
  92. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
  93. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
  94. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
  95. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
  96. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
  97. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
  98. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +50 -4
  99. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +52 -0
  100. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +30 -5
  101. zrb/builtin/python.py +1 -1
  102. zrb/builtin/random.py +61 -0
  103. zrb/cmd/cmd_val.py +6 -5
  104. zrb/content_transformer/any_content_transformer.py +7 -0
  105. zrb/content_transformer/content_transformer.py +6 -0
  106. zrb/runner/cli.py +14 -7
  107. zrb/runner/web_app.py +28 -280
  108. zrb/runner/web_config/config.py +91 -0
  109. zrb/runner/web_config/config_factory.py +26 -0
  110. zrb/runner/web_route/docs_route.py +17 -0
  111. zrb/runner/web_route/error_page/serve_default_404.py +28 -0
  112. zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +2 -2
  113. zrb/runner/{web_controller → web_route}/error_page/view.html +5 -0
  114. zrb/runner/web_route/home_page/home_page_route.py +51 -0
  115. zrb/runner/web_route/login_api_route.py +31 -0
  116. zrb/runner/web_route/login_page/login_page_route.py +39 -0
  117. zrb/runner/web_route/logout_api_route.py +18 -0
  118. zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
  119. zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
  120. zrb/runner/web_route/node_page/node_page_route.py +50 -0
  121. zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +3 -3
  122. zrb/runner/web_route/refresh_token_api_route.py +38 -0
  123. zrb/runner/web_route/static/static_route.py +44 -0
  124. zrb/runner/web_route/task_input_api_route.py +47 -0
  125. zrb/runner/web_route/task_session_api_route.py +102 -0
  126. zrb/runner/web_schema/session.py +5 -0
  127. zrb/runner/web_schema/token.py +11 -0
  128. zrb/runner/web_schema/user.py +32 -0
  129. zrb/runner/web_util/cookie.py +29 -0
  130. zrb/runner/{web_util.py → web_util/html.py} +1 -23
  131. zrb/runner/web_util/token.py +72 -0
  132. zrb/runner/web_util/user.py +63 -0
  133. zrb/session/session.py +6 -4
  134. zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
  135. zrb/task/base_task.py +53 -6
  136. zrb/task/base_trigger.py +2 -0
  137. zrb/task/cmd_task.py +9 -5
  138. zrb/task/http_check.py +2 -0
  139. zrb/task/llm_task.py +2 -0
  140. zrb/task/make_task.py +2 -0
  141. zrb/task/rsync_task.py +2 -0
  142. zrb/task/scaffolder.py +8 -5
  143. zrb/task/scheduler.py +2 -0
  144. zrb/task/tcp_check.py +2 -0
  145. zrb/task_status/task_status.py +4 -3
  146. zrb/util/cmd/command.py +1 -0
  147. zrb/util/file.py +7 -1
  148. {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/METADATA +1 -1
  149. zrb-1.0.0b2.dist-info/RECORD +307 -0
  150. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
  151. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/my_entity_usecase.py +0 -65
  152. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
  153. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -6
  154. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
  155. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -20
  156. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_usecase.py +0 -245
  157. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
  158. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
  159. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
  160. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
  161. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  162. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py +0 -53
  163. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
  164. zrb/runner/web_config.py +0 -274
  165. zrb/runner/web_controller/home_page/controller.py +0 -33
  166. zrb/runner/web_controller/login_page/controller.py +0 -25
  167. zrb/runner/web_controller/logout_page/controller.py +0 -26
  168. zrb-1.0.0a21.dist-info/RECORD +0 -244
  169. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
  170. /zrb/{runner/web_controller → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission}/__init__.py +0 -0
  171. /zrb/{runner/web_controller/group_info_page → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role}/__init__.py +0 -0
  172. /zrb/runner/{web_controller/home_page → web_route}/__init__.py +0 -0
  173. /zrb/runner/{web_controller/session_page → web_route/home_page}/__init__.py +0 -0
  174. /zrb/runner/{web_controller → web_route}/home_page/view.html +0 -0
  175. /zrb/runner/{web_controller → web_route}/login_page/view.html +0 -0
  176. /zrb/runner/{web_controller → web_route}/logout_page/view.html +0 -0
  177. /zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +0 -0
  178. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
  179. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +0 -0
  180. /zrb/runner/{refresh-token.template.js → web_route/static/refresh-token.template.js} +0 -0
  181. /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
  182. /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
  183. /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
  184. /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
  185. /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
  186. /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
  187. /zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +0 -0
  188. /zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +0 -0
  189. /zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +0 -0
  190. {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/WHEEL +0 -0
  191. {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/entry_points.txt +0 -0
@@ -1,245 +0,0 @@
1
- from enum import Enum
2
- from functools import partial, wraps
3
- from typing import Any, Callable, Sequence
4
-
5
- import httpx
6
- from fastapi import APIRouter, params
7
- from fastapi.routing import APIRoute
8
- from fastapi.types import IncEx
9
- from fastapi.utils import generate_unique_id
10
- from starlette.responses import JSONResponse, Response
11
-
12
-
13
- class RouteParam:
14
- def __init__(
15
- self,
16
- path: str,
17
- response_model: Any,
18
- status_code: int | None = None,
19
- tags: list[str | Enum] | None = None,
20
- dependencies: Sequence[params.Depends] | None = None,
21
- summary: str | None = None,
22
- description: str = "",
23
- response_description: str = "",
24
- responses: dict[int | str, dict[str, Any]] | None = None,
25
- deprecated: bool | None = None,
26
- methods: set[str] | list[str] | None = None,
27
- operation_id: str | None = None,
28
- response_model_include: IncEx | None = None,
29
- response_model_exclude: IncEx | None = None,
30
- response_model_by_alias: bool = True,
31
- response_model_exclude_unset: bool = False,
32
- response_model_exclude_defaults: bool = False,
33
- response_model_exclude_none: bool = False,
34
- include_in_schema: bool = True,
35
- response_class: type[Response] = Response,
36
- name: str | None = None,
37
- openapi_extra: dict[str, Any] | None = None,
38
- generate_unique_id_function: Callable[[APIRoute], str] | None = None,
39
- func: Callable | None = None,
40
- ):
41
- self.path = path
42
- self.response_model = response_model
43
- self.status_code = status_code
44
- self.tags = tags
45
- self.dependencies = dependencies
46
- self.summary = summary
47
- self.description = description
48
- self.response_description = response_description
49
- self.responses = responses
50
- self.deprecated = deprecated
51
- self.methods = methods
52
- self.operation_id = operation_id
53
- self.response_model_include = response_model_include
54
- self.response_model_exclude = response_model_exclude
55
- self.response_model_by_alias = response_model_by_alias
56
- self.response_model_exclude_unset = response_model_exclude_unset
57
- self.response_model_exclude_defaults = response_model_exclude_defaults
58
- self.response_model_exclude_none = response_model_exclude_none
59
- self.include_in_schema = include_in_schema
60
- self.response_class = response_class
61
- self.name = name
62
- self.openapi_extra = openapi_extra
63
- self.generate_unique_id_function = generate_unique_id_function
64
- self.func = func
65
-
66
-
67
- class BaseUsecase:
68
- _route_params: dict[str, RouteParam] = {}
69
-
70
- def __init__(self):
71
- self._route_params: dict[str, RouteParam] = {}
72
- for name, method in self.__class__.__dict__.items():
73
- if hasattr(method, "__route_param__"):
74
- self._route_params[name] = getattr(method, "__route_param__")
75
-
76
- @classmethod
77
- def route(
78
- cls,
79
- path: str,
80
- *,
81
- response_model: Any = None,
82
- status_code: int | None = None,
83
- tags: list[str | Enum] | None = None,
84
- dependencies: Sequence[params.Depends] | None = None,
85
- summary: str | None = None,
86
- description: str = None,
87
- response_description: str = "Successful Response",
88
- responses: dict[int | str, dict[str, Any]] | None = None,
89
- deprecated: bool | None = None,
90
- methods: set[str] | list[str] | None = None,
91
- operation_id: str | None = None,
92
- response_model_include: IncEx | None = None,
93
- response_model_exclude: IncEx | None = None,
94
- response_model_by_alias: bool = True,
95
- response_model_exclude_unset: bool = False,
96
- response_model_exclude_defaults: bool = False,
97
- response_model_exclude_none: bool = False,
98
- include_in_schema: bool = True,
99
- response_class: type[Response] = JSONResponse,
100
- name: str | None = None,
101
- openapi_extra: dict[str, Any] | None = None,
102
- generate_unique_id_function: Callable[[APIRoute], str] = generate_unique_id,
103
- ):
104
- """
105
- Decorator to register a method with its HTTP details.
106
- """
107
-
108
- def decorator(func: Callable):
109
- @wraps(func)
110
- async def wrapped(*args, **kwargs):
111
- return await func(*args, **kwargs)
112
-
113
- # Inject __route_param__ property to the method
114
- # Method with __route_param__ property will automatically
115
- # registered to self._route_param and will be automatically exposed
116
- # into DirectClient and APIClient
117
- wrapped.__route_param__ = RouteParam(
118
- path=path,
119
- response_model=response_model,
120
- status_code=status_code,
121
- tags=tags,
122
- dependencies=dependencies,
123
- summary=summary,
124
- description=description,
125
- response_description=response_description,
126
- responses=responses,
127
- deprecated=deprecated,
128
- methods=methods,
129
- operation_id=operation_id,
130
- response_model_include=response_model_include,
131
- response_model_exclude=response_model_exclude,
132
- response_model_by_alias=response_model_by_alias,
133
- response_model_exclude_unset=response_model_exclude_unset,
134
- response_model_exclude_defaults=response_model_exclude_defaults,
135
- response_model_exclude_none=response_model_exclude_none,
136
- include_in_schema=include_in_schema,
137
- response_class=response_class,
138
- name=name,
139
- openapi_extra=openapi_extra,
140
- generate_unique_id_function=generate_unique_id_function,
141
- func=func,
142
- )
143
- return wrapped
144
-
145
- return decorator
146
-
147
- def as_direct_client(self):
148
- """
149
- Dynamically create a direct client class.
150
- """
151
- _methods = self._route_params
152
- DirectClient = create_client_class("DirectClient")
153
- for name, details in _methods.items():
154
- func = details.func
155
- client_method = create_direct_client_method(func, self)
156
- # Use __get__ to make a bounded method,
157
- # ensuring that client_method use DirectClient as `self`
158
- setattr(DirectClient, name, client_method.__get__(DirectClient))
159
- return DirectClient
160
-
161
- def as_api_client(self, base_url: str):
162
- """
163
- Dynamically create an API client class.
164
- """
165
- _methods = self._route_params
166
- APIClient = create_client_class("APIClient")
167
- # Dynamically generate methods
168
- for name, param in _methods.items():
169
- client_method = create_api_client_method(param, base_url)
170
- # Use __get__ to make a bounded method,
171
- # ensuring that client_method use APIClient as `self`
172
- setattr(APIClient, name, client_method.__get__(APIClient))
173
- return APIClient
174
-
175
- def serve_route(self, app: APIRouter):
176
- """
177
- Dynamically add routes to FastAPI.
178
- """
179
- for _, route_param in self._route_params.items():
180
- bound_func = partial(route_param.func, self)
181
- bound_func.__name__ = route_param.func.__name__
182
- bound_func.__doc__ = route_param.func.__doc__
183
- app.add_api_route(
184
- path=route_param.path,
185
- endpoint=bound_func,
186
- response_model=route_param.response_model,
187
- status_code=route_param.status_code,
188
- tags=route_param.tags,
189
- dependencies=route_param.dependencies,
190
- summary=route_param.summary,
191
- description=route_param.description,
192
- response_description=route_param.response_description,
193
- responses=route_param.responses,
194
- deprecated=route_param.deprecated,
195
- methods=route_param.methods,
196
- operation_id=route_param.operation_id,
197
- response_model_include=route_param.response_model_include,
198
- response_model_exclude=route_param.response_model_exclude,
199
- response_model_by_alias=route_param.response_model_by_alias,
200
- response_model_exclude_unset=route_param.response_model_exclude_unset,
201
- response_model_exclude_defaults=route_param.response_model_exclude_defaults,
202
- response_model_exclude_none=route_param.response_model_exclude_none,
203
- include_in_schema=route_param.include_in_schema,
204
- response_class=route_param.response_class,
205
- name=route_param.name,
206
- openapi_extra=route_param.openapi_extra,
207
- generate_unique_id_function=route_param.generate_unique_id_function,
208
- )
209
-
210
-
211
- def create_client_class(name):
212
- class Client:
213
- pass
214
-
215
- Client.__name__ = name
216
- return Client
217
-
218
-
219
- def create_direct_client_method(func: Callable, usecase: BaseUsecase):
220
- async def client_method(self, *args, **kwargs):
221
- return await func(usecase, *args, **kwargs)
222
-
223
- return client_method
224
-
225
-
226
- def create_api_client_method(param: RouteParam, base_url: str):
227
- _url = param.path
228
- _methods = [method.lower() for method in param.methods]
229
-
230
- async def client_method(self, *args, **kwargs):
231
- async with httpx.AsyncClient() as client:
232
- url = base_url + _url.format(**kwargs)
233
- if "post" in _methods:
234
- response = await client.post(url, json=kwargs)
235
- elif "put" in _methods:
236
- response = await client.put(url, json=kwargs)
237
- elif "delete" in _methods:
238
- response = await client.delete(url, json=kwargs)
239
- else:
240
- response = await client.get(url, params=kwargs)
241
- # Add more HTTP methods as needed
242
- response.raise_for_status()
243
- return response.json()
244
-
245
- return client_method
@@ -1,33 +0,0 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from my_app_name.schema.user import (
4
- UserCreateWithAudit,
5
- UserResponse,
6
- UserUpdateWithAudit,
7
- )
8
-
9
-
10
- class AnyClient(ABC):
11
- @abstractmethod
12
- async def get_user_by_id(self, user_id: str) -> UserResponse:
13
- pass
14
-
15
- @abstractmethod
16
- async def get_all_users(self) -> list[UserResponse]:
17
- pass
18
-
19
- @abstractmethod
20
- async def create_user(
21
- self, data: UserCreateWithAudit | list[UserCreateWithAudit]
22
- ) -> UserResponse | list[UserResponse]:
23
- pass
24
-
25
- @abstractmethod
26
- async def update_user(
27
- self, user_id: str, data: UserUpdateWithAudit
28
- ) -> UserResponse:
29
- pass
30
-
31
- @abstractmethod
32
- async def delete_user(self, user_id: str) -> UserResponse:
33
- pass
@@ -1,7 +0,0 @@
1
- from my_app_name.config import APP_AUTH_BASE_URL
2
- from my_app_name.module.auth.client.any_client import AnyClient
3
- from my_app_name.module.auth.service.user.user_usecase_factory import user_usecase
4
-
5
-
6
- class APIClient(user_usecase.as_api_client(base_url=APP_AUTH_BASE_URL), AnyClient):
7
- pass
@@ -1,6 +0,0 @@
1
- from my_app_name.module.auth.client.any_client import AnyClient
2
- from my_app_name.module.auth.service.user.user_usecase_factory import user_usecase
3
-
4
-
5
- class DirectClient(user_usecase.as_direct_client(), AnyClient):
6
- pass
@@ -1,9 +0,0 @@
1
- from my_app_name.config import APP_COMMUNICATION
2
- from my_app_name.module.auth.client.any_client import AnyClient
3
- from my_app_name.module.auth.client.api_client import APIClient
4
- from my_app_name.module.auth.client.direct_client import DirectClient
5
-
6
- if APP_COMMUNICATION == "direct":
7
- client: AnyClient = DirectClient()
8
- elif APP_COMMUNICATION == "api":
9
- client: AnyClient = APIClient()
@@ -1,37 +0,0 @@
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
- "user",
26
- sa.Column("id", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
27
- sa.Column("username", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
28
- sa.Column("password", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
29
- sa.PrimaryKeyConstraint("id"),
30
- )
31
- # ### end Alembic commands ###
32
-
33
-
34
- def downgrade() -> None:
35
- # ### commands auto generated by Alembic - please adjust! ###
36
- op.drop_table("user")
37
- # ### end Alembic commands ###
@@ -1,53 +0,0 @@
1
- from my_app_name.common.base_usecase import BaseUsecase
2
- from my_app_name.module.auth.service.user.repository.user_repository import (
3
- UserRepository,
4
- )
5
- from my_app_name.schema.user import (
6
- UserCreateWithAudit,
7
- UserResponse,
8
- UserUpdateWithAudit,
9
- )
10
-
11
-
12
- class UserUsecase(BaseUsecase):
13
- def __init__(self, user_repository: UserRepository):
14
- super().__init__()
15
- self.user_repository = user_repository
16
-
17
- @BaseUsecase.route(
18
- "/api/v1/users/{user_id}", methods=["get"], response_model=UserResponse
19
- )
20
- async def get_user_by_id(self, user_id: str) -> UserResponse:
21
- return await self.user_repository.get_by_id(user_id)
22
-
23
- @BaseUsecase.route(
24
- "/api/v1/users", methods=["get"], response_model=list[UserResponse]
25
- )
26
- async def get_all_users(self) -> list[UserResponse]:
27
- return await self.user_repository.get_all()
28
-
29
- @BaseUsecase.route(
30
- "/api/v1/users",
31
- methods=["post"],
32
- response_model=UserResponse | list[UserResponse],
33
- )
34
- async def create_user(
35
- self, data: UserCreateWithAudit | list[UserCreateWithAudit]
36
- ) -> UserResponse | list[UserResponse]:
37
- if isinstance(data, UserCreateWithAudit):
38
- return await self.user_repository.create(data)
39
- return await self.user_repository.create_bulk(data)
40
-
41
- @BaseUsecase.route(
42
- "/api/v1/users/{user_id}", methods=["put"], response_model=UserResponse
43
- )
44
- async def update_user(
45
- self, user_id: str, data: UserUpdateWithAudit
46
- ) -> UserResponse:
47
- return await self.user_repository.update(user_id, data)
48
-
49
- @BaseUsecase.route(
50
- "/api/v1/users/{user_id}", methods=["delete"], response_model=UserResponse
51
- )
52
- async def delete_user(self, user_id: str, deleted_by: str) -> UserResponse:
53
- return await self.user_repository.delete(user_id)
@@ -1,6 +0,0 @@
1
- from my_app_name.module.auth.service.user.repository.user_repository_factory import (
2
- user_repository,
3
- )
4
- from my_app_name.module.auth.service.user.user_usecase import UserUsecase
5
-
6
- user_usecase = UserUsecase(user_repository=user_repository)
zrb/runner/web_config.py DELETED
@@ -1,274 +0,0 @@
1
- from datetime import datetime, timedelta
2
- from typing import TYPE_CHECKING, Callable
3
-
4
- from pydantic import BaseModel, ConfigDict
5
-
6
- from zrb.config import (
7
- WEB_ACCESS_TOKEN_COOKIE_NAME,
8
- WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES,
9
- WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES,
10
- WEB_ENABLE_AUTH,
11
- WEB_GUEST_USERNAME,
12
- WEB_HTTP_PORT,
13
- WEB_REFRESH_TOKEN_COOKIE_NAME,
14
- WEB_SECRET_KEY,
15
- WEB_SUPER_ADMIN_PASSWORD,
16
- WEB_SUPER_ADMIN_USERNAME,
17
- )
18
- from zrb.group.any_group import AnyGroup
19
- from zrb.task.any_task import AnyTask
20
- from zrb.util.group import get_all_subtasks
21
-
22
- if TYPE_CHECKING:
23
- # Import Request only for type checking to reduce runtime dependencies
24
- from fastapi import Request
25
-
26
-
27
- class NewSessionResponse(BaseModel):
28
- session_name: str
29
-
30
-
31
- class RefreshTokenRequest(BaseModel):
32
- refresh_token: str
33
-
34
-
35
- class User(BaseModel):
36
- model_config = ConfigDict(arbitrary_types_allowed=True)
37
- username: str
38
- password: str = ""
39
- is_super_admin: bool = False
40
- is_guest: bool = False
41
- accessible_tasks: list[AnyTask | str] = []
42
-
43
- def is_password_match(self, password: str) -> bool:
44
- return self.password == password
45
-
46
- def can_access_group(self, group: AnyGroup) -> bool:
47
- if self.is_super_admin:
48
- return True
49
- all_tasks = get_all_subtasks(group, web_only=True)
50
- if any(self.can_access_task(task) for task in all_tasks):
51
- return True
52
- return False
53
-
54
- def can_access_task(self, task: AnyTask) -> bool:
55
- if self.is_super_admin:
56
- return True
57
- if task.name in self.accessible_tasks or task in self.accessible_tasks:
58
- return True
59
- return False
60
-
61
-
62
- class Token(BaseModel):
63
- access_token: str
64
- refresh_token: str
65
- token_type: str
66
-
67
-
68
- class WebConfig:
69
- def __init__(
70
- self,
71
- port: int,
72
- secret_key: str,
73
- access_token_expire_minutes: int,
74
- refresh_token_expire_minutes: int,
75
- access_token_cookie_name: str,
76
- refresh_token_cookie_name: str,
77
- enable_auth: bool,
78
- super_admin_username: str,
79
- super_admin_password: str,
80
- guest_username: str,
81
- guest_accessible_tasks: list[AnyTask | str] = [],
82
- find_user_by_username: Callable[[str], User | None] | None = None,
83
- ):
84
- self.secret_key = secret_key
85
- self.access_token_expire_minutes = access_token_expire_minutes
86
- self.refresh_token_expire_minutes = refresh_token_expire_minutes
87
- self.access_token_cookie_name = access_token_cookie_name
88
- self.refresh_token_cookie_name = refresh_token_cookie_name
89
- self.enable_auth = enable_auth
90
- self.port = port
91
- self._user_list = []
92
- self.super_admin_username = super_admin_username
93
- self.super_admin_password = super_admin_password
94
- self.guest_username = guest_username
95
- self.guest_accessible_tasks = guest_accessible_tasks
96
- self._find_user_by_username = find_user_by_username
97
-
98
- @property
99
- def default_user(self) -> User:
100
- if self.enable_auth:
101
- return User(
102
- username=self.guest_username,
103
- password="",
104
- is_guest=True,
105
- accessible_tasks=self.guest_accessible_tasks,
106
- )
107
- return User(
108
- username=self.guest_username,
109
- password="",
110
- is_guest=True,
111
- is_super_admin=True,
112
- )
113
-
114
- @property
115
- def super_admin(self) -> User:
116
- return User(
117
- username=self.super_admin_username,
118
- password=self.super_admin_password,
119
- is_super_admin=True,
120
- )
121
-
122
- @property
123
- def user_list(self) -> list[User]:
124
- if not self.enable_auth:
125
- return [self.default_user]
126
- return self._user_list + [self.super_admin, self.default_user]
127
-
128
- def set_guest_accessible_tasks(self, tasks: list[AnyTask | str]):
129
- self.guest_accessible_tasks = tasks
130
-
131
- def set_find_user_by_username(
132
- self, find_user_by_username: Callable[[str], User | None]
133
- ):
134
- self._find_user_by_username = find_user_by_username
135
-
136
- def append_user(self, user: User):
137
- duplicates = [
138
- existing_user
139
- for existing_user in self.user_list
140
- if existing_user.username == user.username
141
- ]
142
- if len(duplicates) > 0:
143
- raise ValueError(f"User already exists {user.username}")
144
- self._user_list.append(user)
145
-
146
- def find_user_by_username(self, username: str) -> User | None:
147
- user = None
148
- if self._find_user_by_username is not None:
149
- user = self._find_user_by_username(username)
150
- if user is None:
151
- user = next((u for u in self.user_list if u.username == username), None)
152
- return user
153
-
154
- async def get_user_from_request(self, request: "Request") -> User | None:
155
- from fastapi.security import OAuth2PasswordBearer
156
-
157
- if not self.enable_auth:
158
- return self.default_user
159
- # Normally we use "Depends"
160
- get_bearer_token = OAuth2PasswordBearer(
161
- tokenUrl="/api/v1/login", auto_error=False
162
- )
163
- bearer_token = await get_bearer_token(request)
164
- token_user = self._get_user_from_token(bearer_token)
165
- if token_user is not None:
166
- return token_user
167
- cookie_user = self._get_user_from_cookie(request)
168
- if cookie_user is not None:
169
- return cookie_user
170
- return self.default_user
171
-
172
- def _get_user_from_token(self, token: str) -> User | None:
173
- try:
174
- from jose import jwt
175
-
176
- payload = jwt.decode(
177
- token,
178
- self.secret_key,
179
- options={"require_sub": True, "require_exp": True},
180
- )
181
- username: str = payload.get("sub")
182
- if username is None:
183
- return None
184
- user = self.find_user_by_username(username)
185
- if user is None:
186
- return None
187
- return user
188
- except Exception:
189
- return None
190
-
191
- def _get_user_from_cookie(self, request: "Request") -> User | None:
192
- token = request.cookies.get(self.access_token_cookie_name)
193
- if token:
194
- return self._get_user_from_token(token)
195
- return None
196
-
197
- def get_user_by_credentials(self, username: str, password: str) -> User | None:
198
- user = self.find_user_by_username(username)
199
- if user is None or not user.is_password_match(password):
200
- return None
201
- return user
202
-
203
- def generate_tokens_by_credentials(
204
- self, username: str, password: str
205
- ) -> Token | None:
206
- if not self.enable_auth:
207
- user = self.default_user
208
- else:
209
- user = self.get_user_by_credentials(username, password)
210
- if user is None:
211
- return None
212
- access_token = self._generate_access_token(user.username)
213
- refresh_token = self._generate_refresh_token(user.username)
214
- return Token(
215
- access_token=access_token, refresh_token=refresh_token, token_type="bearer"
216
- )
217
-
218
- def _generate_access_token(self, username: str) -> str:
219
- from jose import jwt
220
-
221
- expire = datetime.now() + timedelta(minutes=self.access_token_expire_minutes)
222
- to_encode = {"sub": username, "exp": expire, "type": "access"}
223
- return jwt.encode(to_encode, self.secret_key)
224
-
225
- def _generate_refresh_token(self, username: str) -> str:
226
- from jose import jwt
227
-
228
- expire = datetime.now() + timedelta(minutes=self.refresh_token_expire_minutes)
229
- to_encode = {"sub": username, "exp": expire, "type": "refresh"}
230
- return jwt.encode(to_encode, self.secret_key)
231
-
232
- def regenerate_tokens(self, refresh_token: str) -> Token:
233
- from fastapi import HTTPException
234
- from jose import jwt
235
-
236
- # Decode and validate token
237
- try:
238
- payload = jwt.decode(
239
- refresh_token,
240
- self.secret_key,
241
- options={"require_exp": True, "require_sub": True},
242
- )
243
- except Exception:
244
- raise HTTPException(status_code=401, detail="Invalid JWT token")
245
- if payload.get("type") != "refresh":
246
- raise HTTPException(status_code=401, detail="Invalid token type")
247
- username: str = payload.get("sub")
248
- if username is None:
249
- raise HTTPException(status_code=401, detail="Invalid refresh token")
250
- user = self.find_user_by_username(username)
251
- if user is None:
252
- raise HTTPException(status_code=401, detail="User not found")
253
- # Create new token
254
- new_access_token = self._generate_access_token(username)
255
- new_refresh_token = self._generate_refresh_token(username)
256
- return Token(
257
- access_token=new_access_token,
258
- refresh_token=new_refresh_token,
259
- token_type="bearer",
260
- )
261
-
262
-
263
- web_config = WebConfig(
264
- port=WEB_HTTP_PORT,
265
- secret_key=WEB_SECRET_KEY,
266
- access_token_expire_minutes=WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES,
267
- refresh_token_expire_minutes=WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES,
268
- access_token_cookie_name=WEB_ACCESS_TOKEN_COOKIE_NAME,
269
- refresh_token_cookie_name=WEB_REFRESH_TOKEN_COOKIE_NAME,
270
- enable_auth=WEB_ENABLE_AUTH,
271
- super_admin_username=WEB_SUPER_ADMIN_USERNAME,
272
- super_admin_password=WEB_SUPER_ADMIN_PASSWORD,
273
- guest_username=WEB_GUEST_USERNAME,
274
- )