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.
- zrb/__init__.py +2 -1
- zrb/__main__.py +0 -3
- zrb/builtin/__init__.py +3 -0
- zrb/builtin/group.py +1 -0
- zrb/builtin/llm/llm_chat.py +2 -2
- zrb/builtin/llm/tool/web.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_task.py +2 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/config.py +5 -2
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +80 -20
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +150 -42
- 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
- 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
- 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/{factory.py → 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 +72 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +13 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +23 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +42 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +7 -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 +11 -11
- 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 +8 -8
- 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 +236 -0
- 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/common/util/view.py +37 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +25 -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 +7 -3
- 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/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 +105 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_service_factory.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +43 -14
- 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 +74 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/homepage.html +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-192x192.png +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/android-chrome-512x512.png +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/images/favicon-32x32.png +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.amber.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.blue.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.cyan.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.fuchsia.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.green.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.grey.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.indigo.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.jade.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.lime.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.orange.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pink.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.pumpkin.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.purple.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.red.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.sand.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.slate.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.violet.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css +4 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +34 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -0
- 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/python.py +1 -1
- zrb/builtin/random.py +61 -0
- zrb/cmd/cmd_val.py +6 -5
- zrb/content_transformer/any_content_transformer.py +7 -0
- zrb/content_transformer/content_transformer.py +6 -0
- zrb/runner/cli.py +14 -7
- zrb/runner/web_app.py +28 -280
- zrb/runner/web_config/config.py +91 -0
- zrb/runner/web_config/config_factory.py +26 -0
- zrb/runner/web_route/docs_route.py +17 -0
- zrb/runner/web_route/error_page/serve_default_404.py +28 -0
- zrb/runner/{web_controller/error_page/controller.py → web_route/error_page/show_error_page.py} +2 -2
- zrb/runner/{web_controller → web_route}/error_page/view.html +5 -0
- zrb/runner/web_route/home_page/home_page_route.py +51 -0
- zrb/runner/web_route/login_api_route.py +31 -0
- zrb/runner/web_route/login_page/login_page_route.py +39 -0
- zrb/runner/web_route/logout_api_route.py +18 -0
- zrb/runner/web_route/logout_page/logout_page_route.py +40 -0
- zrb/runner/{web_controller/group_info_page/controller.py → web_route/node_page/group/show_group_page.py} +3 -3
- zrb/runner/web_route/node_page/node_page_route.py +50 -0
- zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py} +3 -3
- zrb/runner/web_route/refresh_token_api_route.py +38 -0
- zrb/runner/web_route/static/static_route.py +44 -0
- zrb/runner/web_route/task_input_api_route.py +47 -0
- zrb/runner/web_route/task_session_api_route.py +102 -0
- zrb/runner/web_schema/session.py +5 -0
- zrb/runner/web_schema/token.py +11 -0
- zrb/runner/web_schema/user.py +32 -0
- zrb/runner/web_util/cookie.py +29 -0
- zrb/runner/{web_util.py → web_util/html.py} +1 -23
- zrb/runner/web_util/token.py +72 -0
- zrb/runner/web_util/user.py +63 -0
- zrb/session/session.py +6 -4
- zrb/session_state_logger/{default_session_state_logger.py → session_state_logger_factory.py} +1 -1
- zrb/task/base_task.py +53 -6
- zrb/task/base_trigger.py +2 -0
- zrb/task/cmd_task.py +9 -5
- zrb/task/http_check.py +2 -0
- zrb/task/llm_task.py +2 -0
- zrb/task/make_task.py +2 -0
- zrb/task/rsync_task.py +2 -0
- zrb/task/scaffolder.py +8 -5
- zrb/task/scheduler.py +2 -0
- zrb/task/tcp_check.py +2 -0
- zrb/task_status/task_status.py +4 -3
- zrb/util/cmd/command.py +1 -0
- zrb/util/file.py +7 -1
- {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/METADATA +1 -1
- zrb-1.0.0b2.dist-info/RECORD +307 -0
- 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/entity/template/app_template/module/my_module/service/my_entity/my_entity_usecase.py +0 -65
- 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 -6
- 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 -20
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/base_usecase.py +0 -245
- 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/module/auth/service/user/user_usecase.py +0 -53
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +0 -6
- zrb/runner/web_config.py +0 -274
- zrb/runner/web_controller/home_page/controller.py +0 -33
- zrb/runner/web_controller/login_page/controller.py +0 -25
- zrb/runner/web_controller/logout_page/controller.py +0 -26
- zrb-1.0.0a21.dist-info/RECORD +0 -244
- /zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/{create_column_task.py → add_column_task.py} +0 -0
- /zrb/{runner/web_controller → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission}/__init__.py +0 -0
- /zrb/{runner/web_controller/group_info_page → builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role}/__init__.py +0 -0
- /zrb/runner/{web_controller/home_page → web_route}/__init__.py +0 -0
- /zrb/runner/{web_controller/session_page → web_route/home_page}/__init__.py +0 -0
- /zrb/runner/{web_controller → web_route}/home_page/view.html +0 -0
- /zrb/runner/{web_controller → web_route}/login_page/view.html +0 -0
- /zrb/runner/{web_controller → web_route}/logout_page/view.html +0 -0
- /zrb/runner/{web_controller/group_info_page → web_route/node_page/group}/view.html +0 -0
- /zrb/runner/{web_controller/session_page → web_route/node_page/task}/partial/input.html +0 -0
- /zrb/runner/{web_controller/session_page → web_route/node_page/task}/view.html +0 -0
- /zrb/runner/{refresh-token.template.js → web_route/static/refresh-token.template.js} +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/common.css +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/favicon-32x32.png +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/login/event.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/logout/event.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/pico.min.css +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/common-util.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/current-session.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/event.js +0 -0
- /zrb/runner/{web_controller/static → web_route/static/resources}/session/past-session.js +0 -0
- {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/WHEEL +0 -0
- {zrb-1.0.0a21.dist-info → zrb-1.0.0b2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
import os
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from zrb.group.any_group import AnyGroup
|
5
|
+
from zrb.runner.web_config.config import WebConfig
|
6
|
+
from zrb.runner.web_util.html import get_html_auth_link
|
7
|
+
from zrb.runner.web_util.user import get_user_from_request
|
8
|
+
from zrb.util.file import read_file
|
9
|
+
from zrb.util.string.format import fstring_format
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
13
|
+
from fastapi import FastAPI
|
14
|
+
|
15
|
+
|
16
|
+
def serve_login_page(
|
17
|
+
app: "FastAPI",
|
18
|
+
root_group: AnyGroup,
|
19
|
+
web_config: WebConfig,
|
20
|
+
) -> None:
|
21
|
+
from fastapi import Request
|
22
|
+
from fastapi.responses import HTMLResponse
|
23
|
+
|
24
|
+
@app.get("/login", response_class=HTMLResponse, include_in_schema=False)
|
25
|
+
async def login(request: Request) -> HTMLResponse:
|
26
|
+
_DIR = os.path.dirname(__file__)
|
27
|
+
_VIEW_TEMPLATE = read_file(os.path.join(_DIR, "view.html"))
|
28
|
+
user = await get_user_from_request(web_config, request)
|
29
|
+
auth_link = get_html_auth_link(user)
|
30
|
+
return HTMLResponse(
|
31
|
+
fstring_format(
|
32
|
+
_VIEW_TEMPLATE,
|
33
|
+
{
|
34
|
+
"name": root_group.name,
|
35
|
+
"description": root_group.description,
|
36
|
+
"auth_link": auth_link,
|
37
|
+
},
|
38
|
+
)
|
39
|
+
)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from zrb.runner.web_config.config import WebConfig
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
7
|
+
from fastapi import FastAPI
|
8
|
+
|
9
|
+
|
10
|
+
def serve_logout_api(app: "FastAPI", web_config: WebConfig) -> None:
|
11
|
+
from fastapi import Response
|
12
|
+
|
13
|
+
@app.get("/api/v1/logout")
|
14
|
+
@app.post("/api/v1/logout")
|
15
|
+
async def logout_api(response: Response):
|
16
|
+
response.delete_cookie(web_config.access_token_cookie_name)
|
17
|
+
response.delete_cookie(web_config.refresh_token_cookie_name)
|
18
|
+
return {"message": "Logout successful"}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import os
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from zrb.group.any_group import AnyGroup
|
5
|
+
from zrb.runner.web_config.config import WebConfig
|
6
|
+
from zrb.runner.web_util.html import get_html_auth_link
|
7
|
+
from zrb.runner.web_util.user import get_user_from_request
|
8
|
+
from zrb.util.file import read_file
|
9
|
+
from zrb.util.string.format import fstring_format
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
13
|
+
from fastapi import FastAPI
|
14
|
+
|
15
|
+
|
16
|
+
def serve_logout_page(
|
17
|
+
app: "FastAPI",
|
18
|
+
root_group: AnyGroup,
|
19
|
+
web_config: WebConfig,
|
20
|
+
) -> None:
|
21
|
+
from fastapi import Request
|
22
|
+
from fastapi.responses import HTMLResponse
|
23
|
+
|
24
|
+
@app.get("/logout", response_class=HTMLResponse, include_in_schema=False)
|
25
|
+
async def logout(request: Request) -> HTMLResponse:
|
26
|
+
_DIR = os.path.dirname(__file__)
|
27
|
+
_VIEW_TEMPLATE = read_file(os.path.join(_DIR, "view.html"))
|
28
|
+
user = await get_user_from_request(web_config, request)
|
29
|
+
auth_link = get_html_auth_link(user)
|
30
|
+
return HTMLResponse(
|
31
|
+
fstring_format(
|
32
|
+
_VIEW_TEMPLATE,
|
33
|
+
{
|
34
|
+
"name": root_group.name,
|
35
|
+
"description": root_group.description,
|
36
|
+
"auth_link": auth_link,
|
37
|
+
"user": user,
|
38
|
+
},
|
39
|
+
)
|
40
|
+
)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import os
|
2
2
|
|
3
3
|
from zrb.group.any_group import AnyGroup
|
4
|
-
from zrb.runner.
|
5
|
-
from zrb.runner.web_util import (
|
4
|
+
from zrb.runner.web_schema.user import User
|
5
|
+
from zrb.runner.web_util.html import (
|
6
6
|
get_html_auth_link,
|
7
7
|
get_html_subgroup_info,
|
8
8
|
get_html_subtask_info,
|
@@ -11,7 +11,7 @@ from zrb.util.file import read_file
|
|
11
11
|
from zrb.util.string.format import fstring_format
|
12
12
|
|
13
13
|
|
14
|
-
def
|
14
|
+
def show_group_page(user: User, root_group: AnyGroup, group: AnyGroup, url: str):
|
15
15
|
from fastapi.responses import HTMLResponse
|
16
16
|
|
17
17
|
_DIR = os.path.dirname(__file__)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import os
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from zrb.context.shared_context import SharedContext
|
5
|
+
from zrb.group.any_group import AnyGroup
|
6
|
+
from zrb.runner.web_config.config import WebConfig
|
7
|
+
from zrb.runner.web_route.error_page.show_error_page import show_error_page
|
8
|
+
from zrb.runner.web_route.node_page.group.show_group_page import show_group_page
|
9
|
+
from zrb.runner.web_route.node_page.task.show_task_page import show_task_page
|
10
|
+
from zrb.runner.web_util.user import get_user_from_request
|
11
|
+
from zrb.session.session import Session
|
12
|
+
from zrb.task.any_task import AnyTask
|
13
|
+
from zrb.util.group import NodeNotFoundError, extract_node_from_args
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
17
|
+
from fastapi import FastAPI
|
18
|
+
|
19
|
+
|
20
|
+
def serve_node_page(
|
21
|
+
app: "FastAPI",
|
22
|
+
root_group: AnyGroup,
|
23
|
+
web_config: WebConfig,
|
24
|
+
) -> None:
|
25
|
+
from fastapi import Request
|
26
|
+
from fastapi.responses import HTMLResponse
|
27
|
+
|
28
|
+
@app.get("/ui/{path:path}", response_class=HTMLResponse, include_in_schema=False)
|
29
|
+
async def ui_page(path: str, request: Request) -> HTMLResponse:
|
30
|
+
user = await get_user_from_request(web_config, request)
|
31
|
+
# Avoid capturing '/ui' itself
|
32
|
+
if not path:
|
33
|
+
return show_error_page(user, root_group, 422, "Undefined path")
|
34
|
+
args = path.strip("/").split("/")
|
35
|
+
try:
|
36
|
+
node, node_path, residual_args = extract_node_from_args(root_group, args)
|
37
|
+
except NodeNotFoundError as e:
|
38
|
+
return show_error_page(user, root_group, 404, str(e))
|
39
|
+
url = f"/ui/{'/'.join(node_path)}/"
|
40
|
+
if isinstance(node, AnyTask):
|
41
|
+
if not user.can_access_task(node):
|
42
|
+
return show_error_page(user, root_group, 403, "Forbidden")
|
43
|
+
shared_ctx = SharedContext(env=dict(os.environ))
|
44
|
+
session = Session(shared_ctx=shared_ctx, root_group=root_group)
|
45
|
+
return show_task_page(user, root_group, node, session, url, residual_args)
|
46
|
+
elif isinstance(node, AnyGroup):
|
47
|
+
if not user.can_access_group(node):
|
48
|
+
return show_error_page(user, root_group, 403, "Forbidden")
|
49
|
+
return show_group_page(user, root_group, node, url)
|
50
|
+
return show_error_page(user, root_group, 404, "Not found")
|
zrb/runner/{web_controller/session_page/controller.py → web_route/node_page/task/show_task_page.py}
RENAMED
@@ -2,15 +2,15 @@ import json
|
|
2
2
|
import os
|
3
3
|
|
4
4
|
from zrb.group.any_group import AnyGroup
|
5
|
-
from zrb.runner.
|
6
|
-
from zrb.runner.web_util import get_html_auth_link
|
5
|
+
from zrb.runner.web_schema.user import User
|
6
|
+
from zrb.runner.web_util.html import get_html_auth_link
|
7
7
|
from zrb.session.any_session import AnySession
|
8
8
|
from zrb.task.any_task import AnyTask
|
9
9
|
from zrb.util.file import read_file
|
10
10
|
from zrb.util.string.format import fstring_format
|
11
11
|
|
12
12
|
|
13
|
-
def
|
13
|
+
def show_task_page(
|
14
14
|
user: User,
|
15
15
|
root_group: AnyGroup,
|
16
16
|
task: AnyTask,
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from zrb.runner.web_config.config import WebConfig
|
4
|
+
from zrb.runner.web_schema.token import RefreshTokenRequest
|
5
|
+
from zrb.runner.web_util.cookie import set_auth_cookie
|
6
|
+
from zrb.runner.web_util.token import regenerate_tokens
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
10
|
+
from fastapi import FastAPI
|
11
|
+
|
12
|
+
|
13
|
+
def serve_refresh_token_api(app: "FastAPI", web_config: WebConfig) -> None:
|
14
|
+
from fastapi import Cookie, Response
|
15
|
+
from fastapi.responses import JSONResponse
|
16
|
+
|
17
|
+
@app.post("/api/v1/refresh-token")
|
18
|
+
async def refresh_token_api(
|
19
|
+
response: Response,
|
20
|
+
body: RefreshTokenRequest = None,
|
21
|
+
refresh_token_cookie: str = Cookie(
|
22
|
+
None, alias=web_config.refresh_token_cookie_name
|
23
|
+
),
|
24
|
+
):
|
25
|
+
# Try to get the refresh token from the request body first
|
26
|
+
refresh_token = body.refresh_token if body else None
|
27
|
+
# If not in the body, try to get it from the cookie
|
28
|
+
if not refresh_token:
|
29
|
+
refresh_token = refresh_token_cookie
|
30
|
+
# If we still don't have a refresh token, raise an exception
|
31
|
+
if not refresh_token:
|
32
|
+
return JSONResponse(
|
33
|
+
content={"detail": "Refresh token not provided"}, status_code=400
|
34
|
+
)
|
35
|
+
# Get token
|
36
|
+
new_token = regenerate_tokens(web_config, refresh_token)
|
37
|
+
set_auth_cookie(web_config, response, new_token)
|
38
|
+
return new_token
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import os
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from zrb.runner.web_config.config import WebConfig
|
5
|
+
from zrb.util.file import read_file
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
9
|
+
from fastapi import FastAPI
|
10
|
+
|
11
|
+
|
12
|
+
def serve_static_resources(app: "FastAPI", web_config: WebConfig) -> None:
|
13
|
+
from fastapi import HTTPException
|
14
|
+
from fastapi.responses import FileResponse, PlainTextResponse
|
15
|
+
from fastapi.staticfiles import StaticFiles
|
16
|
+
|
17
|
+
_STATIC_DIR = os.path.join(os.path.dirname(__file__), "resources")
|
18
|
+
|
19
|
+
app.mount("/static", StaticFiles(directory=_STATIC_DIR), name="static")
|
20
|
+
|
21
|
+
# Serve static files
|
22
|
+
@app.get("/static/{file_path:path}", include_in_schema=False)
|
23
|
+
async def static_files(file_path: str):
|
24
|
+
full_path = os.path.join(_STATIC_DIR, file_path)
|
25
|
+
if os.path.isfile(full_path):
|
26
|
+
return FileResponse(full_path)
|
27
|
+
raise HTTPException(status_code=404, detail="File not found")
|
28
|
+
|
29
|
+
@app.get("/refresh-token.js", include_in_schema=False)
|
30
|
+
async def refresh_token_js():
|
31
|
+
return PlainTextResponse(
|
32
|
+
content=_get_refresh_token_js(
|
33
|
+
60 * web_config.refresh_token_expire_minutes / 3
|
34
|
+
),
|
35
|
+
media_type="application/javascript",
|
36
|
+
)
|
37
|
+
|
38
|
+
|
39
|
+
def _get_refresh_token_js(refresh_interval_seconds: int):
|
40
|
+
_DIR = os.path.dirname(__file__)
|
41
|
+
return read_file(
|
42
|
+
os.path.join(_DIR, "refresh-token.template.js"),
|
43
|
+
{"refreshIntervalSeconds": f"{refresh_interval_seconds}"},
|
44
|
+
)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import json
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from zrb.group.any_group import AnyGroup
|
5
|
+
from zrb.runner.common_util import get_run_kwargs
|
6
|
+
from zrb.runner.web_config.config import WebConfig
|
7
|
+
from zrb.runner.web_util.user import get_user_from_request
|
8
|
+
from zrb.task.any_task import AnyTask
|
9
|
+
from zrb.util.group import NodeNotFoundError, extract_node_from_args
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
13
|
+
from fastapi import FastAPI
|
14
|
+
|
15
|
+
|
16
|
+
def serve_task_input_api(
|
17
|
+
app: "FastAPI",
|
18
|
+
root_group: AnyGroup,
|
19
|
+
web_config: WebConfig,
|
20
|
+
) -> None:
|
21
|
+
from fastapi import Query, Request
|
22
|
+
from fastapi.responses import JSONResponse
|
23
|
+
|
24
|
+
@app.get("/api/v1/task-inputs/{path:path}", response_model=dict[str, str])
|
25
|
+
async def get_default_inputs_api(
|
26
|
+
path: str,
|
27
|
+
request: Request,
|
28
|
+
query: str = Query("{}", description="JSON encoded inputs"),
|
29
|
+
) -> dict[str, str]:
|
30
|
+
"""
|
31
|
+
Getting input completion for path
|
32
|
+
"""
|
33
|
+
user = await get_user_from_request(web_config, request)
|
34
|
+
args = path.strip("/").split("/")
|
35
|
+
try:
|
36
|
+
task, _, _ = extract_node_from_args(root_group, args)
|
37
|
+
except NodeNotFoundError:
|
38
|
+
return JSONResponse(content={"detail": "Not found"}, status_code=404)
|
39
|
+
if isinstance(task, AnyTask):
|
40
|
+
if not user.can_access_task(task):
|
41
|
+
return JSONResponse(content={"detail": "Forbidden"}, status_code=403)
|
42
|
+
query_dict = json.loads(query)
|
43
|
+
run_kwargs = get_run_kwargs(
|
44
|
+
task=task, args=[], kwargs=query_dict, prompt=False
|
45
|
+
)
|
46
|
+
return run_kwargs
|
47
|
+
return JSONResponse(content={"detail": "Not found"}, status_code=404)
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import asyncio
|
2
|
+
import os
|
3
|
+
from datetime import datetime, timedelta
|
4
|
+
from typing import TYPE_CHECKING, Any
|
5
|
+
|
6
|
+
from zrb.context.shared_context import SharedContext
|
7
|
+
from zrb.group.any_group import AnyGroup
|
8
|
+
from zrb.runner.web_config.config import WebConfig
|
9
|
+
from zrb.runner.web_schema.session import NewSessionResponse
|
10
|
+
from zrb.runner.web_util.user import get_user_from_request
|
11
|
+
from zrb.session.session import Session
|
12
|
+
from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
|
13
|
+
from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
|
14
|
+
from zrb.task.any_task import AnyTask
|
15
|
+
from zrb.util.group import NodeNotFoundError, extract_node_from_args, get_node_path
|
16
|
+
|
17
|
+
if TYPE_CHECKING:
|
18
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
19
|
+
|
20
|
+
from fastapi import FastAPI
|
21
|
+
|
22
|
+
|
23
|
+
def serve_task_session_api(
|
24
|
+
app: "FastAPI",
|
25
|
+
root_group: AnyGroup,
|
26
|
+
web_config: WebConfig,
|
27
|
+
session_state_logger: AnySessionStateLogger,
|
28
|
+
coroutines: list,
|
29
|
+
) -> None:
|
30
|
+
from fastapi import Query, Request
|
31
|
+
from fastapi.responses import JSONResponse
|
32
|
+
|
33
|
+
@app.post("/api/v1/task-sessions/{path:path}")
|
34
|
+
async def create_new_task_session_api(
|
35
|
+
path: str,
|
36
|
+
request: Request,
|
37
|
+
inputs: dict[str, Any],
|
38
|
+
) -> NewSessionResponse:
|
39
|
+
"""
|
40
|
+
Creating new session
|
41
|
+
"""
|
42
|
+
user = await get_user_from_request(web_config, request)
|
43
|
+
args = path.strip("/").split("/")
|
44
|
+
try:
|
45
|
+
task, _, residual_args = extract_node_from_args(root_group, args)
|
46
|
+
except NodeNotFoundError:
|
47
|
+
return JSONResponse(content={"detail": "Not found"}, status_code=404)
|
48
|
+
if isinstance(task, AnyTask):
|
49
|
+
if not user.can_access_task(task):
|
50
|
+
return JSONResponse(content={"detail": "Forbidden"}, status_code=403)
|
51
|
+
session_name = residual_args[0] if residual_args else None
|
52
|
+
if not session_name:
|
53
|
+
shared_ctx = SharedContext(env=dict(os.environ))
|
54
|
+
session = Session(shared_ctx=shared_ctx, root_group=root_group)
|
55
|
+
coro = asyncio.create_task(task.async_run(session, str_kwargs=inputs))
|
56
|
+
coroutines.append(coro)
|
57
|
+
coro.add_done_callback(lambda coro: coroutines.remove(coro))
|
58
|
+
return NewSessionResponse(session_name=session.name)
|
59
|
+
return JSONResponse(content={"detail": "Not found"}, status_code=404)
|
60
|
+
|
61
|
+
@app.get(
|
62
|
+
"/api/v1/task-sessions/{path:path}",
|
63
|
+
response_model=SessionStateLog | SessionStateLogList,
|
64
|
+
)
|
65
|
+
async def get_task_session_api(
|
66
|
+
path: str,
|
67
|
+
request: Request,
|
68
|
+
min_start_query: str = Query(default=None, alias="from"),
|
69
|
+
max_start_query: str = Query(default=None, alias="to"),
|
70
|
+
page: int = Query(default=0, alias="page"),
|
71
|
+
limit: int = Query(default=10, alias="limit"),
|
72
|
+
) -> SessionStateLog | SessionStateLogList:
|
73
|
+
"""
|
74
|
+
Getting existing session or sessions
|
75
|
+
"""
|
76
|
+
user = await get_user_from_request(web_config, request)
|
77
|
+
args = path.strip("/").split("/")
|
78
|
+
try:
|
79
|
+
task, _, residual_args = extract_node_from_args(root_group, args)
|
80
|
+
except NodeNotFoundError:
|
81
|
+
return JSONResponse(content={"detail": "Not found"}, status_code=404)
|
82
|
+
if isinstance(task, AnyTask) and residual_args:
|
83
|
+
if not user.can_access_task(task):
|
84
|
+
return JSONResponse(content={"detail": "Forbidden"}, status_code=403)
|
85
|
+
if residual_args[0] == "list":
|
86
|
+
task_path = get_node_path(root_group, task)
|
87
|
+
max_start_time = (
|
88
|
+
datetime.now()
|
89
|
+
if max_start_query is None
|
90
|
+
else datetime.strptime(max_start_query, "%Y-%m-%d %H:%M:%S")
|
91
|
+
)
|
92
|
+
min_start_time = (
|
93
|
+
max_start_time - timedelta(hours=1)
|
94
|
+
if min_start_query is None
|
95
|
+
else datetime.strptime(min_start_query, "%Y-%m-%d %H:%M:%S")
|
96
|
+
)
|
97
|
+
return session_state_logger.list(
|
98
|
+
task_path, min_start_time, max_start_time, page, limit
|
99
|
+
)
|
100
|
+
else:
|
101
|
+
return session_state_logger.read(residual_args[0])
|
102
|
+
return JSONResponse(content={"detail": "Not found"}, status_code=404)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from pydantic import BaseModel, ConfigDict
|
2
|
+
|
3
|
+
from zrb.group.any_group import AnyGroup
|
4
|
+
from zrb.task.any_task import AnyTask
|
5
|
+
from zrb.util.group import get_all_subtasks
|
6
|
+
|
7
|
+
|
8
|
+
class User(BaseModel):
|
9
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
10
|
+
username: str
|
11
|
+
password: str = ""
|
12
|
+
is_super_admin: bool = False
|
13
|
+
is_guest: bool = False
|
14
|
+
accessible_tasks: list[AnyTask | str] = []
|
15
|
+
|
16
|
+
def is_password_match(self, password: str) -> bool:
|
17
|
+
return self.password == password
|
18
|
+
|
19
|
+
def can_access_group(self, group: AnyGroup) -> bool:
|
20
|
+
if self.is_super_admin:
|
21
|
+
return True
|
22
|
+
all_tasks = get_all_subtasks(group, web_only=True)
|
23
|
+
if any(self.can_access_task(task) for task in all_tasks):
|
24
|
+
return True
|
25
|
+
return False
|
26
|
+
|
27
|
+
def can_access_task(self, task: AnyTask) -> bool:
|
28
|
+
if self.is_super_admin:
|
29
|
+
return True
|
30
|
+
if task.name in self.accessible_tasks or task in self.accessible_tasks:
|
31
|
+
return True
|
32
|
+
return False
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from datetime import datetime, timedelta, timezone
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from zrb.runner.web_config.config import WebConfig
|
5
|
+
from zrb.runner.web_schema.token import Token
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
# We want fastapi to only be loaded when necessary to decrease footprint
|
9
|
+
from fastapi import Response
|
10
|
+
|
11
|
+
|
12
|
+
def set_auth_cookie(web_config: WebConfig, response: "Response", token: Token):
|
13
|
+
access_token_max_age = web_config.access_token_expire_minutes * 60
|
14
|
+
refresh_token_max_age = web_config.refresh_token_expire_minutes * 60
|
15
|
+
now = datetime.now(timezone.utc)
|
16
|
+
response.set_cookie(
|
17
|
+
key=web_config.access_token_cookie_name,
|
18
|
+
value=token.access_token,
|
19
|
+
httponly=True,
|
20
|
+
max_age=access_token_max_age,
|
21
|
+
expires=now + timedelta(seconds=access_token_max_age),
|
22
|
+
)
|
23
|
+
response.set_cookie(
|
24
|
+
key=web_config.refresh_token_cookie_name,
|
25
|
+
value=token.refresh_token,
|
26
|
+
httponly=True,
|
27
|
+
max_age=refresh_token_max_age,
|
28
|
+
expires=now + timedelta(seconds=refresh_token_max_age),
|
29
|
+
)
|
@@ -1,23 +1,9 @@
|
|
1
|
-
import os
|
2
|
-
|
3
1
|
from zrb.group.any_group import AnyGroup
|
4
|
-
from zrb.runner.
|
2
|
+
from zrb.runner.web_schema.user import User
|
5
3
|
from zrb.task.any_task import AnyTask
|
6
|
-
from zrb.util.file import read_file
|
7
4
|
from zrb.util.group import get_non_empty_subgroups, get_subtasks
|
8
5
|
|
9
6
|
|
10
|
-
def url_to_args(url: str) -> list[str]:
|
11
|
-
stripped_url = url.strip("/")
|
12
|
-
return [part for part in stripped_url.split("/") if part.strip() != ""]
|
13
|
-
|
14
|
-
|
15
|
-
def node_path_to_url(args: list[str]) -> str:
|
16
|
-
pruned_args = [part for part in args if part.strip() != ""]
|
17
|
-
stripped_url = "/".join(pruned_args)
|
18
|
-
return f"/{stripped_url}/"
|
19
|
-
|
20
|
-
|
21
7
|
def get_html_auth_link(user: User) -> str:
|
22
8
|
if user.is_guest and user.is_super_admin:
|
23
9
|
return f"Hi, {user.username}"
|
@@ -26,14 +12,6 @@ def get_html_auth_link(user: User) -> str:
|
|
26
12
|
return f'Hi, {user.username} <a href="/logout">Logout 🚪</a>'
|
27
13
|
|
28
14
|
|
29
|
-
def get_refresh_token_js(refresh_interval_seconds: int):
|
30
|
-
_DIR = os.path.dirname(__file__)
|
31
|
-
return read_file(
|
32
|
-
os.path.join(_DIR, "refresh-token.template.js"),
|
33
|
-
{"refreshIntervalSeconds": f"{refresh_interval_seconds}"},
|
34
|
-
)
|
35
|
-
|
36
|
-
|
37
15
|
def get_html_subtask_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
|
38
16
|
subtasks = get_subtasks(parent_group, web_only=True)
|
39
17
|
task_li = "\n".join(
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from datetime import datetime, timedelta, timezone
|
2
|
+
|
3
|
+
from zrb.runner.web_config.config import WebConfig
|
4
|
+
from zrb.runner.web_schema.token import Token
|
5
|
+
from zrb.runner.web_util.user import get_user_by_credentials
|
6
|
+
|
7
|
+
|
8
|
+
def generate_tokens_by_credentials(
|
9
|
+
web_config: WebConfig, username: str, password: str
|
10
|
+
) -> Token | None:
|
11
|
+
if not web_config.enable_auth:
|
12
|
+
user = web_config.default_user
|
13
|
+
else:
|
14
|
+
user = get_user_by_credentials(web_config, username, password)
|
15
|
+
if user is None:
|
16
|
+
return None
|
17
|
+
access_token = _generate_access_token(web_config, user.username)
|
18
|
+
refresh_token = _generate_refresh_token(web_config, user.username)
|
19
|
+
return Token(
|
20
|
+
access_token=access_token, refresh_token=refresh_token, token_type="bearer"
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
def regenerate_tokens(web_config: WebConfig, refresh_token: str) -> Token:
|
25
|
+
from fastapi import HTTPException
|
26
|
+
from jose import jwt
|
27
|
+
|
28
|
+
# Decode and validate token
|
29
|
+
try:
|
30
|
+
payload = jwt.decode(
|
31
|
+
refresh_token,
|
32
|
+
web_config.secret_key,
|
33
|
+
options={"require_exp": True, "require_sub": True},
|
34
|
+
)
|
35
|
+
except Exception:
|
36
|
+
raise HTTPException(status_code=401, detail="Invalid JWT token")
|
37
|
+
if payload.get("type") != "refresh":
|
38
|
+
raise HTTPException(status_code=401, detail="Invalid token type")
|
39
|
+
username: str = payload.get("sub")
|
40
|
+
if username is None:
|
41
|
+
raise HTTPException(status_code=401, detail="Invalid refresh token")
|
42
|
+
user = web_config.find_user_by_username(username)
|
43
|
+
if user is None:
|
44
|
+
raise HTTPException(status_code=401, detail="User not found")
|
45
|
+
# Create new token
|
46
|
+
new_access_token = _generate_access_token(web_config, username)
|
47
|
+
new_refresh_token = _generate_refresh_token(web_config, username)
|
48
|
+
return Token(
|
49
|
+
access_token=new_access_token,
|
50
|
+
refresh_token=new_refresh_token,
|
51
|
+
token_type="bearer",
|
52
|
+
)
|
53
|
+
|
54
|
+
|
55
|
+
def _generate_access_token(web_config: WebConfig, username: str) -> str:
|
56
|
+
from jose import jwt
|
57
|
+
|
58
|
+
expire = datetime.now(timezone.utc) + timedelta(
|
59
|
+
minutes=web_config.access_token_expire_minutes
|
60
|
+
)
|
61
|
+
to_encode = {"sub": username, "exp": expire, "type": "access"}
|
62
|
+
return jwt.encode(to_encode, web_config.secret_key)
|
63
|
+
|
64
|
+
|
65
|
+
def _generate_refresh_token(web_config: WebConfig, username: str) -> str:
|
66
|
+
from jose import jwt
|
67
|
+
|
68
|
+
expire = datetime.now(timezone.utc) + timedelta(
|
69
|
+
minutes=web_config.refresh_token_expire_minutes
|
70
|
+
)
|
71
|
+
to_encode = {"sub": username, "exp": expire, "type": "refresh"}
|
72
|
+
return jwt.encode(to_encode, web_config.secret_key)
|