restructure session management

This commit is contained in:
matthias@matsewe.de
2024-05-24 11:58:18 +02:00
parent d05f1f6760
commit fe4dafb560
6 changed files with 109 additions and 17 deletions

View File

@@ -1,8 +1,11 @@
import app.models as models import app.models as models
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm.attributes import flag_modified
def get_songs_and_vote_for_user(db, user_id) -> list[models.Song]: def get_songs_and_vote_for_session(db, session_name) -> list[models.Song]:
votes = db.query(models.Vote).filter(models.Vote.user_id == user_id).subquery() session_entry = activate_session(db, session_name)
votes = db.query(models.Vote).filter(models.Vote.session_id == session_entry.id).subquery()
songs_and_votes = db.query( songs_and_votes = db.query(
models.Song, votes.c.vote models.Song, votes.c.vote
@@ -58,12 +61,38 @@ def create_song(db,
db.commit() db.commit()
def create_or_update_vote(db, song_id, user_id, vote): def create_or_update_vote(db, song_id, session_name, vote):
session_entry = activate_session(db, session_name)
vote_entry = db.query(models.Vote).filter( vote_entry = db.query(models.Vote).filter(
(models.Vote.user_id == user_id) & (models.Vote.song_id == song_id)).first() (models.Vote.session_id == session_entry.id) & (models.Vote.song_id == song_id)).first()
if vote_entry: if vote_entry:
vote_entry.vote = str(vote) # type: ignore vote_entry.vote = str(vote) # type: ignore
else: else:
vote_entry = models.Vote(song_id=song_id, user_id=user_id, vote=vote) vote_entry = models.Vote(song_id=song_id, session_id=session_entry.id, vote=vote)
db.add(vote_entry) db.add(vote_entry)
db.commit() db.commit()
def activate_session(db, session_name):
session_entry = db.query(models.Session).filter(
(models.Session.session_name == session_name)).first()
if session_entry:
session_entry.active = True
else:
session_entry = models.Session(session_name=session_name, active=True)
db.add(session_entry)
flag_modified(session_entry, "active")
db.commit()
return session_entry
def deactivate_session(db, session_name):
session_entry = db.query(models.Session).filter(
(models.Session.session_name == session_name)).first()
if session_entry:
session_entry.active = False
else:
session_entry = models.Session(session_name=session_name, active=False)
db.add(session_entry)
db.commit()

View File

@@ -1,10 +1,10 @@
from fastapi import FastAPI, Request, Depends from fastapi import FastAPI, Request, Depends
from app.routers import admin, user, songs from app.routers import admin, user, songs, session
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from app.database import engine, Base, get_db from app.database import engine, Base, get_db
from app.crud import get_songs_and_vote_for_user from app.crud import get_songs_and_vote_for_session
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from typing import Annotated from typing import Annotated
from app.schemas import Song from app.schemas import Song
@@ -16,6 +16,7 @@ app = FastAPI()
app.include_router(admin.router) app.include_router(admin.router)
app.include_router(user.router) app.include_router(user.router)
app.include_router(songs.router) app.include_router(songs.router)
app.include_router(session.router)
app.mount("/static", StaticFiles(directory="static"), name="static") app.mount("/static", StaticFiles(directory="static"), name="static")
@@ -28,7 +29,7 @@ async def root(request: Request, session_id : str = "", db: Annotated[Session, D
request=request, name="landing.html" request=request, name="landing.html"
) )
else: else:
songs = [Song(**s.__dict__, vote=v) for s, v in get_songs_and_vote_for_user(db, session_id)] songs = [Song(**s.__dict__, vote=v) for s, v in get_songs_and_vote_for_session(db, session_id)]
songs_by_category = {} songs_by_category = {}
all_categories = set() all_categories = set()

View File

@@ -25,11 +25,20 @@ class Song(Base):
singable: Mapped[Optional[bool]] singable: Mapped[Optional[bool]]
class Session(Base):
__tablename__ = 'sessions'
id: Mapped[int] = mapped_column(primary_key=True)
session_name: Mapped[int]
active: Mapped[bool]
time_created: Mapped[datetime] = mapped_column(server_default=func.now())
time_updated: Mapped[Optional[datetime]
] = mapped_column(onupdate=func.now())
class Vote(Base): class Vote(Base):
__tablename__ = 'votes' __tablename__ = 'votes'
id: Mapped[int] = mapped_column(primary_key=True) id: Mapped[int] = mapped_column(primary_key=True)
song_id: Mapped[int] = mapped_column(Integer, ForeignKey("songs.id")) song_id: Mapped[int] = mapped_column(Integer, ForeignKey("songs.id"))
user_id: Mapped[int] session_id: Mapped[int] = mapped_column(Integer, ForeignKey("sessions.id"))
vote: Mapped[Optional[int]] vote: Mapped[Optional[int]]
time_created: Mapped[datetime] = mapped_column(server_default=func.now()) time_created: Mapped[datetime] = mapped_column(server_default=func.now())
time_updated: Mapped[Optional[datetime] time_updated: Mapped[Optional[datetime]

27
app/routers/session.py Normal file
View File

@@ -0,0 +1,27 @@
from typing import Annotated
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
import app.models as models
from app.database import get_db
from app.schemas import Song
import app.crud as crud
router = APIRouter(
prefix="/session",
# dependencies=[Security(get_current_user, scopes=["public"])],
responses={404: {"description": "Not found"}},
)
@router.put("/{session_id}")
async def activate_session(session_id: str = "", db: Annotated[Session, Depends(get_db)] = None):
crud.activate_session(db, session_id)
@router.delete("/{session_id}")
async def deactivate_session(session_id: str = "", db: Annotated[Session, Depends(get_db)] = None):
crud.deactivate_session(db, session_id)
#@router.get("/{session_id}")
#async def get_session(session_id: str = "", db: Annotated[Session, Depends(get_db)] = None):
# return "get " + session_id

View File

@@ -5,7 +5,7 @@ from sqlalchemy.orm import Session
import app.models as models import app.models as models
from app.database import get_db from app.database import get_db
from app.schemas import Song from app.schemas import Song
from app.crud import get_songs_and_vote_for_user, create_or_update_vote, get_all_songs_and_votes from app.crud import get_songs_and_vote_for_session, create_or_update_vote, get_all_songs_and_votes
router = APIRouter( router = APIRouter(
prefix="/songs", prefix="/songs",
@@ -15,13 +15,13 @@ router = APIRouter(
@router.get("/") @router.get("/")
async def get_songs(user_id: str = "", db: Annotated[Session, Depends(get_db)] = None) -> list[Song]: async def get_songs(session_id: str = "", db: Annotated[Session, Depends(get_db)] = None) -> list[Song]:
return [Song(**s.__dict__, vote=v) for s, v in get_songs_and_vote_for_user(db, user_id)] return [Song(**s.__dict__, vote=v) for s, v in get_songs_and_vote_for_session(db, session_id)]
@router.post("/{song_id}/vote") @router.post("/{song_id}/vote")
async def vote(song_id: str, user_id: str, vote: int, db: Annotated[Session, Depends(get_db)]): async def vote(song_id: str, session_id: str, vote: int, db: Annotated[Session, Depends(get_db)]):
create_or_update_vote(db, song_id, user_id, vote) create_or_update_vote(db, song_id, session_id, vote)
@router.get("/evaluation") @router.get("/evaluation")

View File

@@ -12,6 +12,34 @@
<script src="https://open.spotify.com/embed/iframe-api/v1" async></script> <script src="https://open.spotify.com/embed/iframe-api/v1" async></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript"> <script type="text/javascript">
const session_id = "{{ session_id }}";
function activate_session() {
$.ajax({
url: "/session/" + session_id,
method: "PUT"
})
}
function deactivate_session() {
$.ajax({
url: "/session/" + session_id,
method: "DELETE"
})
}
$( window ).on("load", activate_session);
$( window ).on("beforeunload", deactivate_session);
$( window ).on("pagehide", deactivate_session);
$(document).on('visibilitychange', function() {
if (document.visibilityState == 'hidden') {
deactivate_session();
} else {
activate_session()
}
});
var spotify_embed_controller; var spotify_embed_controller;
window.onSpotifyIframeApiReady = (IFrameAPI) => { window.onSpotifyIframeApiReady = (IFrameAPI) => {
@@ -79,8 +107,6 @@
} }
function vote(song_id, vote) { function vote(song_id, vote) {
const session_id = "{{ session_id }}";
no_button = $("#song-" + song_id).find(".button-no") no_button = $("#song-" + song_id).find(".button-no")
yes_button = $("#song-" + song_id).find(".button-yes") yes_button = $("#song-" + song_id).find(".button-yes")
neutral_button = $("#song-" + song_id).find(".button-neutral") neutral_button = $("#song-" + song_id).find(".button-neutral")
@@ -103,7 +129,7 @@
} }
$.ajax({ $.ajax({
url: "/songs/" + song_id + "/vote?" + $.param({ user_id: session_id, vote: vote }), url: "/songs/" + song_id + "/vote?" + $.param({ session_id: session_id, vote: vote }),
method: "POST" method: "POST"
}) })
} }