zrb 1.0.0a20__py3-none-any.whl → 1.0.0b3__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 (195) hide show
  1. zrb/__init__.py +2 -1
  2. zrb/__main__.py +3 -3
  3. zrb/builtin/__init__.py +3 -0
  4. zrb/builtin/group.py +1 -0
  5. zrb/builtin/llm/llm_chat.py +5 -3
  6. zrb/builtin/llm/tool/cli.py +1 -1
  7. zrb/builtin/llm/tool/rag.py +108 -145
  8. zrb/builtin/llm/tool/web.py +1 -1
  9. zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -2
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +80 -20
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +150 -42
  13. 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
  14. 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
  15. 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
  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.py +37 -16
  17. 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
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py +16 -6
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/client_method.py +57 -0
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +74 -0
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +23 -0
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -0
  26. 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
  27. 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
  28. 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
  29. 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
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +11 -11
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py +2 -2
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/task.py +8 -8
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/util.py +47 -20
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app_factory.py +29 -0
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_db_repository.py +230 -102
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_service.py +236 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/{db_engine.py → db_engine_factory.py} +1 -1
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/error.py +12 -0
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/logger_factory.py +10 -0
  40. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/parser_factory.py +7 -0
  41. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/app.py +47 -0
  42. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +105 -0
  43. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/user_agent.py +58 -0
  44. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/view.py +37 -0
  45. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +37 -1
  46. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +1 -1
  47. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_api_client.py +16 -0
  48. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client.py +169 -0
  49. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_client_factory.py +9 -0
  50. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/auth_direct_client.py +15 -0
  51. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_auth_tables.py +160 -0
  52. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration_metadata.py +18 -1
  53. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +7 -3
  54. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service.py +117 -0
  55. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/permission_service_factory.py +11 -0
  56. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_db_repository.py +26 -0
  57. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository.py +61 -0
  58. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/repository/permission_repository_factory.py +13 -0
  59. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_db_repository.py +89 -0
  60. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository.py +67 -0
  61. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/repository/role_repository_factory.py +13 -0
  62. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service.py +137 -0
  63. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/role_service_factory.py +7 -0
  64. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_db_repository.py +179 -12
  65. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +67 -17
  66. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +2 -2
  67. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service.py +127 -0
  68. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +7 -0
  69. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -14
  70. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +200 -30
  71. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +74 -0
  72. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
  73. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
  74. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
  75. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
  76. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
  77. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
  78. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
  79. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
  80. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
  81. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
  82. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
  83. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
  84. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
  85. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
  86. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
  87. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
  88. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
  89. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
  90. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
  91. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
  92. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
  93. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
  94. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
  95. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
  96. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
  97. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
  98. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
  99. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py +17 -5
  100. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py +78 -4
  101. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/session.py +48 -0
  102. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/user.py +69 -5
  103. zrb/builtin/python.py +1 -1
  104. zrb/builtin/random.py +61 -0
  105. zrb/cmd/cmd_val.py +6 -5
  106. zrb/config.py +16 -3
  107. zrb/content_transformer/any_content_transformer.py +7 -0
  108. zrb/content_transformer/content_transformer.py +6 -0
  109. zrb/runner/cli.py +14 -7
  110. zrb/runner/web_app.py +28 -238
  111. zrb/runner/web_config/config.py +91 -0
  112. zrb/runner/web_config/config_factory.py +26 -0
  113. zrb/runner/web_route/docs_route.py +17 -0
  114. zrb/runner/web_route/error_page/serve_default_404.py +28 -0
  115. zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +4 -3
  116. zrb/runner/{web_controller → web_route}/error_page/view.html +6 -0
  117. zrb/runner/web_route/home_page/home_page_route.py +51 -0
  118. zrb/runner/{web_controller → web_route}/home_page/view.html +1 -0
  119. zrb/runner/web_route/login_api_route.py +31 -0
  120. zrb/runner/web_route/login_page/login_page_route.py +39 -0
  121. zrb/runner/{web_controller → web_route}/login_page/view.html +1 -0
  122. zrb/runner/web_route/logout_api_route.py +18 -0
  123. zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
  124. zrb/runner/{web_controller → web_route}/logout_page/view.html +1 -0
  125. zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
  126. zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +1 -0
  127. zrb/runner/web_route/node_page/node_page_route.py +50 -0
  128. zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +5 -5
  129. zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +1 -0
  130. zrb/runner/web_route/refresh_token_api_route.py +38 -0
  131. zrb/runner/web_route/static/refresh-token.template.js +22 -0
  132. zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +6 -3
  133. zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +10 -8
  134. zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +9 -3
  135. zrb/runner/web_route/static/static_route.py +44 -0
  136. zrb/runner/web_route/task_input_api_route.py +47 -0
  137. zrb/runner/web_route/task_session_api_route.py +147 -0
  138. zrb/runner/web_schema/session.py +5 -0
  139. zrb/runner/web_schema/token.py +11 -0
  140. zrb/runner/web_schema/user.py +32 -0
  141. zrb/runner/web_util/cookie.py +29 -0
  142. zrb/runner/{web_util.py → web_util/html.py} +1 -18
  143. zrb/runner/web_util/token.py +72 -0
  144. zrb/runner/web_util/user.py +63 -0
  145. zrb/session/session.py +6 -4
  146. zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
  147. zrb/task/base_task.py +56 -8
  148. zrb/task/base_trigger.py +2 -0
  149. zrb/task/cmd_task.py +9 -5
  150. zrb/task/http_check.py +2 -0
  151. zrb/task/llm_task.py +184 -71
  152. zrb/task/make_task.py +2 -0
  153. zrb/task/rsync_task.py +2 -0
  154. zrb/task/scaffolder.py +8 -5
  155. zrb/task/scheduler.py +2 -0
  156. zrb/task/tcp_check.py +2 -0
  157. zrb/task_status/task_status.py +4 -3
  158. zrb/util/cmd/command.py +1 -0
  159. zrb/util/file.py +7 -1
  160. zrb/util/llm/tool.py +3 -7
  161. {zrb-1.0.0a20.dist-info → zrb-1.0.0b3.dist-info}/METADATA +9 -52
  162. zrb-1.0.0b3.dist-info/RECORD +307 -0
  163. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +0 -27
  164. 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
  165. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +0 -6
  166. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +0 -6
  167. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +0 -9
  168. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/app.py +0 -20
  169. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_usecase.py +0 -245
  170. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/any_client.py +0 -33
  171. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +0 -7
  172. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +0 -6
  173. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +0 -9
  174. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
  175. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase.py +0 -53
  176. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
  177. zrb/runner/web_config.py +0 -288
  178. zrb/runner/web_controller/home_page/controller.py +0 -33
  179. zrb/runner/web_controller/login_page/controller.py +0 -25
  180. zrb/runner/web_controller/logout_page/controller.py +0 -26
  181. zrb-1.0.0a20.dist-info/RECORD +0 -243
  182. /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
  183. /zrb/{runner/web_controller → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission}/__init__.py +0 -0
  184. /zrb/{runner/web_controller/group_info_page → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role}/__init__.py +0 -0
  185. /zrb/runner/{web_controller/home_page → web_route}/__init__.py +0 -0
  186. /zrb/runner/{web_controller/session_page → web_route/home_page}/__init__.py +0 -0
  187. /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
  188. /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
  189. /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
  190. /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
  191. /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
  192. /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
  193. /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
  194. {zrb-1.0.0a20.dist-info → zrb-1.0.0b3.dist-info}/WHEEL +0 -0
  195. {zrb-1.0.0a20.dist-info → zrb-1.0.0b3.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,288 +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 User(BaseModel):
28
- model_config = ConfigDict(arbitrary_types_allowed=True)
29
- username: str
30
- password: str = ""
31
- is_super_admin: bool = False
32
- is_guest: bool = False
33
- accessible_tasks: list[AnyTask | str] = []
34
-
35
- def is_password_match(self, password: str) -> bool:
36
- return self.password == password
37
-
38
- def can_access_group(self, group: AnyGroup) -> bool:
39
- if self.is_super_admin:
40
- return True
41
- all_tasks = get_all_subtasks(group, web_only=True)
42
- if any(self.can_access_task(task) for task in all_tasks):
43
- return True
44
- return False
45
-
46
- def can_access_task(self, task: AnyTask) -> bool:
47
- if self.is_super_admin:
48
- return True
49
- if task.name in self.accessible_tasks or task in self.accessible_tasks:
50
- return True
51
- return False
52
-
53
-
54
- class Token(BaseModel):
55
- access_token: str
56
- refresh_token: str
57
- token_type: str
58
-
59
-
60
- class WebConfig:
61
- def __init__(
62
- self,
63
- port: int,
64
- secret_key: str,
65
- access_token_expire_minutes: int,
66
- refresh_token_expire_minutes: int,
67
- access_token_cookie_name: str,
68
- refresh_token_cookie_name: str,
69
- enable_auth: bool,
70
- super_admin_username: str,
71
- super_admin_password: str,
72
- guest_username: str,
73
- guest_accessible_tasks: list[AnyTask | str] = [],
74
- find_user_by_username: Callable[[str], User | None] | None = None,
75
- ):
76
- self._secret_key = secret_key
77
- self._access_token_expire_minutes = access_token_expire_minutes
78
- self._refresh_token_expire_minutes = refresh_token_expire_minutes
79
- self._access_token_cookie_name = access_token_cookie_name
80
- self._refresh_token_cookie_name = refresh_token_cookie_name
81
- self._enable_auth = enable_auth
82
- self._port = port
83
- self._user_list = []
84
- self._super_admin_username = super_admin_username
85
- self._super_admin_password = super_admin_password
86
- self._guest_username = guest_username
87
- self._guest_accessible_tasks = guest_accessible_tasks
88
- self._find_user_by_username = find_user_by_username
89
-
90
- @property
91
- def port(self) -> int:
92
- return self._port
93
-
94
- @property
95
- def access_token_cookie_name(self) -> str:
96
- return self._access_token_cookie_name
97
-
98
- @property
99
- def refresh_token_cookie_name(self) -> str:
100
- return self._refresh_token_cookie_name
101
-
102
- @property
103
- def access_token_max_age(self) -> int:
104
- self._access_token_expire_minutes * 60
105
-
106
- @property
107
- def refresh_token_max_age(self) -> int:
108
- self._refresh_token_expire_minutes * 60
109
-
110
- @property
111
- def default_user(self) -> User:
112
- if self._enable_auth:
113
- return User(
114
- username=self._guest_username,
115
- password="",
116
- is_guest=True,
117
- accessible_tasks=self._guest_accessible_tasks,
118
- )
119
- return User(
120
- username=self._guest_username,
121
- password="",
122
- is_guest=True,
123
- is_super_admin=True,
124
- )
125
-
126
- @property
127
- def super_admin(self) -> User:
128
- return User(
129
- username=self._super_admin_username,
130
- password=self._super_admin_password,
131
- is_super_admin=True,
132
- )
133
-
134
- @property
135
- def user_list(self) -> list[User]:
136
- if not self._enable_auth:
137
- return [self.default_user]
138
- return self._user_list + [self.super_admin, self.default_user]
139
-
140
- def set_guest_accessible_tasks(self, tasks: list[AnyTask | str]):
141
- self._guest_accessible_tasks = tasks
142
-
143
- def set_find_user_by_username(
144
- self, find_user_by_username: Callable[[str], User | None]
145
- ):
146
- self._find_user_by_username = find_user_by_username
147
-
148
- def append_user(self, user: User):
149
- duplicates = [
150
- existing_user
151
- for existing_user in self.user_list
152
- if existing_user.username == user.username
153
- ]
154
- if len(duplicates) > 0:
155
- raise ValueError(f"User already exists {user.username}")
156
- self._user_list.append(user)
157
-
158
- def enable_auth(self):
159
- self._enable_auth = True
160
-
161
- def disable_auth(self):
162
- self._enable_auth = False
163
-
164
- def find_user_by_username(self, username: str) -> User | None:
165
- user = None
166
- if self._find_user_by_username is not None:
167
- user = self._find_user_by_username(username)
168
- if user is None:
169
- user = next((u for u in self.user_list if u.username == username), None)
170
- return user
171
-
172
- async def get_user_by_request(self, request: "Request") -> User | None:
173
- from fastapi.security import OAuth2PasswordBearer
174
-
175
- if not self._enable_auth:
176
- return self.default_user
177
- # Normally we use "Depends"
178
- get_bearer_token = OAuth2PasswordBearer(
179
- tokenUrl="/api/v1/login", auto_error=False
180
- )
181
- bearer_token = await get_bearer_token(request)
182
- token_user = self._get_user_from_token(bearer_token)
183
- if token_user is not None:
184
- return token_user
185
- cookie_user = self._get_user_from_cookie(request)
186
- if cookie_user is not None:
187
- return cookie_user
188
- return self.default_user
189
-
190
- def _get_user_from_token(self, token: str) -> User | None:
191
- try:
192
- from jose import jwt
193
-
194
- payload = jwt.decode(
195
- token,
196
- self._secret_key,
197
- options={"require_sub": True, "require_exp": True},
198
- )
199
- username: str = payload.get("sub")
200
- if username is None:
201
- return None
202
- user = self.find_user_by_username(username)
203
- if user is None:
204
- return None
205
- return user
206
- except Exception:
207
- return None
208
-
209
- def _get_user_from_cookie(self, request: "Request") -> User | None:
210
- token = request.cookies.get(self._access_token_cookie_name)
211
- if token:
212
- return self._get_user_from_token(token)
213
- return None
214
-
215
- def get_user_by_credentials(self, username: str, password: str) -> User:
216
- user = self.find_user_by_username(username)
217
- if user is None or not user.is_password_match(password):
218
- return self.default_user
219
- return user
220
-
221
- def generate_tokens(self, username: str, password: str) -> Token:
222
- if not self._enable_auth:
223
- user = self.default_user
224
- else:
225
- user = self.get_user_by_credentials(username, password)
226
- access_token = self.create_access_token(user.username)
227
- refresh_token = self.create_refresh_token(user.username)
228
- return Token(
229
- access_token=access_token, refresh_token=refresh_token, token_type="bearer"
230
- )
231
-
232
- def create_access_token(self, username: str) -> str:
233
- from jose import jwt
234
-
235
- expire = datetime.now() + timedelta(minutes=self._access_token_expire_minutes)
236
- to_encode = {"sub": username, "exp": expire, "type": "access"}
237
- return jwt.encode(to_encode, self._secret_key)
238
-
239
- def create_refresh_token(self, username: str) -> str:
240
- from jose import jwt
241
-
242
- expire = datetime.now() + timedelta(minutes=self._refresh_token_expire_minutes)
243
- to_encode = {"sub": username, "exp": expire, "type": "refresh"}
244
- return jwt.encode(to_encode, self._secret_key)
245
-
246
- def refresh_tokens(self, refresh_token: str) -> Token:
247
- from fastapi import HTTPException
248
- from jose import jwt
249
-
250
- # Decode and validate token
251
- try:
252
- payload = jwt.decode(
253
- refresh_token,
254
- self._secret_key,
255
- options={"require_exp": True, "require_sub": True},
256
- )
257
- except Exception:
258
- raise HTTPException(status_code=401, detail="Invalid JWT token")
259
- if payload.get("type") != "refresh":
260
- raise HTTPException(status_code=401, detail="Invalid token type")
261
- username: str = payload.get("sub")
262
- if username is None:
263
- raise HTTPException(status_code=401, detail="Invalid refresh token")
264
- user = self.find_user_by_username(username)
265
- if user is None:
266
- raise HTTPException(status_code=401, detail="User not found")
267
- # Create new token
268
- new_access_token = self.create_access_token(username)
269
- new_refresh_token = self.create_refresh_token(username)
270
- return Token(
271
- access_token=new_access_token,
272
- refresh_token=new_refresh_token,
273
- token_type="bearer",
274
- )
275
-
276
-
277
- web_config = WebConfig(
278
- port=WEB_HTTP_PORT,
279
- secret_key=WEB_SECRET_KEY,
280
- access_token_expire_minutes=WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES,
281
- refresh_token_expire_minutes=WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES,
282
- access_token_cookie_name=WEB_ACCESS_TOKEN_COOKIE_NAME,
283
- refresh_token_cookie_name=WEB_REFRESH_TOKEN_COOKIE_NAME,
284
- enable_auth=WEB_ENABLE_AUTH,
285
- super_admin_username=WEB_SUPER_ADMIN_USERNAME,
286
- super_admin_password=WEB_SUPER_ADMIN_PASSWORD,
287
- guest_username=WEB_GUEST_USERNAME,
288
- )