zrb 1.0.0b10__py3-none-any.whl → 1.2.0__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 (61) hide show
  1. zrb/builtin/git.py +8 -8
  2. zrb/builtin/llm/llm_chat.py +3 -3
  3. zrb/builtin/project/add/fastapp/fastapp_input.py +1 -1
  4. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_task.py +99 -55
  5. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_util.py +301 -0
  6. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +24 -1
  7. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +61 -1
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/gateway/view/content/my-module/my-entity.html +297 -0
  9. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/gateway_subroute.py +24 -0
  10. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/navigation_config_file.py +8 -0
  11. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/input.py +3 -3
  12. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +8 -0
  13. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +40 -1
  14. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py +2 -0
  15. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/navigation_config_file.py +6 -0
  16. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/parser.py +2 -2
  17. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/util/view.py +1 -1
  18. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/config.py +18 -8
  19. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/config/navigation.py +39 -0
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +52 -11
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/schema/navigation.py +95 -0
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +91 -8
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/auth.py +9 -0
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/util/view.py +33 -8
  25. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/auth/permission.html +311 -0
  26. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/auth/role.html +0 -0
  27. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/auth/user.html +0 -0
  28. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/error.html +4 -1
  29. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/login.html +67 -0
  30. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/content/logout.html +49 -0
  31. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/common/util.js +160 -0
  32. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/crud/style.css +14 -0
  33. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/crud/util.js +94 -0
  34. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/default/pico-style.css +23 -0
  35. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/default/script.js +44 -0
  36. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/default/style.css +102 -0
  37. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html +73 -18
  38. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +1 -1
  39. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_homepage.py +2 -4
  40. zrb/builtin/project/create/project_task.py +2 -2
  41. zrb/builtin/random.py +3 -3
  42. zrb/builtin/setup/common_input.py +5 -5
  43. zrb/builtin/setup/tmux/tmux.py +1 -1
  44. zrb/builtin/setup/zsh/zsh.py +1 -1
  45. zrb/builtin/todo.py +4 -4
  46. zrb/input/base_input.py +17 -12
  47. zrb/input/bool_input.py +12 -5
  48. zrb/input/float_input.py +12 -5
  49. zrb/input/int_input.py +12 -5
  50. zrb/input/option_input.py +5 -5
  51. zrb/input/password_input.py +5 -5
  52. zrb/input/text_input.py +4 -4
  53. zrb/runner/web_route/refresh_token_api_route.py +1 -1
  54. zrb/runner/web_route/static/refresh-token.template.js +9 -0
  55. zrb/runner/web_route/static/static_route.py +1 -1
  56. zrb/util/load.py +13 -7
  57. {zrb-1.0.0b10.dist-info → zrb-1.2.0.dist-info}/METADATA +2 -2
  58. {zrb-1.0.0b10.dist-info → zrb-1.2.0.dist-info}/RECORD +60 -44
  59. zrb/util/llm/tool.py +0 -87
  60. {zrb-1.0.0b10.dist-info → zrb-1.2.0.dist-info}/WHEEL +0 -0
  61. {zrb-1.0.0b10.dist-info → zrb-1.2.0.dist-info}/entry_points.txt +0 -0
@@ -1,18 +1,21 @@
1
- import os
1
+ from typing import Annotated
2
2
 
3
- from fastapi import FastAPI, HTTPException, Request
3
+ from fastapi import Depends, FastAPI, HTTPException, Request
4
4
  from fastapi.exception_handlers import http_exception_handler
5
- from fastapi.responses import HTMLResponse
5
+ from fastapi.responses import HTMLResponse, RedirectResponse
6
6
  from my_app_name.common.app_factory import app
7
7
  from my_app_name.common.schema import BasicResponse
8
8
  from my_app_name.config import (
9
- APP_GATEWAY_VIEW_PATH,
9
+ APP_AUTH_ACCESS_TOKEN_COOKIE_NAME,
10
10
  APP_MAIN_MODULE,
11
11
  APP_MODE,
12
12
  APP_MODULES,
13
13
  )
14
+ from my_app_name.module.auth.client.auth_client_factory import auth_client
14
15
  from my_app_name.module.gateway.subroute.auth import serve_auth_route
15
- from my_app_name.module.gateway.util.view import render, render_error
16
+ from my_app_name.module.gateway.util.auth import get_current_user
17
+ from my_app_name.module.gateway.util.view import render_content, render_error
18
+ from my_app_name.schema.user import AuthUserResponse
16
19
 
