Fix backend imports and clip pinning flow
This commit is contained in:
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy import delete, select, update
|
||||
from sqlalchemy import delete, func, select, update
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..auth import require_session
|
||||
@@ -19,6 +19,7 @@ from ..schemas import (
|
||||
AudioClipCreate,
|
||||
AudioClipResponse,
|
||||
AudioClipUpdate,
|
||||
AudioClipReorder,
|
||||
)
|
||||
from ..storage import storage
|
||||
|
||||
@@ -39,6 +40,7 @@ def clip_to_response(clip: AudioClip) -> AudioClipResponse:
|
||||
label=clip.label,
|
||||
start_ms=clip.start_ms,
|
||||
end_ms=clip.end_ms,
|
||||
sort_order=clip.sort_order,
|
||||
normalization_status=clip.normalization_status,
|
||||
normalized_url=normalized_url,
|
||||
waveform_duration_ms=waveform["duration_ms"] if waveform else None,
|
||||
@@ -53,6 +55,18 @@ def can_manage_asset(session: UserSession, asset: AudioAsset, owner_external_pla
|
||||
return owner_external_player_id is not None and asset.owner_external_player_id == owner_external_player_id
|
||||
|
||||
|
||||
def next_clip_sort_order(db: Session, *, external_team_id: str, owner_external_player_id: str) -> int:
|
||||
highest_sort_order = db.scalar(
|
||||
select(func.max(AudioClip.sort_order))
|
||||
.join(AudioClip.asset)
|
||||
.where(
|
||||
AudioAsset.external_team_id == external_team_id,
|
||||
AudioAsset.owner_external_player_id == owner_external_player_id,
|
||||
)
|
||||
)
|
||||
return highest_sort_order + 1 if highest_sort_order is not None else 0
|
||||
|
||||
|
||||
def create_asset_with_default_clip(
|
||||
*,
|
||||
db: Session,
|
||||
@@ -83,6 +97,11 @@ def create_asset_with_default_clip(
|
||||
label=asset.title,
|
||||
start_ms=0,
|
||||
end_ms=DEFAULT_CLIP_LENGTH_MS,
|
||||
sort_order=next_clip_sort_order(
|
||||
db,
|
||||
external_team_id=external_team_id,
|
||||
owner_external_player_id=owner_external_player_id,
|
||||
),
|
||||
normalization_status="processing",
|
||||
)
|
||||
db.add(clip)
|
||||
@@ -282,6 +301,11 @@ def create_clip(
|
||||
label=payload.label,
|
||||
start_ms=payload.start_ms,
|
||||
end_ms=payload.end_ms,
|
||||
sort_order=next_clip_sort_order(
|
||||
db,
|
||||
external_team_id=payload.external_team_id,
|
||||
owner_external_player_id=payload.owner_external_player_id,
|
||||
),
|
||||
normalization_status="processing",
|
||||
)
|
||||
db.add(clip)
|
||||
@@ -314,6 +338,8 @@ def update_clip(
|
||||
clip.label = payload.label or clip.label
|
||||
clip.start_ms = payload.start_ms
|
||||
clip.end_ms = payload.end_ms
|
||||
if payload.sort_order is not None:
|
||||
clip.sort_order = payload.sort_order
|
||||
db.commit()
|
||||
db.refresh(clip)
|
||||
return clip_to_response(clip)
|
||||
@@ -357,7 +383,7 @@ def list_clips(
|
||||
select(AudioClip)
|
||||
.join(AudioClip.asset)
|
||||
.where(AudioAsset.external_team_id == external_team_id)
|
||||
.order_by(AudioClip.created_at.desc())
|
||||
.order_by(AudioClip.sort_order.asc(), AudioClip.created_at.desc())
|
||||
)
|
||||
if owner_external_player_id:
|
||||
query = query.where(AudioAsset.owner_external_player_id == owner_external_player_id)
|
||||
@@ -365,6 +391,33 @@ def list_clips(
|
||||
return [clip_to_response(clip) for clip in clips]
|
||||
|
||||
|
||||
@router.post("/clips/reorder", status_code=204)
|
||||
def reorder_clips(
|
||||
payload: AudioClipReorder,
|
||||
session: UserSession = Depends(require_session),
|
||||
db: Session = Depends(get_db),
|
||||
) -> None:
|
||||
if not session.is_admin and session.external_team_id != payload.external_team_id:
|
||||
raise HTTPException(status_code=403, detail="You can only reorder clips for your selected team")
|
||||
|
||||
clips = db.scalars(
|
||||
select(AudioClip)
|
||||
.join(AudioClip.asset)
|
||||
.where(
|
||||
AudioAsset.external_team_id == payload.external_team_id,
|
||||
AudioAsset.owner_external_player_id == payload.owner_external_player_id,
|
||||
)
|
||||
).all()
|
||||
clips_by_id = {clip.id: clip for clip in clips}
|
||||
if len(clips_by_id) != len(clips) or set(clips_by_id) != set(payload.clip_ids):
|
||||
raise HTTPException(status_code=422, detail="Clip order must include every clip for that player")
|
||||
|
||||
for sort_order, clip_id in enumerate(payload.clip_ids):
|
||||
clips_by_id[clip_id].sort_order = sort_order
|
||||
|
||||
db.commit()
|
||||
|
||||
|
||||
@router.get("/files/{relative_path:path}")
|
||||
def media_file(relative_path: str) -> FileResponse:
|
||||
path = storage.absolute_path(relative_path)
|
||||
|
||||
Reference in New Issue
Block a user