feat: 完善分割工作区导入导出与管理流程
- 新增基于 JWT 当前用户的登录恢复、角色权限、用户管理、审计日志和演示出厂重置后台接口与前端管理页。 - 重串 GT_label 导出和 GT Mask 导入逻辑:导出保留类别真实 maskid,导入仅接受灰度或 RGB 等通道 maskid 图,支持未知 maskid 策略、尺寸最近邻拉伸和导入预览。 - 统一分割结果导出体验:默认当前帧,按项目抽帧顺序和 XhXXmXXsXXXms 时间戳命名 ZIP 与图片,补齐 GT/Pro/Mix/分开 Mask 输出和映射 JSON。 - 调整工作区左侧工具栏:移除创建点/线段入口,新增画笔、橡皮擦及尺寸控制,并按绘制、布尔、导入/AI 工具分组分隔。 - 扩展 Canvas 编辑能力:画笔按语义分类绘制并可自动并入连通选中 mask,橡皮擦对选中区域扣除,优化布尔操作、选区、撤销重做和保存状态联动。 - 优化自动传播时间轴显示:同一蓝色系按传播新旧递进变暗,老传播记录达到阈值后统一旧记录色,并维护范围选择与清空后的历史显示。 - 将 AI 智能分割入口替换为更明确的 AI 元素图标,并同步侧栏、工作区和 AI 页面入口表现。 - 完善模板分类、maskid 工具函数、分类树联动、遮罩透明度、边缘平滑和传播链同步相关前端状态。 - 扩展后端项目、媒体、任务、Dashboard、模板和传播 runner 的用户隔离、任务控制、进度事件与兼容处理。 - 补充前后端测试,覆盖用户管理、GT_label 往返导入导出、GT Mask 校验和预览、画笔/橡皮擦、时间轴传播历史、导出范围、WebSocket 与 API 封装。 - 更新 AGENTS、README 和 doc 文档,记录当前接口契约、实现状态、测试计划、安装说明和 maskid/GT_label 规则。
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from models import Annotation, Frame, Mask, ProcessingTask, Project
|
||||
from models import Annotation, Frame, Mask, ProcessingTask, Project, User
|
||||
from routers.auth import create_access_token, hash_password
|
||||
|
||||
|
||||
def test_project_crud_and_frames(client, monkeypatch):
|
||||
@@ -93,3 +94,33 @@ def test_project_and_frame_404s(client):
|
||||
}).status_code == 404
|
||||
assert client.get("/api/projects/999/frames").status_code == 404
|
||||
assert client.get("/api/projects/999/frames/1").status_code == 404
|
||||
|
||||
|
||||
def test_projects_are_scoped_to_authenticated_owner(client, db_session):
|
||||
owner_project = client.post("/api/projects", json={"name": "Owner Project"}).json()
|
||||
other_user = User(
|
||||
username="other",
|
||||
password_hash=hash_password("pass"),
|
||||
role="annotator",
|
||||
is_active=1,
|
||||
)
|
||||
db_session.add(other_user)
|
||||
db_session.commit()
|
||||
db_session.refresh(other_user)
|
||||
other_project = Project(name="Other Project", owner_user_id=other_user.id)
|
||||
db_session.add(other_project)
|
||||
db_session.commit()
|
||||
db_session.refresh(other_project)
|
||||
|
||||
listing = client.get("/api/projects")
|
||||
assert [project["id"] for project in listing.json()] == [owner_project["id"]]
|
||||
assert client.get(f"/api/projects/{other_project.id}").status_code == 404
|
||||
|
||||
original_auth = client.headers["Authorization"]
|
||||
client.headers.update({"Authorization": f"Bearer {create_access_token(other_user)}"})
|
||||
try:
|
||||
other_listing = client.get("/api/projects")
|
||||
assert [project["id"] for project in other_listing.json()] == [other_project.id]
|
||||
assert client.get(f"/api/projects/{owner_project['id']}").status_code == 404
|
||||
finally:
|
||||
client.headers.update({"Authorization": original_auth})
|
||||
|
||||
Reference in New Issue
Block a user