import json
import qrcode
from flask import render_template , flash , redirect , url_for , request , abort , send_file
from flask_login import current_user , login_required
from sqlalchemy import and_
from io import BytesIO
from app import db
from app . main import bp
from app . models import Player , Game , Role , GamePlayer , Objective , ObjectiveMinimalEncoder , LocationEncoder
from app . main . forms import CreateGameForm , ObjectiveForm , PlayerAddForm , PlayerCreateForm , PlayerUpdateForm
@bp . route ( ' / ' )
@bp . route ( ' /index ' )
@login_required
def index ( ) :
if len ( current_user . games ) == 1 :
return redirect ( url_for ( ' main.game_dashboard ' , game_name = current_user . games [ 0 ] . name ) )
return render_template ( " index.html " , title = ' Home ' )
@bp . route ( ' /create_game ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def create_game ( ) :
print ( current_user . is_authenticated )
form = CreateGameForm ( )
if form . validate_on_submit ( ) :
game = Game ( name = form . game_name . data , start_time = form . start_time . data , end_time = form . end_time . data )
game . game_players . append ( GamePlayer ( player = current_user , role = Role [ ' owner ' ] ) )
db . session . add ( game )
db . session . commit ( )
flash ( f " ' { game . name } ' had been created! " )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = game . name ) )
return render_template ( ' create_game.html ' , title = ' Create Game ' , form = form )
@bp . route ( ' /game/<game_name>/dashboard ' )
@login_required
def game_dashboard ( game_name ) :
game = Game . query . filter_by ( name = game_name ) . first_or_404 ( )
role = current_user . role_in_game ( game )
if role == Role . owner :
return render_template ( ' game_owner_dashboard.html ' , title = ' Game Dashboard ' ,
game = game , json = json , objective_encoder = ObjectiveMinimalEncoder , location_encoder = LocationEncoder )
if role == Role . bunny :
return render_template ( ' game_bunny_dashboard.html ' , title = ' Game Dashboard ' ,
game = game , json = json , objective_encoder = ObjectiveMinimalEncoder , location_encoder = LocationEncoder )
if role == Role . hunter :
return render_template ( ' game_hunter_dashboard.html ' , title = ' Game Dashboard ' ,
game = game , json = json , location_encoder = LocationEncoder )
if role == Role . none :
return render_template ( ' game_hunter_dashboard.html ' , title = ' Game Dashboard ' ,
game = game , json = json , location_encoder = LocationEncoder )
if role is None :
abort ( 403 )
@bp . route ( ' /game/<game_name>/addplayer ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def add_player ( game_name ) :
game = Game . query . filter_by ( name = game_name ) . first_or_404 ( )
if not game . owned_by ( current_user ) :
abort ( 403 )
form_add = PlayerAddForm ( )
form_create = PlayerCreateForm ( )
if form_add . submit_add . data and form_add . validate_on_submit ( ) :
player = Player . query . filter_by ( form_add . name . data ) . first_or_404 ( )
game . game_players . append ( GamePlayer ( player = player , role = Role [ form_create . role . data ] ) )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = game . name ) )
if form_create . submit_create . data and form_create . validate_on_submit ( ) :
player = Player ( name = form_create . name . data )
player . set_auth_hash ( )
game . game_players . append ( GamePlayer ( player = player , role = Role [ form_create . role . data ] ) )
db . session . commit ( )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = game . name ) )
return render_template ( ' add_player.html ' , title = f ' Add Player for { game_name } ' , form_add = form_add , form_create = form_create , game = game )
@bp . route ( ' /game/<game_name>/removeplayer/<player_name> ' )
@login_required
def remove_player ( game_name , player_name ) :
game = Game . query . filter_by ( name = game_name ) . first_or_404 ( )
if not game . owned_by ( current_user ) :
abort ( 403 )
player = Player . query . filter ( and_ ( Player . name == player_name , Player . games . contains ( game ) ) ) . first_or_404 ( )
game . players . remove ( player )
db . session . commit ( )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = game . name ) )
@bp . route ( ' /game/<game_name>/player/<player_name> ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def game_player ( game_name , player_name ) :
game = Game . query . filter_by ( name = game_name ) . first_or_404 ( )
if not game . owned_by ( current_user ) :
abort ( 403 )
player = Player . query . filter ( and_ ( Player . name == player_name , Player . games . contains ( game ) ) ) . first_or_404 ( )
gameplayer = [ gameplayer for gameplayer in player . player_games if gameplayer . game == game ] [ 0 ]
form = PlayerUpdateForm ( role = gameplayer . role . name )
if form . validate_on_submit ( ) :
gameplayer . role = Role [ form . role . data ]
db . session . commit ( )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = game . name ) )
return render_template ( ' player.html ' , title = f ' { player . name } in { game_name } ' , game = game , player = player , form = form , json = json , location_encoder = LocationEncoder )
@bp . route ( ' /player/<auth_hash>/qrcode.png ' )
@login_required
def player_qrcode ( auth_hash ) :
player = Player . query . filter_by ( auth_hash = auth_hash ) . first_or_404 ( )
if not current_user . owns_game_played_by ( player ) :
abort ( 403 )
img = generate_qr_code ( url_for ( ' main.player ' , auth_hash = auth_hash , _external = True ) )
return serve_pil_image ( img )
@bp . route ( ' /player/<auth_hash> ' )
@login_required
def player ( auth_hash ) :
player = Player . query . filter_by ( auth_hash = auth_hash ) . first_or_404 ( )
return render_template ( ' player.html ' , title = f ' Player: { player . name } ' , player = player )
@bp . route ( ' /game/<game_name>/add_objective ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def add_objective ( game_name ) :
game = Game . query . filter_by ( name = game_name ) . first_or_404 ( )
if not game . owned_by ( current_user ) :
abort ( 403 )
form = ObjectiveForm ( )
objective = Objective ( name = ' ' , latitude = 52.0932 , longitude = 5.12405 )
if form . validate_on_submit ( ) :
objective = Objective ( name = form . objective_name . data , longitude = form . longitude . data , latitude = form . latitude . data )
objective . set_hash ( )
game . objectives . append ( objective )
db . session . commit ( )
flash ( f " Objective has been added! " )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = game . name ) )
return render_template ( ' objective.html ' , title = f ' Add Objective for { game_name } ' , form = form , objective = objective , owner = True )
@bp . route ( ' /objective/<objective_hash>/delete ' , methods = [ ' GET ' ] )
@login_required
def delete_objective ( objective_hash ) :
objective = Objective . query . filter_by ( hash = objective_hash ) . first_or_404 ( )
if not objective . owned_by ( current_user ) :
abort ( 403 )
else :
db . session . delete ( objective )
db . session . commit ( )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = objective . game . name ) )
def generate_qr_code ( url ) :
qr = qrcode . QRCode (
version = None ,
error_correction = qrcode . constants . ERROR_CORRECT_M ,
box_size = 30 ,
border = 4 ,
)
qr . add_data ( url )
qr . make ( fit = True )
return qr . make_image ( fill_color = ' black ' , back_color = ' white ' )
# Source: https://stackoverflow.com/questions/7877282/how-to-send-image-generated-by-pil-to-browser
def serve_pil_image ( pil_img ) :
img_io = BytesIO ( )
pil_img . save ( img_io , ' PNG ' , quality = 70 )
img_io . seek ( 0 )
return send_file ( img_io , mimetype = ' image/png ' )
@bp . route ( ' /objective/<objective_hash>/qrcode.png ' )
@login_required
def objective_qrcode ( objective_hash ) :
objective = Objective . query . filter_by ( hash = objective_hash ) . first_or_404 ( )
if not objective . owned_by ( current_user ) :
abort ( 403 )
img = generate_qr_code ( url_for ( ' main.objective ' , objective_hash = objective . hash , _external = True ) )
return serve_pil_image ( img )
@bp . route ( ' /objective/<objective_hash> ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def objective ( objective_hash ) :
objective = Objective . query . filter_by ( hash = objective_hash ) . first_or_404 ( )
owner = objective . owned_by ( current_user )
qrcode = generate_qr_code ( objective ) if owner else None
form = ObjectiveForm ( )
if form . submit . data and form . validate ( ) and owner :
objective . name = form . objective_name . data
objective . longitude = form . longitude . data
objective . latitude = form . latitude . data
db . session . commit ( )
return redirect ( url_for ( ' main.game_dashboard ' , game_name = objective . game . name ) )
return render_template ( ' objective.html ' , title = ' Objective view ' , objective = objective , owner = owner , form = form , qrcode = qrcode )