style: auto-format with black + isort + prettier [skip ci-format-check]
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m53s
AI Code Review / AI Code Review (pull_request) Successful in 6m8s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m19s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 6m57s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m46s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m38s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Successful in 10m33s
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 13m38s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 24m6s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 37m13s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 48m43s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 5m5s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 5m12s

This commit is contained in:
CI Bot
2026-08-31 13:27:03 +00:00
parent a9438ed996
commit 6bf9eff604
3 changed files with 49 additions and 35 deletions
@@ -6,6 +6,7 @@ Create Date: 2026-08-31
"""
import sqlalchemy as sa
from alembic import op
revision = "060_migrate_segments"
@@ -41,8 +42,7 @@ def upgrade() -> None:
"s.id, s.template_id, 'main', s.segment_order, "
"s.duration_min, s.duration_max, "
"'', " + empty_json + ", "
"'cut', "
+ config_expr + ", "
"'cut', " + config_expr + ", "
"s.created_at, s.updated_at "
"FROM template_segments s "
"WHERE NOT EXISTS ("
@@ -212,14 +212,16 @@ class SQLAlchemyTemplateRepository:
# 复用 create_segments 写入 template_clip_configs
new_segments: List[TemplateSegment] = []
for seg in source.segments:
new_segments.append(TemplateSegment(
id=str(uuid.uuid4()),
template_id=created.id,
segment_order=seg.segment_order,
duration_min=seg.duration_min,
duration_max=seg.duration_max,
material_type=seg.material_type,
))
new_segments.append(
TemplateSegment(
id=str(uuid.uuid4()),
template_id=created.id,
segment_order=seg.segment_order,
duration_min=seg.duration_min,
duration_max=seg.duration_max,
material_type=seg.material_type,
)
)
if new_segments:
self.create_segments(new_segments)
else:
+37 -25
View File
@@ -48,15 +48,27 @@ def repo(session):
def _make_template(template_id=None, user_id="u1", name="测试模板", mode="one_take"):
tid = template_id or str(uuid.uuid4())
return Template(
id=tid, user_id=user_id, name=name, mode=mode,
category="", tags=[], estimated_duration=30.0, is_active=True, segments=[])
id=tid,
user_id=user_id,
name=name,
mode=mode,
category="",
tags=[],
estimated_duration=30.0,
is_active=True,
segments=[],
)
def _make_segment(template_id, order=1, material_type=None):
return TemplateSegment(
id=str(uuid.uuid4()), template_id=template_id,
segment_order=order, duration_min=5.0, duration_max=10.0,
material_type=material_type)
id=str(uuid.uuid4()),
template_id=template_id,
segment_order=order,
duration_min=5.0,
duration_max=10.0,
material_type=material_type,
)
class TestCreateSegments:
@@ -65,8 +77,7 @@ class TestCreateSegments:
repo.create(tpl)
seg = _make_segment(tpl.id, order=1)
repo.create_segments([seg])
clips = session.query(TemplateClipConfigModel).filter(
TemplateClipConfigModel.template_id == tpl.id).all()
clips = session.query(TemplateClipConfigModel).filter(TemplateClipConfigModel.template_id == tpl.id).all()
assert len(clips) == 1
assert clips[0].clip_type == "main"
assert clips[0].order == 1
@@ -77,8 +88,7 @@ class TestCreateSegments:
repo.create(tpl)
seg = _make_segment(tpl.id, order=1, material_type="voiceover")
repo.create_segments([seg])
clip = session.query(TemplateClipConfigModel).filter(
TemplateClipConfigModel.template_id == tpl.id).first()
clip = session.query(TemplateClipConfigModel).filter(TemplateClipConfigModel.template_id == tpl.id).first()
assert clip.config["material_type"] == "voiceover"
@@ -96,8 +106,13 @@ class TestListSegments:
tpl = _make_template()
repo.create(tpl)
old = TemplateSegmentModel(
id=str(uuid.uuid4()), template_id=tpl.id,
segment_order=1, duration_min=3.0, duration_max=8.0, material_type="场景")
id=str(uuid.uuid4()),
template_id=tpl.id,
segment_order=1,
duration_min=3.0,
duration_max=8.0,
material_type="场景",
)
session.add(old)
session.commit()
result = repo.list_segments(tpl.id)
@@ -110,8 +125,8 @@ class TestListSegments:
seg = _make_segment(tpl.id, order=1)
repo.create_segments([seg])
old = TemplateSegmentModel(
id=str(uuid.uuid4()), template_id=tpl.id,
segment_order=1, duration_min=1.0, duration_max=2.0)
id=str(uuid.uuid4()), template_id=tpl.id, segment_order=1, duration_min=1.0, duration_max=2.0
)
session.add(old)
session.commit()
result = repo.list_segments(tpl.id)
@@ -134,8 +149,8 @@ class TestListByUser:
tpl = _make_template()
repo.create(tpl)
old = TemplateSegmentModel(
id=str(uuid.uuid4()), template_id=tpl.id,
segment_order=1, duration_min=2.0, duration_max=6.0)
id=str(uuid.uuid4()), template_id=tpl.id, segment_order=1, duration_min=2.0, duration_max=6.0
)
session.add(old)
session.commit()
result = repo.list_by_user("u1")
@@ -152,8 +167,7 @@ class TestCopyTemplate:
repo.create_segments([seg])
copied = repo.copy_template(tpl.id, "u1", "副本模板")
assert copied.id != tpl.id
clips = session.query(TemplateClipConfigModel).filter(
TemplateClipConfigModel.template_id == copied.id).all()
clips = session.query(TemplateClipConfigModel).filter(TemplateClipConfigModel.template_id == copied.id).all()
assert len(clips) == 1
assert clips[0].config["material_type"] == "voiceover"
@@ -171,15 +185,13 @@ class TestDelete:
seg = _make_segment(tpl.id, order=1)
repo.create_segments([seg])
old = TemplateSegmentModel(
id=str(uuid.uuid4()), template_id=tpl.id,
segment_order=1, duration_min=1.0, duration_max=2.0)
id=str(uuid.uuid4()), template_id=tpl.id, segment_order=1, duration_min=1.0, duration_max=2.0
)
session.add(old)
session.commit()
repo.delete(tpl.id, "u1")
c1 = session.query(TemplateClipConfigModel).filter(
TemplateClipConfigModel.template_id == tpl.id).count()
c2 = session.query(TemplateSegmentModel).filter(
TemplateSegmentModel.template_id == tpl.id).count()
c1 = session.query(TemplateClipConfigModel).filter(TemplateClipConfigModel.template_id == tpl.id).count()
c2 = session.query(TemplateSegmentModel).filter(TemplateSegmentModel.template_id == tpl.id).count()
assert c1 == 0
assert c2 == 0
@@ -189,8 +201,8 @@ class TestDelete:
seg = _make_segment(tpl.id, order=1)
repo.create_segments([seg])
old = TemplateSegmentModel(
id=str(uuid.uuid4()), template_id=tpl.id,
segment_order=2, duration_min=1.0, duration_max=2.0)
id=str(uuid.uuid4()), template_id=tpl.id, segment_order=2, duration_min=1.0, duration_max=2.0
)
session.add(old)
session.commit()
count = repo.delete_segments_by_template(tpl.id)