17
20
 
18
21
  def serve_route(app: FastAPI):
@@ -21,18 +24,48 @@ def serve_route(app: FastAPI):
21
24
  if APP_MODE == "monolith" or APP_MAIN_MODULE == "gateway":
22
25
  _serve_health_check(app)
23
26
  _serve_readiness_check(app)
24
- _serve_homepage(app)
27
+ _serve_common_pages(app)
25
28
  _handle_404(app)
26
29
 
27
30
  # Serve auth routes
28
31
  serve_auth_route(app)
29
32
 
30
33
 
31
- def _serve_homepage(app: FastAPI):
34
+ def _serve_common_pages(app: FastAPI):
32
35
  @app.get("/", include_in_schema=False)
33
- def home_page():
34
- return render(
35
- view_path=os.path.join(APP_GATEWAY_VIEW_PATH, "content", "homepage.html")
36
+ def home_page(
37
+ current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
38
+ ):
39
+ return render_content(
40
+ view_path="homepage.html",
41
+ current_user=current_user,
42
+ page_name="gateway.home",
43
+ )
44
+
45
+ @app.get("/login", include_in_schema=False)
46
+ def login_page(
47
+ current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
48
+ ):
49
+ if not current_user.is_guest:
50
+ return RedirectResponse("/")
51
+ return render_content(
52
+ view_path="login.html",
53
+ current_user=current_user,
54
+ page_name="gateway.home",
55
+ partials={"show_user_info": False},
56
+ )
57
+
58
+ @app.get("/logout", include_in_schema=False)
59
+ def logout_page(
60
+ current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
61
+ ):
62
+ if current_user is None:
63
+ return RedirectResponse("/")
64
+ return render_content(
65
+ view_path="logout.html",
66
+ current_user=current_user,
67
+ page_name="gateway.home",
68
+ partials={"show_user_info": False},
36
69
  )
37
70
 
38
71
 
@@ -60,7 +93,15 @@ def _handle_404(app: FastAPI):
60
93
  if request.url.path.startswith("/api"):
61
94
  # Re-raise the exception to let FastAPI handle it
62
95
  return await http_exception_handler(request, exc)
63
- return render_error(error_message="Not found", status_code=404)
96
+ # Get current user by cookies
97
+ current_user = None
98
+ cookie_access_token = request.cookies.get(APP_AUTH_ACCESS_TOKEN_COOKIE_NAME)
99
+ if cookie_access_token is not None and cookie_access_token != "":
100
+ current_user = await auth_client.get_current_user(cookie_access_token)
101
+ # Show error page
102
+ return render_error(
103
+ error_message="Not found", status_code=404, current_user=current_user
104
+ )
64
105
 
65
106
 
66
107
  serve_route(app)
@@ -0,0 +1,95 @@
1
+ from my_app_name.schema.user import AuthUserResponse
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class Page(BaseModel):
6
+ name: str
7
+ caption: str
8
+ url: str
9
+ permission: str | None = None
10
+
11
+
12
+ class AccessiblePage(BaseModel):
13
+ name: str
14
+ caption: str
15
+ url: str
16
+ active: bool
17
+
18
+
19
+ class PageGroup(BaseModel):
20
+ name: str
21
+ caption: str
22
+ pages: list[Page] = []
23
+
24
+ def append_page(self, submenu: Page) -> Page:
25
+ self.pages.append(submenu)
26
+ return submenu
27
+
28
+ def get_accessible_pages(
29
+ self, submenu_name: str | None = None, user: AuthUserResponse | None = None
30
+ ) -> list[AccessiblePage]:
31
+ return [
32
+ AccessiblePage(
33
+ name=page.name,
34
+ caption=page.caption,
35
+ url=page.url,
36
+ active=page.name == submenu_name,
37
+ )
38
+ for page in self.pages
39
+ if _has_permission(user, page.permission)
40
+ ]
41
+
42
+
43
+ class AccessiblePageGroup(BaseModel):
44
+ name: str
45
+ caption: str
46
+ pages: list[AccessiblePage]
47
+ active: bool
48
+
49
+
50
+ class Navigation(BaseModel):
51
+ items: list[PageGroup | Page] = []
52
+
53
+ def append_page_group(self, page_group: PageGroup) -> PageGroup:
54
+ self.items.append(page_group)
55
+ return page_group
56
+
57
+ def append_page(self, page: Page) -> Page:
58
+ self.items.append(page)
59
+ return page
60
+
61
+ def get_accessible_items(
62
+ self, page_name: str | None, user: AuthUserResponse | None
63
+ ) -> list[AccessiblePageGroup | AccessiblePage]:
64
+ accessible_items = []
65
+ for item in self.items:
66
+ if isinstance(item, Page) and _has_permission(user, item.permission):
67
+ accessible_items.append(
68
+ AccessiblePage(
69
+ name=item.name,
70
+ caption=item.caption,
71
+ url=item.url,
72
+ active=item.name == page_name,
73
+ )
74
+ )
75
+ continue
76
+ accessible_submenus = item.get_accessible_pages(page_name, user)
77
+ if accessible_submenus:
78
+ active = any(submenu.active for submenu in accessible_submenus)
79
+ accessible_items.append(
80
+ AccessiblePageGroup(
81
+ name=item.name,
82
+ caption=item.caption,
83
+ pages=accessible_submenus,
84
+ active=active,
85
+ )
86
+ )
87
+ return accessible_items
88
+
89
+
90
+ def _has_permission(user: AuthUserResponse | None, permission: str | None):
91
+ if permission is None:
92
+ return True
93
+ if user is not None:
94
+ return user.has_permission(permission)
95
+ return False
@@ -1,14 +1,17 @@
1
+ import os
1
2
  from typing import Annotated
2
3
 
3
- from fastapi import Depends, FastAPI, Response
4
+ from fastapi import Depends, FastAPI, Request, Response
4
5
  from fastapi.security import OAuth2PasswordRequestForm
5
- from my_app_name.common.error import ForbiddenError
6
+ from my_app_name.common.error import ForbiddenError, NotFoundError
6
7
  from my_app_name.module.auth.client.auth_client_factory import auth_client
7
8
  from my_app_name.module.gateway.util.auth import (
8
9
  get_current_user,
10
+ get_refresh_token,
9
11
  set_user_session_cookie,
10
12
  unset_user_session_cookie,
11
13
  )
14
+ from my_app_name.module.gateway.util.view import render_content, render_error
12
15
  from my_app_name.schema.permission import (
13
16
  MultiplePermissionResponse,
14
17
  PermissionCreate,
@@ -49,22 +52,56 @@ def serve_auth_route(app: FastAPI):
49
52
 
50
53
  @app.put("/api/v1/user-sessions", response_model=UserSessionResponse)
51
54
  async def update_user_session(
52
- response: Response, refresh_token: str
55
+ request: Request, response: Response, refresh_token: str | None = None
53
56
  ) -> UserSessionResponse:
54
- user_session = await auth_client.update_user_session(refresh_token)
57
+ actual_refresh_token = get_refresh_token(request, refresh_token)
58
+ if actual_refresh_token is None:
59
+ raise ForbiddenError("Refresh token needed")
60
+ try:
61
+ user_session = await auth_client.update_user_session(actual_refresh_token)
62
+ except NotFoundError:
63
+ raise ForbiddenError("Session not found")
55
64
  set_user_session_cookie(response, user_session)
56
65
  return user_session
57
66
 
58
67
  @app.delete("/api/v1/user-sessions", response_model=UserSessionResponse)
59
68
  async def delete_user_session(
60
- response: Response, refresh_token: str
69
+ request: Request, response: Response, refresh_token: str | None = None
61
70
  ) -> UserSessionResponse:
62
- user_session = await auth_client.delete_user_session(refresh_token)
63
- unset_user_session_cookie(response)
64
- return user_session
71
+ try:
72
+ actual_refresh_token = get_refresh_token(request, refresh_token)
73
+ if actual_refresh_token is None:
74
+ raise ForbiddenError("Refresh token needed")
75
+ user_session = await auth_client.delete_user_session(actual_refresh_token)
76
+ return user_session
77
+ finally:
78
+ unset_user_session_cookie(response)
65
79
 
66
80
  # Permission routes
67
81
 
82
+ @app.get("/auth/permissions", include_in_schema=False)
83
+ def permissions_crud_ui(
84
+ current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
85
+ page: int = 1,
86
+ page_size: int = 10,
87
+ sort: str | None = None,
88
+ filter: str | None = None,
89
+ ):
90
+ if not current_user.has_permission("permission:read"):
91
+ return render_error(error_message="Access denied", status_code=403)
92
+ return render_content(
93
+ view_path=os.path.join("auth", "permission.html"),
94
+ current_user=current_user,
95
+ page_name="auth.permission",
96
+ page=page,
97
+ page_size=page_size,
98
+ sort=sort,
99
+ filter=filter,
100
+ allow_create=current_user.has_permission("permission:create"),
101
+ allow_update=current_user.has_permission("permission:update"),
102
+ allow_delete=current_user.has_permission("permission:delete"),
103
+ )
104
+
68
105
  @app.get("/api/v1/permissions", response_model=MultiplePermissionResponse)
69
106
  async def get_permissions(
70
107
  current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
@@ -176,6 +213,29 @@ def serve_auth_route(app: FastAPI):
176
213
 
177
214
  # Role routes
178
215
 
216
+ @app.get("/auth/roles", include_in_schema=False)
217
+ def roles_crud_ui(
218
+ current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
219
+ page: int = 1,
220
+ page_size: int = 10,
221
+ sort: str | None = None,
222
+ filter: str | None = None,
223
+ ):
224
+ if not current_user.has_permission("role:read"):
225
+ return render_error(error_message="Access denied", status_code=403)
226
+ return render_content(
227
+ view_path=os.path.join("auth", "role.html"),
228
+ current_user=current_user,
229
+ page_name="auth.role",
230
+ page=page,
231
+ page_size=page_size,
232
+ sort=sort,
233
+ filter=filter,
234
+ allow_create=current_user.has_permission("role:create"),
235
+ allow_update=current_user.has_permission("role:update"),
236
+ allow_delete=current_user.has_permission("role:delete"),
237
+ )
238
+
179
239
  @app.get("/api/v1/roles", response_model=MultipleRoleResponse)
180
240
  async def get_roles(
181
241
  current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
@@ -283,6 +343,29 @@ def serve_auth_route(app: FastAPI):
283
343
 
284
344
  # User routes
285
345
 
346
+ @app.get("/auth/users", include_in_schema=False)
347
+ def users_crud_ui(
348
+ current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
349
+ page: int = 1,
350
+ page_size: int = 10,
351
+ sort: str | None = None,
352
+ filter: str | None = None,
353
+ ):
354
+ if not current_user.has_permission("user:read"):
355
+ return render_error(error_message="Access denied", status_code=403)
356
+ return render_content(
357
+ view_path=os.path.join("auth", "user.html"),
358
+ current_user=current_user,
359
+ page_name="auth.user",
360
+ page=page,
361
+ page_size=page_size,
362
+ sort=sort,
363
+ filter=filter,
364
+ allow_create=current_user.has_permission("user:create"),
365
+ allow_update=current_user.has_permission("user:update"),
366
+ allow_delete=current_user.has_permission("user:delete"),
367
+ )
368
+
286
369
  @app.get("/api/v1/users", response_model=MultipleUserResponse)
287
370
  async def get_users(
288
371
  current_user: Annotated[AuthUserResponse, Depends(get_current_user)],
@@ -15,6 +15,15 @@ from typing_extensions import Annotated
15
15
  oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/user-sessions", auto_error=False)
16
16
 
17
17
 
18
+ def get_refresh_token(request: Request, refresh_token: str | None) -> str | None:
19
+ if refresh_token is not None and refresh_token != "":
20
+ return refresh_token
21
+ cookie_refresh_token = request.cookies.get(APP_AUTH_REFRESH_TOKEN_COOKIE_NAME)
22
+ if cookie_refresh_token is not None and cookie_refresh_token != "":
23
+ return cookie_refresh_token
24
+ return None
25
+
26
+
18
27
  async def get_current_user(
19
28
  request: Request,
20
29
  response: Response,
@@ -1,18 +1,24 @@
1
1
  import os
2
2
  from typing import Any
3
3
 
4
+ import my_app_name.config as CFG
4
5
  from fastapi.responses import HTMLResponse
5
6
  from my_app_name.common.util.view import render_page, render_str
6
7
  from my_app_name.config import (
8
+ APP_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES,
7
9
  APP_GATEWAY_CSS_PATH_LIST,
8
10
  APP_GATEWAY_FAVICON_PATH,
11
+ APP_GATEWAY_FOOTER,
9
12
  APP_GATEWAY_JS_PATH_LIST,
10
13
  APP_GATEWAY_LOGO_PATH,
14
+ APP_GATEWAY_PICO_CSS_PATH,
11
15
  APP_GATEWAY_SUBTITLE,
12
16
  APP_GATEWAY_TITLE,
13
17
  APP_GATEWAY_VIEW_DEFAULT_TEMPLATE_PATH,
14
18
  APP_GATEWAY_VIEW_PATH,
15
19
  )
20
+ from my_app_name.module.gateway.config.navigation import APP_NAVIGATION
21
+ from my_app_name.schema.user import AuthUserResponse
16
22
 
17
23
  _DEFAULT_TEMPLATE_PATH = os.path.join(
18
24
  APP_GATEWAY_VIEW_PATH, APP_GATEWAY_VIEW_DEFAULT_TEMPLATE_PATH
@@ -24,32 +30,47 @@ _DEFAULT_ERROR_TEMPLATE_PATH = os.path.join(
24
30
  _DEFAULT_PARTIALS = {
25
31
  "title": APP_GATEWAY_TITLE,
26
32
  "subtitle": APP_GATEWAY_SUBTITLE,
33
+ "footer": APP_GATEWAY_FOOTER,
27
34
  "logo_path": APP_GATEWAY_LOGO_PATH,
28
35
  "favicon_path": APP_GATEWAY_FAVICON_PATH,
36
+ "pico_css_path": APP_GATEWAY_PICO_CSS_PATH,
29
37
  "css_path_list": APP_GATEWAY_CSS_PATH_LIST,
30
38
  "js_path_list": APP_GATEWAY_JS_PATH_LIST,
39
+ "show_user_info": True,
40
+ "should_refresh_session": True,
41
+ "refresh_session_interval_seconds": f"{APP_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES * 60 / 3}",
31
42
  }
32
43
 
33
44
 
34
- def render(
45
+ def render_content(
35
46
  view_path: str,
36
47
  template_path: str = _DEFAULT_TEMPLATE_PATH,
37
48
  status_code: int = 200,
38
- headers: dict[str, str] = None,
49
+ headers: dict[str, str] | None = None,
39
50
  media_type: str | None = None,
51
+ current_user: AuthUserResponse | None = None,
52
+ page_name: str | None = None,
40
53
  partials: dict[str, Any] = {},
41
- **data: Any
54
+ **data: Any,
42
55
  ) -> HTMLResponse:
43
56
  rendered_partials = {key: val for key, val in _DEFAULT_PARTIALS.items()}
44
57
  for key, val in partials.items():
45
58
  rendered_partials[key] = val
59
+ rendered_partials["page_name"] = page_name
60
+ rendered_partials["current_user"] = current_user
61
+ rendered_partials["navigations"] = APP_NAVIGATION.get_accessible_items(
62
+ page_name, current_user
63
+ )
46
64
  return render_page(
47
65
  template_path=template_path,
48
66
  status_code=status_code,
49
67
  headers=headers,
50
68
  media_type=media_type,
51
- partials=rendered_partials,
52
- content=render_str(template_path=view_path, **data),
69
+ content=render_str(
70
+ template_path=os.path.join(APP_GATEWAY_VIEW_PATH, "content", view_path),
71
+ **data,
72
+ ),
73
+ **rendered_partials,
53
74
  )
54
75
 
55
76
 
@@ -58,17 +79,21 @@ def render_error(
58
79
  status_code: int = 500,
59
80
  view_path: str = _DEFAULT_ERROR_TEMPLATE_PATH,
60
81
  template_path: str = _DEFAULT_TEMPLATE_PATH,
61
- headers: dict[str, str] = None,
82
+ headers: dict[str, str] | None = None,
62
83
  media_type: str | None = None,
84
+ current_user: AuthUserResponse | None = None,
85
+ page_name: str | None = None,
63
86
  partials: dict[str, Any] = {},
64
87
  ):
65
- return render(
88
+ return render_content(
66
89
  view_path=view_path,
67
90
  template_path=template_path,
68
91
  status_code=status_code,
69
92
  headers=headers,
70
93
  media_type=media_type,
71
- partials=partials,
94
+ current_user=current_user,
95
+ page_name=page_name,
96
+ partials={"show_user_info": False, **partials},
72
97
  error_status_code=status_code,
73
98
  error_message=error_message,
74
99
  )