Adding database support, basic reads
This commit is contained in:
@@ -3,12 +3,28 @@ import os
|
||||
import typer
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from groove import ondemand
|
||||
from groove.db import metadata
|
||||
|
||||
|
||||
app = typer.Typer()
|
||||
|
||||
|
||||
@app.command()
|
||||
def initialize():
|
||||
load_dotenv()
|
||||
|
||||
# todo: abstract this and replace in_memory_db fixture
|
||||
engine = create_engine(f"sqlite:///{os.environ.get('DATABASE_PATH')}", future=True)
|
||||
Session = sessionmaker(bind=engine, future=True)
|
||||
session = Session()
|
||||
metadata.create_all(bind=engine)
|
||||
session.close()
|
||||
|
||||
|
||||
@app.command()
|
||||
def server(
|
||||
host: str = typer.Argument(
|
||||
@@ -29,6 +45,8 @@ def server(
|
||||
"""
|
||||
load_dotenv()
|
||||
|
||||
ondemand.initialize()
|
||||
|
||||
print("Starting Groove On Demand...")
|
||||
|
||||
debug = os.getenv('DEBUG', None)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy import Table, Column, Integer, String, UnicodeText, ForeignKey, PrimaryKeyConstraint
|
||||
|
||||
metadata = MetaData()
|
||||
|
||||
track = Table(
|
||||
"track",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, autoincrement=True),
|
||||
Column("relpath", UnicodeText, index=True, unique=True),
|
||||
)
|
||||
|
||||
playlist = Table(
|
||||
"playlist",
|
||||
metadata,
|
||||
Column("id", Integer, primary_key=True, autoincrement=True),
|
||||
Column("name", String),
|
||||
Column("description", UnicodeText),
|
||||
Column("slug", String, index=True, unique=True),
|
||||
)
|
||||
|
||||
entry = Table(
|
||||
"entry",
|
||||
metadata,
|
||||
Column("track", Integer),
|
||||
Column("playlist_id", Integer, ForeignKey("playlist.id")),
|
||||
Column("track_id", Integer, ForeignKey("track.id")),
|
||||
PrimaryKeyConstraint("playlist_id", "track"),
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from bottle import HTTPResponse
|
||||
|
||||
from sqlalchemy import bindparam
|
||||
|
||||
from groove import db
|
||||
|
||||
|
||||
class PlaylistDatabaseHelper:
|
||||
"""
|
||||
Convenience class for database interactions.
|
||||
"""
|
||||
def __init__(self, connection):
|
||||
self._conn = connection
|
||||
|
||||
@property
|
||||
def conn(self):
|
||||
return self._conn
|
||||
|
||||
def playlist(self, slug: str) -> dict:
|
||||
"""
|
||||
Retrieve a playlist and its entries by its slug.
|
||||
"""
|
||||
playlist = {}
|
||||
|
||||
query = db.playlist.select(db.playlist.c.slug==bindparam('slug'))
|
||||
logging.debug(f"playlist: '{slug}' requested. Query: {query}")
|
||||
results = self.conn.execute(str(query), {'slug': slug}).fetchone()
|
||||
if not results:
|
||||
return playlist
|
||||
|
||||
playlist = results
|
||||
query = db.entry.select(db.entry.c.playlist_id == bindparam('playlist_id'))
|
||||
logging.debug(f"Retrieving playlist entries. Query: {query}")
|
||||
entries = self.conn.execute(str(query), {'playlist_id': playlist['id']}).fetchall()
|
||||
|
||||
playlist = dict(playlist)
|
||||
playlist['entries'] = [dict(entry) for entry in entries]
|
||||
return playlist
|
||||
|
||||
def json_response(self, playlist: dict, status: int = 200) -> HTTPResponse:
|
||||
"""
|
||||
Create an application/json HTTPResponse object out of a playlist and its entries.
|
||||
"""
|
||||
response = json.dumps(playlist)
|
||||
logging.debug(response)
|
||||
return HTTPResponse(status=status, content_type='application/json', body=response)
|
||||
+33
-6
@@ -1,7 +1,21 @@
|
||||
from bottle import Bottle, auth_basic
|
||||
from groove.auth import is_authenticated
|
||||
import logging
|
||||
import os
|
||||
|
||||
server = Bottle()
|
||||
import bottle
|
||||
from bottle import HTTPResponse
|
||||
from bottle.ext import sqlite
|
||||
|
||||
from groove.auth import is_authenticated
|
||||
from groove.helper import PlaylistDatabaseHelper
|
||||
|
||||
server = bottle.Bottle()
|
||||
|
||||
|
||||
def initialize():
|
||||
"""
|
||||
Configure the sqlite database.
|
||||
"""
|
||||
server.install(sqlite.Plugin(dbfile=os.environ.get('DATABASE_PATH')))
|
||||
|
||||
|
||||
@server.route('/')
|
||||
@@ -9,7 +23,20 @@ def index():
|
||||
return "Groovy."
|
||||
|
||||
|
||||
@server.route('/admin')
|
||||
@auth_basic(is_authenticated)
|
||||
def admin():
|
||||
@server.route('/build')
|
||||
@bottle.auth_basic(is_authenticated)
|
||||
def build():
|
||||
return "Authenticated. Groovy."
|
||||
|
||||
|
||||
@server.route('/playlist/<slug>')
|
||||
def get_playlist(slug, db):
|
||||
"""
|
||||
Retrieve a playlist and its entries by a slug.
|
||||
"""
|
||||
logging.debug(f"Looking up playlist: {slug}...")
|
||||
pldb = PlaylistDatabaseHelper(connection=db)
|
||||
playlist = pldb.playlist(slug)
|
||||
if not playlist:
|
||||
return HTTPResponse(status=404, body="Not found")
|
||||
return pldb.json_response(playlist)
|
||||
|
||||
Reference in New Issue
Block a user