feat(api): auto-link rehearsal sessions on watcher upload and nc-scan

parse_rehearsal_date() extracts YYMMDD / YYYYMMDD from the file path
and get_or_create() a RehearsalSession. Both the watcher nc-upload
endpoint and the nc-scan endpoint now set song.session_id when a
dated folder is detected. Existing songs without a session_id are
back-filled on the next import of the same folder.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Steffen Schuhmann
2026-03-29 13:41:01 +02:00
parent a779c57a26
commit b882c9ea6d
3 changed files with 75 additions and 1 deletions

View File

@@ -12,10 +12,12 @@ from rehearsalhub.dependencies import get_current_member
from rehearsalhub.repositories.audio_version import AudioVersionRepository
from rehearsalhub.repositories.band import BandRepository
from rehearsalhub.repositories.comment import CommentRepository
from rehearsalhub.repositories.rehearsal_session import RehearsalSessionRepository
from rehearsalhub.repositories.song import SongRepository
from rehearsalhub.schemas.comment import SongCommentCreate, SongCommentRead
from rehearsalhub.schemas.song import SongCreate, SongRead, SongUpdate
from rehearsalhub.services.band import BandService
from rehearsalhub.services.session import parse_rehearsal_date
from rehearsalhub.services.song import SongService
from rehearsalhub.storage.nextcloud import NextcloudClient
@@ -156,6 +158,7 @@ async def scan_nextcloud(
nc = NextcloudClient.for_member(current_member)
version_repo = AudioVersionRepository(session)
session_repo = RehearsalSessionRepository(session)
song_svc = SongService(session)
# dav_prefix to strip full WebDAV hrefs → user-relative paths
@@ -231,6 +234,13 @@ async def scan_nextcloud(
skipped_count += 1
continue
# Resolve rehearsal session from YYMMDD folder segment
rehearsal_date = parse_rehearsal_date(nc_file_path)
rehearsal_session_id = None
if rehearsal_date:
rs = await session_repo.get_or_create(band_id, rehearsal_date, nc_folder)
rehearsal_session_id = rs.id
# Find or create song record
song = await song_repo.get_by_nc_folder_path(nc_folder)
if song is None:
@@ -239,14 +249,17 @@ async def scan_nextcloud(
log.info("Creating new song '%s' (folder: %s)", song_title, nc_folder)
song = await song_repo.create(
band_id=band_id,
session_id=rehearsal_session_id,
title=song_title,
status="jam",
notes=f"Rehearsal: {rehearsal_label}" if rehearsal_label else None,
notes=None,
nc_folder_path=nc_folder,
created_by=current_member.id,
)
else:
log.info("Found existing song '%s' (id: %s)", song.title, song.id)
if rehearsal_session_id and song.session_id is None:
song = await song_repo.update(song, session_id=rehearsal_session_id)
await song_svc.register_version(
song.id,