You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
8.4 KiB

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():
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(Game.game_players.any(and_(GamePlayer.player.has(Player.name == current_user.name), GamePlayer.role == 'owner'))).first_or_404()
game = Game.query.filter_by(name=game_name).first_or_404()
if not is_game_owner(game):
abort(403)
return render_template('game_dashboard.html', title='Game Dashboard', game=game, json=json, objective_encoder=ObjectiveMinimalEncoder, location_encoder=LocationEncoder)
@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 is_game_owner(game):
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 is_game_owner(game):
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 is_game_owner(game):
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 is_player_game_owner(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)
'''given player is an owner of the given game'''
def is_game_owner(game, owner=current_user):
return owner in [gameplayer.player for gameplayer in game.game_players if gameplayer.role == Role.owner]
'''given player is an owner of a game the subject_player participates in'''
def is_player_game_owner(subject_player, owner=current_user):
return owner in [gameplayer.player for gameplayers in
[game.game_players for game in subject_player.games]
for gameplayer in gameplayers if gameplayer.role == Role.owner]
'''given player is an owner of a game the given object is part of'''
def is_objective_owner(objective, owner=current_user):
return owner in [gameplayer.player for gameplayer in objective.game.game_players if gameplayer.role == Role.owner]
@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 is_game_owner(game):
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 is_objective_owner(objective):
abort(403)
if is_objective_owner(objective):
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 is_objective_owner(objective):
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 = is_objective_owner(objective)
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)