- таблица sections (дерево через parent_id), у видео section_id
- API: CRUD /sections, фильтры /videos (поиск, раздел с потомками, метод),
GET /videos/{id}/text, PATCH раздела, DELETE вместе с файлами
- pipeline: keep_video=false удаляет mp4 после расшифровки, section_id
- UI: панель разделов с вложенностью и счётчиками, поиск, фильтр по методу,
диалоги полного текста/выжимки, привязка к разделу, удаление,
переключатель «Сохранять видео на диске»
- compose: bind-mount ./web для правок без пересборки
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
from sqlalchemy import func, select, update
|
|
|
|
from api.db.connection import SessionLocal
|
|
from api.models.section import Section
|
|
from api.models.video import Video
|
|
|
|
|
|
async def list_sections() -> list[dict]:
|
|
"""Плоский список разделов + количество видео в каждом (дерево строит клиент)."""
|
|
async with SessionLocal() as session:
|
|
res = await session.execute(select(Section).order_by(Section.name))
|
|
sections = list(res.scalars().all())
|
|
counts_res = await session.execute(
|
|
select(Video.section_id, func.count()).group_by(Video.section_id)
|
|
)
|
|
counts = dict(counts_res.all())
|
|
return [
|
|
{
|
|
"id": s.id,
|
|
"name": s.name,
|
|
"parent_id": s.parent_id,
|
|
"video_count": counts.get(s.id, 0),
|
|
}
|
|
for s in sections
|
|
]
|
|
|
|
|
|
async def create_section(name: str, parent_id: int | None) -> Section:
|
|
async with SessionLocal() as session:
|
|
if parent_id is not None:
|
|
parent = await session.get(Section, parent_id)
|
|
if parent is None:
|
|
raise ValueError(f"Parent section {parent_id} not found")
|
|
s = Section(name=name, parent_id=parent_id)
|
|
session.add(s)
|
|
await session.commit()
|
|
await session.refresh(s)
|
|
return s
|
|
|
|
|
|
async def delete_section(section_id: int) -> bool:
|
|
"""Удаляет раздел: дочерние разделы поднимаются к родителю, видео — без раздела."""
|
|
async with SessionLocal() as session:
|
|
s = await session.get(Section, section_id)
|
|
if s is None:
|
|
return False
|
|
await session.execute(
|
|
update(Section)
|
|
.where(Section.parent_id == section_id)
|
|
.values(parent_id=s.parent_id)
|
|
)
|
|
await session.execute(
|
|
update(Video).where(Video.section_id == section_id).values(section_id=None)
|
|
)
|
|
await session.delete(s)
|
|
await session.commit()
|
|
return True
|