diff --git a/app/crud.py b/app/crud.py index 2547a05..d22dfaf 100644 --- a/app/crud.py +++ b/app/crud.py @@ -10,9 +10,7 @@ def get_songs_and_vote_for_session(db, session_name) -> list[models.Song]: models.Vote.session_id == session_entry.id).subquery() songs_and_votes = db.query( - models.Song, votes.c.vote - ).filter( - models.Song.singable == True + models.Song, votes.c.vote, votes.c.comment ).join(votes, isouter=True).filter().all() return songs_and_votes @@ -46,7 +44,8 @@ def create_song(db, arng_url, categories, main_category, - singable + singable, + comment ): s = models.Song(og_artist=og_artist, aca_artist=aca_artist, @@ -61,7 +60,8 @@ def create_song(db, arng_url=arng_url, categories=categories, main_category=main_category, - singable=singable) + singable=singable, + comment=comment) db.add(s) db.commit() @@ -80,6 +80,21 @@ def create_or_update_vote(db, song_id, session_name, vote): db.add(vote_entry) db.commit() +def create_or_update_comment(db, song_id, session_name, comment): + session_entry = activate_session(db, session_name) + + if comment == "": + comment = None + + vote_entry = db.query(models.Vote).filter( + (models.Vote.session_id == session_entry.id) & (models.Vote.song_id == song_id)).first() + if vote_entry: + vote_entry.comment = comment # type: ignore + else: + vote_entry = models.Vote( + song_id=song_id, session_id=session_entry.id, comment=comment) + db.add(vote_entry) + db.commit() def activate_session(db, session_name): session_entry = db.query(models.Session).filter( @@ -104,3 +119,20 @@ def deactivate_session(db, session_name): session_entry = models.Session(session_name=session_name, active=False) db.add(session_entry) db.commit() + + +def get_setting(db, key): + entry = db.query(models.Config.value).filter(models.Config.key == key).first() + if entry: + return entry[0] + else: + return None + +def set_setting(db, key, value): + setting_entry = db.query(models.Config).filter(models.Config.key == key).first() + if setting_entry: + setting_entry.value = value + else: + setting_entry = models.Config(key=key, value=value) + db.add(setting_entry) + db.commit() \ No newline at end of file diff --git a/app/database.py b/app/database.py index cde0f3a..f3a63c6 100644 --- a/app/database.py +++ b/app/database.py @@ -21,5 +21,6 @@ async def get_db(): class Base(DeclarativeBase): type_annotation_map = { - dict[str, bool]: PickleType + dict[str, bool]: PickleType, + object: PickleType } \ No newline at end of file diff --git a/app/main.py b/app/main.py index 7e43d83..6ff1bfc 100644 --- a/app/main.py +++ b/app/main.py @@ -4,10 +4,11 @@ from fastapi.staticfiles import StaticFiles from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from app.database import engine, Base, get_db -from app.crud import get_songs_and_vote_for_session +from app.crud import get_songs_and_vote_for_session, get_setting from sqlalchemy.orm import Session from typing import Annotated from app.schemas import Song +import json Base.metadata.create_all(engine) @@ -31,17 +32,23 @@ async def root(request: Request) -> HTMLResponse: @app.get("/vote") -async def vote(request: Request, session_id: str, db: Annotated[Session, Depends(get_db)]) -> HTMLResponse: - songs = [Song(**s.__dict__, vote=v) - for s, v in get_songs_and_vote_for_session(db, session_id)] +async def vote(request: Request, session_id: str, db: Session = Depends(get_db)) -> HTMLResponse: + veto_mode = get_setting(db, "veto_mode") + + songs = [Song(**s.__dict__, vote=v, vote_comment=c) + for s, v, c in get_songs_and_vote_for_session(db, session_id)] songs_by_category = {} all_categories = set() wildcard_songs = [] current_songs = [] + other_songs = [] for song in songs: + if (not song.singable) and (not veto_mode): + continue + if song.is_current: current_songs.append(song) continue @@ -50,26 +57,35 @@ async def vote(request: Request, session_id: str, db: Annotated[Session, Depends wildcard_songs.append(song) continue + if not song.main_category: + other_songs.append(song) + continue + if song.main_category not in songs_by_category: songs_by_category[song.main_category] = [] songs_by_category[song.main_category].append(song) all_categories.update(song.categories.keys()) + songs_by_category["Sonstige"] = other_songs songs_by_category["Wildcard (nicht a cappella)"] = wildcard_songs songs_by_category["Aktuelles Programm"] = current_songs all_categories = list(all_categories) all_categories.sort() + all_categories.append("Sonstige") all_categories.append("Wildcard (nicht a cappella)") all_categories.append("Aktuelles Programm") - print(all_categories) + # print(all_categories) + # with open('/data/songs_by_cat.json', 'w') as f: + # json.dump({cat : [s.__dict__ for s in songs] for cat, songs in songs_by_category.items()}, f) return templates.TemplateResponse( request=request, name="voting.html", context={ "songs_by_category": songs_by_category, "all_categories": {c: i+1 for i, c in enumerate(all_categories)}, - "session_id": session_id + "session_id": session_id, + "veto_mode": veto_mode } ) diff --git a/app/models.py b/app/models.py index 8e11065..f0534fa 100644 --- a/app/models.py +++ b/app/models.py @@ -24,6 +24,7 @@ class Song(Base): categories: Mapped[Optional[dict[str, bool]]] main_category: Mapped[Optional[str]] singable: Mapped[Optional[bool]] + comment: Mapped[Optional[str]] class Session(Base): @@ -42,6 +43,13 @@ class Vote(Base): song_id: Mapped[int] = mapped_column(Integer, ForeignKey("songs.id")) session_id: Mapped[int] = mapped_column(Integer, ForeignKey("sessions.id")) vote: Mapped[Optional[int]] + comment: Mapped[Optional[str]] time_created: Mapped[datetime] = mapped_column(server_default=func.now()) time_updated: Mapped[Optional[datetime] ] = mapped_column(onupdate=func.now()) + +class Config(Base): + __tablename__ = 'config' + #id: Mapped[int] = mapped_column(primary_key=True) + key: Mapped[str] = mapped_column(primary_key=True) + value: Mapped[object] diff --git a/app/routers/admin.py b/app/routers/admin.py index 93da6e3..83beaa7 100644 --- a/app/routers/admin.py +++ b/app/routers/admin.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import Session from app.database import get_db, engine, Base from app.routers.user import get_current_user -from app.crud import create_song +from app.crud import create_song, get_setting, set_setting router = APIRouter( prefix="/admin", @@ -66,7 +66,7 @@ def get_spotify_id(url): @router.post("/load_list") -async def create_upload_file(db: Session = Depends(get_db)): +async def create_upload_file(include_non_singable: bool = False, db: Session = Depends(get_db)): Base.metadata.drop_all(engine) Base.metadata.create_all(engine) @@ -78,16 +78,24 @@ async def create_upload_file(db: Session = Depends(get_db)): category_names = list(song_list.iloc[0][8:17]) for i, row in song_list[1:].iterrows(): + if (row[17] == "nein") and not include_non_singable: + continue + row = np.array(row) + if not row[2]: # no title + continue + yt_id = get_youtube_id(row[3]) spfy_id = get_spotify_id(row[3]) categories = {n: v for n, v in zip( category_names, row[8:17] != None)} - if (not np.any(list(categories.values()))) and (row[5] != "ja"): - continue + if (not np.any(list(categories.values()))): + main_category = None + else: + main_category = category_names[get_main_category(row[8:17])] create_song(db, og_artist=row[0], @@ -102,6 +110,18 @@ async def create_upload_file(db: Session = Depends(get_db)): is_aca=row[6] == "ja", arng_url=row[7], categories=categories, - main_category=category_names[get_main_category(row[8:17])], - singable=row[17] != "nein" + main_category=main_category, + singable=row[17] != "nein", + comment=row[18] ) + + +@router.post("/toggle_veto_mode") +async def toggle_veto_mode(db: Session = Depends(get_db)) -> bool: + veto_setting = get_setting(db, "veto_mode") + if veto_setting: + set_setting(db, "veto_mode", False) + return False + else: + set_setting(db, "veto_mode", True) + return True diff --git a/app/routers/songs.py b/app/routers/songs.py index e4d1b90..524f8d7 100644 --- a/app/routers/songs.py +++ b/app/routers/songs.py @@ -5,7 +5,7 @@ from sqlalchemy.orm import Session import app.models as models from app.database import get_db from app.schemas import Song -from app.crud import get_songs_and_vote_for_session, 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, create_or_update_comment router = APIRouter( prefix="/songs", @@ -16,13 +16,17 @@ router = APIRouter( @router.get("/") 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_session(db, session_id)] + return [Song(**s.__dict__, vote=v, vote_comment=c) for s, v, c in get_songs_and_vote_for_session(db, session_id)] @router.post("/{song_id}/vote") async def vote(song_id: str, session_id: str, vote: int, db: Annotated[Session, Depends(get_db)]): create_or_update_vote(db, song_id, session_id, vote) +@router.post("/{song_id}/comment") +async def comment(song_id: str, session_id: str, comment: str, db: Annotated[Session, Depends(get_db)]): + create_or_update_comment(db, song_id, session_id, comment) + #create_or_update_vote(db, song_id, session_id, vote) @router.get("/evaluation") async def get_evaluation(db: Annotated[Session, Depends(get_db)] = None) -> dict[int, dict[int, int]]: diff --git a/app/schemas.py b/app/schemas.py index 149e0d2..a2150c4 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -17,4 +17,6 @@ class Song(BaseModel): categories: Optional[dict[str, bool]] main_category: Optional[str] singable: Optional[bool] + comment: Optional[str] vote: Optional[int] + vote_comment: Optional[str] diff --git a/static/site.css b/static/site.css index 3ea7fae..a3b4aa1 100644 --- a/static/site.css +++ b/static/site.css @@ -224,8 +224,6 @@ font-size: 0.7em; } - - h1 { font-family: sans-serif; padding: 0.1em; diff --git a/templates/voting.html b/templates/voting.html index 45763c3..e646b69 100644 --- a/templates/voting.html +++ b/templates/voting.html @@ -9,6 +9,19 @@ + {% if veto_mode %} + + {% endif %} +
+ {% if veto_mode %} +