initial
This commit is contained in:
304
backend/routes/admin.py
Normal file
304
backend/routes/admin.py
Normal file
@@ -0,0 +1,304 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from backend.models import db, Game, Team
|
||||
from backend.services import game_service
|
||||
from backend.app import socketio
|
||||
from backend.auth.middleware import require_auth
|
||||
|
||||
bp = Blueprint('admin', __name__, url_prefix='/api/admin')
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/start', methods=['POST'])
|
||||
@require_auth
|
||||
def start_game(game_id):
|
||||
"""Start/activate a game"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.start_game(game, socketio)
|
||||
return jsonify({'message': 'Game started successfully', 'game': game.to_dict()}), 200
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/next', methods=['POST'])
|
||||
@require_auth
|
||||
def next_question(game_id):
|
||||
"""Move to next question"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
if game_service.next_question(game, socketio):
|
||||
return jsonify({'message': 'Moved to next question', 'current_index': game.current_question_index}), 200
|
||||
else:
|
||||
return jsonify({'error': 'Already at last question'}), 400
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/prev', methods=['POST'])
|
||||
@require_auth
|
||||
def previous_question(game_id):
|
||||
"""Move to previous question"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
if game_service.previous_question(game, socketio):
|
||||
return jsonify({'message': 'Moved to previous question', 'current_index': game.current_question_index}), 200
|
||||
else:
|
||||
return jsonify({'error': 'Already at first question'}), 400
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/award', methods=['POST'])
|
||||
@require_auth
|
||||
def award_points(game_id):
|
||||
"""Award points to a team
|
||||
|
||||
Expected JSON: { "team_id": int, "points": int }
|
||||
"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
data = request.get_json()
|
||||
|
||||
if not data or 'team_id' not in data or 'points' not in data:
|
||||
return jsonify({'error': 'team_id and points are required'}), 400
|
||||
|
||||
team_id = data['team_id']
|
||||
points = data['points']
|
||||
|
||||
team = Team.query.get_or_404(team_id)
|
||||
|
||||
# Verify team belongs to this game
|
||||
if team.game_id != game_id:
|
||||
return jsonify({'error': 'Team does not belong to this game'}), 400
|
||||
|
||||
try:
|
||||
game_service.award_points(game, team, points, socketio)
|
||||
return jsonify({'message': 'Points awarded successfully', 'team': team.to_dict()}), 200
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/current', methods=['GET'])
|
||||
@require_auth
|
||||
def get_current_state(game_id):
|
||||
"""Get current game state with answer (admin only)"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
state = game_service.get_admin_game_state(game)
|
||||
return jsonify(state), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/toggle-answer', methods=['POST'])
|
||||
@require_auth
|
||||
def toggle_answer_visibility(game_id):
|
||||
"""Toggle answer visibility on contestant screen
|
||||
|
||||
Expected JSON: { "show_answer": bool }
|
||||
"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
data = request.get_json()
|
||||
|
||||
if not data or 'show_answer' not in data:
|
||||
return jsonify({'error': 'show_answer is required'}), 400
|
||||
|
||||
show_answer = data['show_answer']
|
||||
|
||||
try:
|
||||
game_service.toggle_answer_visibility(game, show_answer, socketio)
|
||||
return jsonify({'message': 'Answer visibility toggled', 'show_answer': show_answer}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/pause-timer', methods=['POST'])
|
||||
@require_auth
|
||||
def pause_timer(game_id):
|
||||
"""Pause or resume the timer
|
||||
|
||||
Expected JSON: { "paused": bool }
|
||||
"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
data = request.get_json()
|
||||
|
||||
if not data or 'paused' not in data:
|
||||
return jsonify({'error': 'paused is required'}), 400
|
||||
|
||||
paused = data['paused']
|
||||
|
||||
try:
|
||||
game_service.toggle_timer_pause(game, paused, socketio)
|
||||
return jsonify({'message': 'Timer pause state updated', 'paused': paused}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/reset-timer', methods=['POST'])
|
||||
@require_auth
|
||||
def reset_timer(game_id):
|
||||
"""Reset the timer to 30 seconds"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.reset_timer(game, socketio)
|
||||
return jsonify({'message': 'Timer reset'}), 200
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/end', methods=['POST'])
|
||||
@require_auth
|
||||
def end_game(game_id):
|
||||
"""End/deactivate a game"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.end_game(game, socketio)
|
||||
return jsonify({'message': 'Game ended successfully', 'game': game.to_dict()}), 200
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/restart', methods=['POST'])
|
||||
@require_auth
|
||||
def restart_game(game_id):
|
||||
"""Restart a game (clear scores and reset to waiting state)"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.restart_game(game, socketio)
|
||||
return jsonify({'message': 'Game restarted successfully', 'game': game.to_dict()}), 200
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/team/<int:team_id>/use-lifeline', methods=['POST'])
|
||||
@require_auth
|
||||
def use_lifeline(game_id, team_id):
|
||||
"""Use a phone-a-friend lifeline for a team"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
team = Team.query.get_or_404(team_id)
|
||||
|
||||
# Verify team belongs to this game
|
||||
if team.game_id != game_id:
|
||||
return jsonify({'error': 'Team does not belong to this game'}), 400
|
||||
|
||||
if team.phone_a_friend_count <= 0:
|
||||
return jsonify({'error': 'No lifelines remaining'}), 400
|
||||
|
||||
try:
|
||||
team.phone_a_friend_count -= 1
|
||||
db.session.commit()
|
||||
|
||||
# Broadcast lifeline update
|
||||
game_service.broadcast_lifeline_update(game, team, socketio)
|
||||
|
||||
return jsonify({'message': 'Lifeline used', 'team': team.to_dict()}), 200
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/team/<int:team_id>/add-lifeline', methods=['POST'])
|
||||
@require_auth
|
||||
def add_lifeline(game_id, team_id):
|
||||
"""Add a phone-a-friend lifeline to a team"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
team = Team.query.get_or_404(team_id)
|
||||
|
||||
# Verify team belongs to this game
|
||||
if team.game_id != game_id:
|
||||
return jsonify({'error': 'Team does not belong to this game'}), 400
|
||||
|
||||
try:
|
||||
team.phone_a_friend_count += 1
|
||||
db.session.commit()
|
||||
|
||||
# Broadcast lifeline update
|
||||
game_service.broadcast_lifeline_update(game, team, socketio)
|
||||
|
||||
return jsonify({'message': 'Lifeline added', 'team': team.to_dict()}), 200
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/audio/play', methods=['POST'])
|
||||
@require_auth
|
||||
def play_audio(game_id):
|
||||
"""Admin controls audio playback for contestants"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.broadcast_audio_play(game, socketio)
|
||||
return jsonify({'message': 'Audio play command sent'}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/audio/pause', methods=['POST'])
|
||||
@require_auth
|
||||
def pause_audio(game_id):
|
||||
"""Pause audio for all contestants"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.broadcast_audio_pause(game, socketio)
|
||||
return jsonify({'message': 'Audio pause command sent'}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/audio/stop', methods=['POST'])
|
||||
@require_auth
|
||||
def stop_audio(game_id):
|
||||
"""Stop and reset audio for all contestants"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
|
||||
try:
|
||||
game_service.broadcast_audio_stop(game, socketio)
|
||||
return jsonify({'message': 'Audio stop command sent'}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@bp.route('/game/<int:game_id>/audio/seek', methods=['POST'])
|
||||
@require_auth
|
||||
def seek_audio(game_id):
|
||||
"""Seek audio to specific position
|
||||
|
||||
Expected JSON: { "position": float }
|
||||
"""
|
||||
game = Game.query.get_or_404(game_id)
|
||||
data = request.get_json()
|
||||
|
||||
if not data or 'position' not in data:
|
||||
return jsonify({'error': 'position is required'}), 400
|
||||
|
||||
try:
|
||||
position = float(data['position'])
|
||||
game_service.broadcast_audio_seek(game, position, socketio)
|
||||
return jsonify({'message': f'Audio seeked to {position}s'}), 200
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
Reference in New Issue
Block a user