pipeline-sdlc/wwwroot/api/workspace_file.dspy

63 lines
2.2 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# workspace_file.dspy - 提供工作空间文件(媒体流 / 下载)
import os
from urllib.parse import quote, unquote
from aiohttp.web_fileresponse import FileResponse
def _decode_id(s):
# 前端 id 可能被多层编码,循环解码到无 % 为止2026-09-03 中文文件名根因)
for _ in range(4):
if '%' not in s:
break
s2 = unquote(s)
if s2 == s:
break
s = s2
return s
file_id = _decode_id((params_kw or {}).get('id', '').strip())
download = (params_kw or {}).get('download', '').strip()
uid = await get_user()
if not uid:
uid = 'user-01'
session_id = (params_kw or {}).get('session_id', '') or ''
pipeline_id = (params_kw or {}).get('pipeline_id', '') or ''
dbname = get_module_dbname('pipeline-sdlc')
async with DBPools().sqlorContext(dbname) as sor:
# 产线隔离:跨产线项目视为无项目(与弹窗入口一致,防绕过)
project_dir, _ = await get_project_dir_pl(sor, uid, session_id, pipeline_id)
space_dir, _ = await get_space_dir(sor, uid, session_id)
# 通用会话pipeline_id=_generic锁用户专属目录 _general/{uid}
# 不进入任何项目的工作空间2026-09-08 用户要求)
if pipeline_id == '_generic':
_gd = generic_workspace_dir(uid)
os.makedirs(_gd, exist_ok=True)
project_dir = _gd
space_dir = _gd
if not file_id or file_id == '__root__':
return {"widgettype": "Message", "options": {"title": "错误", "message": "未指定文件"}}
full_path = resolve_workspace_path(project_dir, space_dir, file_id)
# 路径穿越校验
real_ws = os.path.realpath(space_dir)
real_full = os.path.realpath(full_path)
if not real_full.startswith(real_ws + os.sep):
return {"widgettype": "Message", "options": {"title": "错误", "message": "非法路径"}}
if not os.path.isfile(full_path):
return {"widgettype": "Message", "options": {"title": "错误", "message": "文件不存在: " + file_id}}
headers = {}
if download:
filename = os.path.basename(full_path)
safe_name = quote(filename)
headers['Content-Disposition'] = 'attachment; filename="%s"; filename*=UTF-8\'\'%s' % (filename, safe_name)
return FileResponse(full_path, headers=headers)