repertory-api/app/routes_tunes.py

143 lines
4.7 KiB
Python
Raw Permalink Normal View History

2026-06-09 15:07:08 -04:00
"""Routes for the core tunes table."""
from flask import Blueprint, jsonify, request
from app.extensions import db
from app.models import Tune, TuneByInstrument, TuneNote, Reference, Musician
from app.auth import require_api_key
tunes_bp = Blueprint("tunes", __name__, url_prefix="/tunes")
# ---------------------------------------------------------------------------
# List / filter
# ---------------------------------------------------------------------------
@tunes_bp.get("/")
def list_tunes():
"""
Query params (all optional, combinable):
instrument_id=1
key=D
tuning_id=1
status=callable|review|to_learn
2026-06-09 15:07:08 -04:00
difficulty=easy|hard
modal=true|false
source_id=1
search=<substring match on name>
"""
q = db.session.query(Tune)
search = request.args.get("search")
if search:
q = q.filter(Tune.name.ilike(f"%{search}%"))
key = request.args.get("key")
if key:
q = q.filter(Tune.key.ilike(key))
modal = request.args.get("modal")
if modal is not None:
q = q.filter(Tune.modal == (modal.lower() in ("true", "1", "yes")))
source_id = request.args.get("source_id")
if source_id:
q = q.filter(Tune.source_id == int(source_id))
instrument_id = request.args.get("instrument_id")
tuning = request.args.get("tuning")
status = request.args.get("status")
2026-06-09 15:07:08 -04:00
difficulty = request.args.get("difficulty")
if any([instrument_id, tuning, status, difficulty]):
2026-06-09 15:07:08 -04:00
q = q.join(Tune.instruments)
if instrument_id:
q = q.filter(TuneByInstrument.instrument_id == int(instrument_id))
if tuning:
q = q.filter(TuneByInstrument.tuning_id == int(tuning))
if status:
q = q.filter(TuneByInstrument.status == status)
2026-06-09 15:07:08 -04:00
if difficulty:
q = q.filter(TuneByInstrument.difficulty.ilike(difficulty))
tunes = q.order_by(Tune.name).all()
2026-06-11 14:51:50 -04:00
return jsonify([t.to_slim_dict() for t in tunes])
2026-06-09 15:07:08 -04:00
# ---------------------------------------------------------------------------
# Get single tune
# ---------------------------------------------------------------------------
@tunes_bp.get("/<int:tune_id>")
def get_tune(tune_id):
tune = db.get_or_404(Tune, tune_id)
return jsonify(tune.to_dict())
# ---------------------------------------------------------------------------
# Create tune (with optional nested instruments / notes / references)
# ---------------------------------------------------------------------------
@tunes_bp.post("/")
@require_api_key
def create_tune():
data = request.get_json(force=True)
tune = Tune(
name=data.get("name"),
key=data.get("key"),
modal=data.get("modal"),
source_id=data.get("source_id"),
)
db.session.add(tune)
db.session.flush()
for inst_data in data.get("instruments", []):
entry = TuneByInstrument(
tune_id=tune.id,
instrument_id=inst_data["instrument_id"],
learned_from_id=inst_data.get("learned_from_id"),
tuning_id=inst_data.get("tuning_id"),
date_learned=inst_data.get("date_learned"),
status=inst_data.get("status"),
2026-06-09 15:07:08 -04:00
difficulty=inst_data.get("difficulty"),
)
db.session.add(entry)
for note_data in data.get("notes", []):
db.session.add(TuneNote(tune_id=tune.id, note=note_data.get("note")))
for ref_data in data.get("references", []):
ref = Reference(tune_id=tune.id, link=ref_data.get("link"), site=ref_data.get("site"))
db.session.add(ref)
db.session.flush()
for m in ref_data.get("musicians", []):
musician = db.session.get(Musician, m["id"])
if musician:
ref.musicians.append(musician)
db.session.commit()
return jsonify(tune.to_dict()), 201
# ---------------------------------------------------------------------------
# Update tune core fields
# ---------------------------------------------------------------------------
@tunes_bp.patch("/<int:tune_id>")
@require_api_key
def update_tune(tune_id):
tune = db.get_or_404(Tune, tune_id)
data = request.get_json(force=True)
for field in ("name", "key", "modal", "source_id"):
if field in data:
setattr(tune, field, data[field])
db.session.commit()
return jsonify(tune.to_dict())
# ---------------------------------------------------------------------------
# Delete tune
# ---------------------------------------------------------------------------
@tunes_bp.delete("/<int:tune_id>")
@require_api_key
def delete_tune(tune_id):
tune = db.get_or_404(Tune, tune_id)
db.session.delete(tune)
db.session.commit()
return jsonify({"deleted": tune_id})