352221f199
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 16s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m0s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 2m42s
CI/CD Pipeline / Integration Tests (push) Successful in 3m50s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m35s
CI/CD Pipeline / Validate - Style (push) Successful in 4m42s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 4m29s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m0s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 43s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m47s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m5s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 3m10s
CI/CD Pipeline / Validate - Security (push) Successful in 11m12s
CI/CD Pipeline / Unit Tests (push) Successful in 11m18s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Failing after 27h18m15s
CI/CD Pipeline / Build Production API Image (push) Failing after 27h18m15s
CI/CD Pipeline / Frontend Lint (push) Failing after 27h29m35s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 27h24m8s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 27h28m58s
CI/CD Pipeline / PR Build API Image (push) Failing after 27h29m0s
CI/CD Pipeline / Deploy Production (push) Failing after 27h17m36s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 27h17m38s
CI/CD Pipeline / Build Production Web Image (push) Failing after 27h17m38s
CI/CD Pipeline / Canary Release to Production (push) Failing after 27h17m36s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 27h24m7s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 27h24m8s
CI/CD Pipeline / PR Build Web Image (push) Failing after 27h28m58s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 27h29m0s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
150 lines
5.1 KiB
Python
Executable File
150 lines
5.1 KiB
Python
Executable File
"""模板编辑器依赖注入.
|
|
|
|
核心依赖:
|
|
- get_editor_services: 获取模板+计划服务
|
|
- get_draft_plan_id: Depends 形式的路径依赖(template_id 路径参数必填)
|
|
- resolve_draft_plan_id: 纯函数版本,供 clips_standalone 等非路径参数场景复用
|
|
(支持空 tid 时自动兜底创建默认模板)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from app.api.routes._default_template import get_or_create_default_template_id
|
|
from app.auth import AuthenticatedUser, get_current_user
|
|
from app.dependencies import get_db_session
|
|
from app.services.edit_plan_service import EditPlanService
|
|
from app.services.edit_template_service import EditTemplateService
|
|
from fastapi import Depends, HTTPException, status
|
|
from sqlalchemy.orm import Session
|
|
|
|
from packages.adapters.sqlalchemy_impl.template_repository import (
|
|
SQLAlchemyTemplateRepository,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def get_editor_services(
|
|
db: Session = Depends(get_db_session),
|
|
) -> tuple[EditTemplateService, EditPlanService]:
|
|
"""获取模板编辑器所需的两个服务"""
|
|
return EditTemplateService(db), EditPlanService(db)
|
|
|
|
|
|
def resolve_draft_plan_id(
|
|
template_id: str,
|
|
services: tuple[EditTemplateService, EditPlanService],
|
|
current_user: AuthenticatedUser,
|
|
db: Session,
|
|
auto_create_default: bool = True,
|
|
) -> str:
|
|
"""根据 template_id 获取或创建草稿,返回 plan_id(纯函数,不带 Depends)。
|
|
|
|
当 auto_create_default=True 且 template_id 为空时,自动调用
|
|
get_or_create_default_template_id 创建默认模板(用于 clips_standalone
|
|
等非路径参数场景)。
|
|
"""
|
|
tpl_svc, plan_svc = services
|
|
user_id = str(current_user.user.id)
|
|
|
|
# 0. 空 tid 兜底
|
|
if not template_id:
|
|
if auto_create_default:
|
|
tid = get_or_create_default_template_id(db, user_id)
|
|
if not tid:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="无法自动创建默认模板,请刷新页面重试",
|
|
)
|
|
template_id = tid
|
|
else:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="template_id 不能为空",
|
|
)
|
|
|
|
# 1. 门禁:校验模板存在且可访问
|
|
old_repo = SQLAlchemyTemplateRepository(db)
|
|
old_template = old_repo.get_active(template_id, user_id)
|
|
is_global_template = tpl_svc.get_template(template_id) is not None
|
|
if old_template is None and not is_global_template:
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="模板不存在")
|
|
|
|
# 2. 草稿已存在 → 直接返回
|
|
draft = tpl_svc.get_template_draft(template_id)
|
|
if draft is not None:
|
|
return draft.id
|
|
|
|
# 3. 全局模板(新系统)→ 用新服务创建草稿
|
|
if is_global_template:
|
|
draft = tpl_svc.create_template_draft(template_id, user_id=user_id)
|
|
return draft.id
|
|
|
|
# 4. 旧模板(templates 表)→ 基于旧模板创建草稿计划
|
|
from app.services.plan_generator_service import PlanGeneratorService
|
|
|
|
from packages.domain.edit_template import EditTemplate, EditTemplateStatus
|
|
from packages.domain.template_clip_config import ClipType, TemplateClipConfig
|
|
|
|
pseudo_template = EditTemplate(
|
|
id=old_template.id,
|
|
name=old_template.name,
|
|
editing_mode=old_template.mode,
|
|
status=EditTemplateStatus.ACTIVE,
|
|
)
|
|
|
|
clip_configs: list[TemplateClipConfig] = []
|
|
for seg in old_template.segments or []:
|
|
clip_configs.append(
|
|
TemplateClipConfig(
|
|
id=f"seg_{seg.id}",
|
|
template_id=old_template.id,
|
|
clip_type=ClipType.MAIN,
|
|
order=seg.segment_order,
|
|
min_duration=seg.duration_min,
|
|
max_duration=seg.duration_max,
|
|
)
|
|
)
|
|
|
|
generator = PlanGeneratorService(db)
|
|
result = generator.generate_from_template(
|
|
template=pseudo_template,
|
|
clip_configs=clip_configs,
|
|
asset_ids=[],
|
|
created_by_user_id=user_id,
|
|
name=f"{old_template.name} - 草稿",
|
|
)
|
|
plan = result["plan"]
|
|
|
|
plan_svc.update_plan_config(plan.id, {"is_template_draft": True})
|
|
|
|
logger.info(
|
|
"旧模板自动创建草稿: template_id=%s draft_plan_id=%s user_id=%s",
|
|
template_id,
|
|
plan.id,
|
|
user_id,
|
|
)
|
|
return plan.id
|
|
|
|
|
|
def get_draft_plan_id(
|
|
template_id: str,
|
|
services: tuple[EditTemplateService, EditPlanService] = Depends(get_editor_services),
|
|
current_user: AuthenticatedUser = Depends(get_current_user),
|
|
db: Session = Depends(get_db_session),
|
|
) -> str:
|
|
"""路径依赖:根据 template_id 获取或创建草稿,返回 plan_id.
|
|
|
|
Depends 版本:路径参数 template_id 由 FastAPI 保证非空,不自动兜底。
|
|
兜底逻辑走 resolve_draft_plan_id(auto_create_default=False)。
|
|
"""
|
|
return resolve_draft_plan_id(
|
|
template_id=template_id,
|
|
services=services,
|
|
current_user=current_user,
|
|
db=db,
|
|
auto_create_default=False,
|
|
)
|