fix(formula): 导出文件安全、清理回收、撤权校验与定义库可靠性(F01/F02/F05-F08)
- F01: _safe_unlink_export 不跟随符号链接、逐层校验父目录,导出失败路径与 清理命令统一使用,只清理受控目录内本次创建的文件 - F02: 清理失败记录告警日志;清理命令回收 failed 任务残留文件 - F05: 定义保存事务内锁数据集行,配额原子检查;revision 冲突返回 409; 保留最近 20 版历史;支持个人/团队共享;审计与变更同事务 - F06: 工作簿参数页毛利率改为只读快照;可编辑单元格解锁并加数值校验 - F07: 对账按指标分容差(人数 0、比率 0.0001、金额 0.01);自定义列使用 服务端 Decimal 表达式求值参考 - F08: 导出任务执行/下载阶段重校验账号有效性与角色 - 对话草稿会话恢复;载入定义后追问携带原定义(F04);下载改浏览器直传 - 迁移 0006-0008;PostgreSQL 咨询锁语义修正(import_worker)
This commit is contained in:
@@ -46,6 +46,23 @@ def test_worker_processes_queued_import_and_formula_export(workspace):
|
||||
assert job.status == "processing"
|
||||
|
||||
|
||||
def test_worker_reclaims_processing_formula_export_after_restart(workspace):
|
||||
ds, _, _, *_ = workspace
|
||||
job = FormulaExport.objects.create(
|
||||
dataset=ds,
|
||||
user=ds.created_by,
|
||||
context={"custom_columns": []},
|
||||
status="processing",
|
||||
)
|
||||
from unittest.mock import patch
|
||||
|
||||
with patch(
|
||||
"finance.management.commands.import_worker.process_formula_export", return_value={"rows": 5}
|
||||
) as process:
|
||||
call_command("import_worker", once=True)
|
||||
process.assert_called_once_with(job.pk)
|
||||
|
||||
|
||||
def test_formula_export_status_download_and_access_controls(workspace, settings, tmp_path):
|
||||
ds, _, client, _, other_client = workspace
|
||||
url = f"/api/datasets/{ds.pk}"
|
||||
@@ -58,7 +75,7 @@ def test_formula_export_status_download_and_access_controls(workspace, settings,
|
||||
job.status = "succeeded"
|
||||
job.expires_at = timezone.now() + timedelta(hours=1)
|
||||
target = tmp_path / "formula-exports" / str(ds.created_by_id) / f"{job.pk}.xlsx"
|
||||
target.parent.mkdir(parents=True)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_bytes(b"xlsx")
|
||||
job.path = str(target)
|
||||
job.save()
|
||||
@@ -85,6 +102,29 @@ def test_formula_export_status_download_and_access_controls(workspace, settings,
|
||||
assert client.get(status_url).status_code == 403
|
||||
|
||||
|
||||
def test_formula_export_rechecks_role_when_worker_runs_and_file_is_downloaded(workspace, settings, tmp_path):
|
||||
from finance.exporting import process_formula_export
|
||||
|
||||
ds, member, client, _, _ = workspace
|
||||
job = FormulaExport.objects.create(dataset=ds, user=ds.created_by, context={}, status="processing")
|
||||
member.role = "viewer"
|
||||
member.save(update_fields=["role"])
|
||||
with pytest.raises(PermissionError, match="撤权"):
|
||||
process_formula_export(job.pk)
|
||||
job.refresh_from_db()
|
||||
assert job.status == "failed"
|
||||
|
||||
job.status = "succeeded"
|
||||
job.expires_at = timezone.now() + timedelta(hours=1)
|
||||
target = tmp_path / "formula-exports" / str(ds.created_by_id) / f"{job.pk}.xlsx"
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_bytes(b"xlsx")
|
||||
job.path = str(target)
|
||||
job.save(update_fields=["status", "expires_at", "path"])
|
||||
assert client.get(f"/api/datasets/{ds.pk}/formula-exports/{job.pk}").status_code == 403
|
||||
assert client.get(f"/api/datasets/{ds.pk}/formula-exports/{job.pk}/download").status_code == 403
|
||||
|
||||
|
||||
def test_formula_export_create_validates_definition_and_records_job(workspace):
|
||||
ds, _, client, *_ = workspace
|
||||
url = f"/api/datasets/{ds.pk}/formula-exports"
|
||||
|
||||
Reference in New Issue
Block a user