from flask_socketio import emit, join_room from sqlalchemy.exc import IntegrityError from .. import socketio from ..models import db from ..models.session import Session, Vote from ..services.match_modes import handle_final_round_vote, is_final_round_mode from ..services.session_recipes import add_recipe_batch, replace_recipe_batch, serialize_recipe from ..services.session_settings import get_match_mode, get_required_likes, get_voting_round, set_match_mode, set_required_likes, set_voting_round def room_name(code): return f"session:{code.upper()}" def emit_session_update(session): socketio.emit( "session:update", { "code": session.code, "status": session.status, "currentRecipeIndex": session.current_recipe_index, "matchedRecipeId": session.matched_recipe_id, "participants": [ {"id": p.id, "name": p.name, "isHost": p.is_host} for p in session.participants ], "recipes": [serialize_recipe(recipe) for recipe in session.recipes], "requiredLikes": get_required_likes(session), "matchMode": get_match_mode(session), "votingRound": get_voting_round(session), }, room=room_name(session.code), ) @socketio.on("session:subscribe") def subscribe(data): code = data.get("code", "").upper() session = Session.query.filter_by(code=code).first() if not session: emit("error", {"message": "Session nicht gefunden."}) return join_room(room_name(code)) emit_session_update(session) @socketio.on("session:start") def start_session(data): code = data.get("code", "").upper() participant_id = data.get("participantId") session = Session.query.filter_by(code=code).first() if not session: emit("error", {"message": "Session nicht gefunden."}) return host = next((p for p in session.participants if p.id == participant_id and p.is_host), None) if not host: emit("error", {"message": "Nur der Host kann starten."}) return session.status = "running" session.current_recipe_index = 0 session.matched_recipe_id = None set_voting_round(session, 1) db.session.commit() emit_session_update(session) @socketio.on("session:set_required_likes") def update_required_likes(data): code = data.get("code", "").upper() participant_id = data.get("participantId") session = Session.query.filter_by(code=code).first() if not session: emit("error", {"message": "Session nicht gefunden."}) return host = next((p for p in session.participants if p.id == participant_id and p.is_host), None) if not host: emit("error", {"message": "Nur der Host kann die Match-Regel ändern."}) return if session.status != "waiting": emit("error", {"message": "Die Match-Regel kann nur in der Lobby geändert werden."}) return set_required_likes(session, data.get("requiredLikes", len(session.participants))) db.session.commit() emit_session_update(session) @socketio.on("session:set_match_mode") def update_match_mode(data): code = data.get("code", "").upper() participant_id = data.get("participantId") session = Session.query.filter_by(code=code).first() if not session: emit("error", {"message": "Session nicht gefunden."}) return host = next((p for p in session.participants if p.id == participant_id and p.is_host), None) if not host: emit("error", {"message": "Nur der Host kann den Modus ändern."}) return if session.status != "waiting": emit("error", {"message": "Der Modus kann nur in der Lobby geändert werden."}) return set_match_mode(session, data.get("matchMode")) db.session.commit() emit_session_update(session) @socketio.on("session:restart") def restart_session(data): code = data.get("code", "").upper() participant_id = data.get("participantId") session = Session.query.filter_by(code=code).first() if not session: emit("error", {"message": "Session nicht gefunden."}) return host = next((p for p in session.participants if p.id == participant_id and p.is_host), None) if not host: emit("error", {"message": "Nur der Host kann neu starten."}) return session.status = "running" session.current_recipe_index = 0 set_voting_round(session, 1) replace_recipe_batch(session) db.session.commit() emit_session_update(session) @socketio.on("vote") def vote(data): code = data.get("code", "").upper() participant_id = data.get("participantId") recipe_id = data.get("recipeId") vote_value = data.get("vote") if vote_value not in ["yes", "no"]: emit("error", {"message": "Ungültige Stimme."}) return session = Session.query.filter_by(code=code).first() if not session or session.status != "running": emit("error", {"message": "Session läuft nicht."}) return recipe = next((r for r in session.recipes if r.id == recipe_id), None) if not recipe: emit("error", {"message": "Rezept nicht gefunden."}) return db.session.add(Vote(session_id=session.id, participant_id=participant_id, recipe_id=recipe.id, vote=vote_value)) try: db.session.commit() except IntegrityError: db.session.rollback() return if is_final_round_mode(session): result = handle_final_round_vote(session, recipe) db.session.commit() if result == "match": matched_recipe = next((r for r in session.recipes if r.id == session.matched_recipe_id), recipe) socketio.emit("session:match", {"recipe": serialize_recipe(matched_recipe)}, room=room_name(code)) emit_session_update(session) return yes_count = Vote.query.filter_by(session_id=session.id, recipe_id=recipe.id, vote="yes").count() if yes_count >= get_required_likes(session): session.status = "finished" session.matched_recipe_id = recipe.id db.session.commit() socketio.emit("session:match", {"recipe": serialize_recipe(recipe)}, room=room_name(code)) emit_session_update(session) return participant_vote_count = Vote.query.filter_by( session_id=session.id, participant_id=participant_id, ).count() if participant_vote_count >= len(session.recipes): add_recipe_batch(session) db.session.commit() emit_session_update(session)