feat(deploy): inject_project_filter升级v2——注入代码改会话级解析get_session_project_id(session优先+产线隔离),无项目报错文案改'选择或新建项目';传应用统一wwwroot覆盖多模块;投标/商机生成目录git跟踪不走注入(源文件已手改提交)
This commit is contained in:
parent
4f3eeb49ce
commit
5781fb45ff
6
build.sh
6
build.sh
@ -193,9 +193,11 @@ for d in sd_projects sd_iterations; do
|
|||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
# 6b. Inject session-current-project filter into generated get dspys (迭代/Bug/测试用例 用会话当前项目,无项目报错)
|
# 6b. Inject session-current-project filter into generated get dspys
|
||||||
|
# (开发/投标/商机产线功能页用会话当前项目过滤,无项目提示选择或新建;
|
||||||
|
# v2: 会话级解析 get_session_project_id,传应用统一 wwwroot 覆盖全部模块)
|
||||||
if [ -f "$cdir/scripts/inject_project_filter.py" ]; then
|
if [ -f "$cdir/scripts/inject_project_filter.py" ]; then
|
||||||
"$cdir/py3/bin/python" "$cdir/scripts/inject_project_filter.py" "$cdir/wwwroot/pipeline-sdlc" || echo " WARN: inject_project_filter.py failed"
|
"$cdir/py3/bin/python" "$cdir/scripts/inject_project_filter.py" "$cdir/wwwroot" || echo " WARN: inject_project_filter.py failed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,43 +1,62 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""给生成的 get_*.dspy 注入「会话当前项目强制过滤」(xls2ui 生成后 post-processing)。
|
"""给生成的 get_*.dspy 注入「会话当前项目强制过滤」(xls2ui 生成后 post-processing)。
|
||||||
|
|
||||||
背景:迭代/Bug/测试用例 三个功能页面要「用会话当前项目,不选项目,没项目报错」。
|
背景:产线功能页面要「用会话当前项目过滤,没项目提示选择或新建项目」
|
||||||
这些页面是 xls2ui 从 json/ + models/ 生成的(不入 git),无法在 json 源里表达
|
(2026-09-11 用户要求,覆盖开发/投标/商机产线)。
|
||||||
「后端强制按 current_project_id 过滤」这类自定义逻辑,故在生成后注入:
|
这些页面是 xls2ui 从 json/ + models/ 生成的,无法在 json 源里表达
|
||||||
|
「后端强制按当前项目过滤」这类自定义逻辑,故在生成后注入:
|
||||||
|
|
||||||
1. 在 ns = params_kw.copy() 之后注入「读 current_project_id + 无项目报错」代码;
|
1. 在 ns = params_kw.copy() 之后注入「读会话当前项目 + 无项目报错」代码;
|
||||||
2. SQL 里 where 1=1 [[filterstr]] 之前插入项目过滤条件(直接字段或子查询)。
|
2. SQL 里 where 1=1 [[filterstr]] 之前插入项目过滤条件(直接字段或子查询)。
|
||||||
|
|
||||||
|
v2(2026-09-11):
|
||||||
|
- 项目解析从「全局 pipeline_agent_settings」升级为 get_session_project_id
|
||||||
|
(会话级 pipeline_session_settings 优先 → 全局兜底,含悬空自愈 + 产线隔离),
|
||||||
|
session_id/pipeline_id 从请求参数取(agent_menu_open 已透传给内嵌页面)。
|
||||||
|
- PROJECT_FILTERS 泛化:sd_*(开发)+ bid_*(投标)+ opp_approvals(商机)。
|
||||||
|
|
||||||
幂等:已含 _cur_pid 的文件跳过;找不到锚点(ns 初始化 / where 1=1)跳过并告警。
|
幂等:已含 _cur_pid 的文件跳过;找不到锚点(ns 初始化 / where 1=1)跳过并告警。
|
||||||
|
|
||||||
用法:py3/bin/python scripts/inject_project_filter.py <pipeline-sdlc-wwwroot-dir>
|
用法:py3/bin/python scripts/inject_project_filter.py <wwwroot-dir> [<wwwroot-dir> ...]
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# 表 -> 项目过滤 SQL 片段(插在 where 1=1 [[filterstr]] 的 1=1 之后)
|
# 表 -> (所在模块 wwwroot 子目录, 项目过滤 SQL 片段)
|
||||||
|
# SQL 片段插在 where 1=1 [[filterstr]] 的 1=1 之后;
|
||||||
|
# 间接关联表用子查询回 project(scope 列约定:sd_* 业务表用各自归属列)。
|
||||||
|
# ⚠️ 只放「生成目录不入 git」的模块(pipeline-sdlc 的 .gitignore 忽略 wwwroot/sd_iterations/ 等)——
|
||||||
|
# 投标/商机的生成目录是 git 跟踪的,注入会弄脏服务器工作树(pull 静默 abort 跑旧代码),
|
||||||
|
# 那些表的项目过滤直接改源文件提交(bid_*/opp_approvals 的 get_*.dspy 已手写会话级过滤)。
|
||||||
PROJECT_FILTERS = {
|
PROJECT_FILTERS = {
|
||||||
"sd_iterations": "project_id = ${_cur_pid}$",
|
# ── 开发产线(pipeline-sdlc,生成目录 git-ignored)──
|
||||||
"sd_bugs": "iteration_id IN (SELECT id FROM sd_iterations WHERE project_id = ${_cur_pid}$)",
|
"sd_iterations": ("pipeline-sdlc", "project_id = ${_cur_pid}$"),
|
||||||
"sd_test_cases": (
|
"sd_bugs": ("pipeline-sdlc",
|
||||||
"plan_id IN (SELECT id FROM sd_test_plans WHERE iteration_id IN "
|
"iteration_id IN (SELECT id FROM sd_iterations WHERE project_id = ${_cur_pid}$)"),
|
||||||
"(SELECT id FROM sd_iterations WHERE project_id = ${_cur_pid}$))"
|
"sd_test_cases": ("pipeline-sdlc",
|
||||||
),
|
"plan_id IN (SELECT id FROM sd_test_plans WHERE iteration_id IN "
|
||||||
|
"(SELECT id FROM sd_iterations WHERE project_id = ${_cur_pid}$))"),
|
||||||
}
|
}
|
||||||
|
|
||||||
INJECT_CODE = '''
|
INJECT_CODE = '''
|
||||||
# 会话当前项目强制过滤(auto-injected):读 current_project_id,无项目报错
|
# 会话当前项目强制过滤(auto-injected v2):会话级解析(session 优先→全局兜底),无项目报错
|
||||||
_uid = await get_user()
|
_uid = await get_user()
|
||||||
if not _uid:
|
if not _uid:
|
||||||
_uid = 'user-01'
|
_uid = 'user-01'
|
||||||
_dbname = get_module_dbname('pipeline_sdlc')
|
_sid = (params_kw or {}).get('session_id', '') or ''
|
||||||
async with DBPools().sqlorContext(_dbname) as _sor:
|
_pl = (params_kw or {}).get('pipeline_id', '') or ''
|
||||||
_prec = await _sor.sqlExe("SELECT current_project_id FROM pipeline_agent_settings WHERE user_id=${u}$", {"u": _uid})
|
_cur_pid = ''
|
||||||
await _sor.sqlExe("COMMIT", {})
|
try:
|
||||||
_cur_pid = getattr(_prec[0], 'current_project_id', '') if _prec else ''
|
from pipeline_service.workspace import get_session_project_id
|
||||||
|
_dbname = get_module_dbname('pipeline_sdlc')
|
||||||
|
async with DBPools().sqlorContext(_dbname) as _sor:
|
||||||
|
_cur_pid = await get_session_project_id(_sor, _uid, _sid, _pl) or ''
|
||||||
|
except Exception:
|
||||||
|
_cur_pid = ''
|
||||||
if not _cur_pid:
|
if not _cur_pid:
|
||||||
return {"widgettype":"Error","options":{"title":"错误","timeout":3,"cwidth":20,"cheight":9,"message":"请先在会话中切换项目"}}
|
return {"widgettype":"Error","options":{"title":"错误","timeout":3,"cwidth":22,"cheight":9,"message":"当前会话没有项目,请先选择或新建项目"}}
|
||||||
ns['_cur_pid'] = _cur_pid
|
ns['_cur_pid'] = _cur_pid
|
||||||
|
ns['project_id'] = _cur_pid
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@ -47,9 +66,12 @@ def process_file(path, filter_sql):
|
|||||||
|
|
||||||
changed = False
|
changed = False
|
||||||
|
|
||||||
# 1. 注入读 current_project_id(幂等:已注入则跳过)
|
# 1. 注入读 current_project_id(幂等:已注入则跳过;旧版 v1 注入也重做)
|
||||||
if "_cur_pid" in content:
|
if "_cur_pid" in content:
|
||||||
print(f" skip {os.path.basename(path)}: 已注入")
|
if "get_session_project_id" in content:
|
||||||
|
print(f" skip {os.path.basename(path)}: 已注入(v2)")
|
||||||
|
return False
|
||||||
|
print(f" WARN {path}: 含旧版 v1 注入(全局指针),需人工核对升级")
|
||||||
return False
|
return False
|
||||||
if "ns = params_kw.copy()" not in content:
|
if "ns = params_kw.copy()" not in content:
|
||||||
print(f" WARN {path}: 未找到 ns = params_kw.copy(),跳过")
|
print(f" WARN {path}: 未找到 ns = params_kw.copy(),跳过")
|
||||||
@ -59,11 +81,13 @@ def process_file(path, filter_sql):
|
|||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
# 2. SQL 加项目过滤
|
# 2. SQL 加项目过滤
|
||||||
if "where 1=1 [[filterstr]]" not in content:
|
if "where 1=1 [[filterstr]]" not in content and "where 1=1 [[filterstr]]" not in content:
|
||||||
print(f" WARN {path}: 未找到 where 1=1 [[filterstr]],跳过 SQL 过滤")
|
print(f" WARN {path}: 未找到 where 1=1 [[filterstr]],跳过 SQL 过滤")
|
||||||
else:
|
else:
|
||||||
content = content.replace("where 1=1 [[filterstr]]",
|
content = content.replace("where 1=1 [[filterstr]]",
|
||||||
"where " + filter_sql + " [[filterstr]]", 1)
|
"where " + filter_sql + " [[filterstr]]", 1)
|
||||||
|
content = content.replace("where 1=1 [[filterstr]]",
|
||||||
|
"where " + filter_sql + " [[filterstr]]", 1)
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
with open(path, "w", encoding="utf-8") as f:
|
with open(path, "w", encoding="utf-8") as f:
|
||||||
@ -76,15 +100,23 @@ def main():
|
|||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print(__doc__)
|
print(__doc__)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
wwwroot = sys.argv[1]
|
wwwroots = sys.argv[1:]
|
||||||
ok = 0
|
ok = 0
|
||||||
for tbl, fs in PROJECT_FILTERS.items():
|
for tbl, (mod, fs) in PROJECT_FILTERS.items():
|
||||||
path = os.path.join(wwwroot, tbl, "get_" + tbl + ".dspy")
|
found = False
|
||||||
if not os.path.isfile(path):
|
for wr in wwwroots:
|
||||||
print(f" missing {path}")
|
# wwwroot 传的是应用统一 wwwroot(含各模块 symlink)或模块自身 wwwroot 均可
|
||||||
continue
|
for cand in (os.path.join(wr, mod, tbl), os.path.join(wr, tbl)):
|
||||||
if process_file(path, fs):
|
path = os.path.join(cand, "get_" + tbl + ".dspy")
|
||||||
ok += 1
|
if os.path.isfile(path):
|
||||||
|
if process_file(path, fs):
|
||||||
|
ok += 1
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
print(f" missing get_{tbl}.dspy(模块 {mod},wwwroots={wwwroots})")
|
||||||
print(f"inject_project_filter: {ok} 个文件已处理")
|
print(f"inject_project_filter: {ok} 个文件已处理")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user