fix(server): 修正宿主机免登录模式文件服务路由的工作区解析
/user_upload/ 与 /workspace/ 路由此前误用 user_manager 的 users/<user>/projects/<id> 结构,宿主机免登录模式下解析到空工作区, 导致已上传文件 404(show_image 引用上传目录图片加载失败)。 改为与 get_user_resources 同源的 host_workspaces.json 解析。 Co-authored-by: Astrion powered by Kimi-K3 <astrion-agent@users.noreply.github.com>
This commit is contained in:
parent
b3158913ef
commit
92e4931408
@ -441,17 +441,48 @@ def terminal_page():
|
|||||||
return current_app.send_static_file('terminal.html')
|
return current_app.send_static_file('terminal.html')
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_serving_workspace_roots(user):
|
||||||
|
"""返回 (uploads_dir, project_root),供 /user_upload/ 与 /workspace/ 文件服务路由使用。
|
||||||
|
|
||||||
|
宿主机免登录模式(host_mode session)必须与 get_user_resources 走同一套
|
||||||
|
host_workspaces.json 解析:上传文件实际存放在宿主机工作区目录的
|
||||||
|
.astrion/user_upload 下。若误用 user_manager 的 users/<user>/projects/<id>
|
||||||
|
结构,会解析到一个空工作区,导致已上传文件 404(show_image 引用上传目录
|
||||||
|
图片时加载失败)。
|
||||||
|
"""
|
||||||
|
host_mode_session = bool(session.get("host_mode"))
|
||||||
|
sandbox_is_host = (TERMINAL_SANDBOX_MODE or "").lower() == "host"
|
||||||
|
if host_mode_session and sandbox_is_host:
|
||||||
|
selected_workspace_id = session.get("host_workspace_id") or session.get("workspace_id")
|
||||||
|
active_workspace_path = None
|
||||||
|
if not selected_workspace_id:
|
||||||
|
with state.HOST_ACTIVE_WORKSPACE_LOCK:
|
||||||
|
selected_workspace_id = state.HOST_ACTIVE_WORKSPACE_ID
|
||||||
|
active_workspace_path = state.HOST_ACTIVE_WORKSPACE_PATH
|
||||||
|
_, host_workspace = resolve_host_workspace(selected_workspace_id)
|
||||||
|
if not host_workspace:
|
||||||
|
return None, None
|
||||||
|
if active_workspace_path:
|
||||||
|
host_workspace = dict(host_workspace)
|
||||||
|
host_workspace["path"] = active_workspace_path
|
||||||
|
project_root = Path(host_workspace.get("path") or "").expanduser().resolve()
|
||||||
|
return (project_root / ".astrion" / "user_upload").resolve(), project_root
|
||||||
|
workspace = state.user_manager.ensure_user_workspace(
|
||||||
|
user.username,
|
||||||
|
session.get("workspace_id") or "default",
|
||||||
|
)
|
||||||
|
return workspace.uploads_dir.resolve(), workspace.project_path.resolve()
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route('/user_upload/<path:filename>')
|
@auth_bp.route('/user_upload/<path:filename>')
|
||||||
@login_required
|
@login_required
|
||||||
def serve_user_upload(filename: str):
|
def serve_user_upload(filename: str):
|
||||||
user = get_current_user_record()
|
user = get_current_user_record()
|
||||||
if not user:
|
if not user:
|
||||||
return redirect('/login')
|
return redirect('/login')
|
||||||
workspace = state.user_manager.ensure_user_workspace(
|
uploads_dir, _project_root = _resolve_serving_workspace_roots(user)
|
||||||
user.username,
|
if not uploads_dir:
|
||||||
session.get("workspace_id") or "default",
|
abort(404)
|
||||||
)
|
|
||||||
uploads_dir = workspace.uploads_dir.resolve()
|
|
||||||
target = (uploads_dir / filename).resolve()
|
target = (uploads_dir / filename).resolve()
|
||||||
try:
|
try:
|
||||||
target.relative_to(uploads_dir)
|
target.relative_to(uploads_dir)
|
||||||
@ -468,11 +499,9 @@ def serve_workspace_file(filename: str):
|
|||||||
user = get_current_user_record()
|
user = get_current_user_record()
|
||||||
if not user:
|
if not user:
|
||||||
return redirect('/login')
|
return redirect('/login')
|
||||||
workspace = state.user_manager.ensure_user_workspace(
|
_uploads_dir, project_root = _resolve_serving_workspace_roots(user)
|
||||||
user.username,
|
if not project_root:
|
||||||
session.get("workspace_id") or "default",
|
abort(404)
|
||||||
)
|
|
||||||
project_root = workspace.project_path.resolve()
|
|
||||||
target = (project_root / filename).resolve()
|
target = (project_root / filename).resolve()
|
||||||
try:
|
try:
|
||||||
target.relative_to(project_root)
|
target.relative_to(project_root)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user