repertory-api/app/routes_tunes.py

142 lines
4.7 KiB
Python

"""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
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")
difficulty = request.args.get("difficulty")
if any([instrument_id, tuning, status, difficulty]):
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)
if difficulty:
q = q.filter(TuneByInstrument.difficulty.ilike(difficulty))
tunes = q.order_by(Tune.name).all()
return jsonify([t.to_slim_dict() for t in tunes])
# ---------------------------------------------------------------------------
# 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"),
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})