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.

189 lines
8.3 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 User, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
from app.main.forms import CreateGameForm, ObjectiveForm, PlayerAddForm, UserCreateForm, 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(game_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>/adduser', methods=['GET', 'POST'])
@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 = UserCreateForm()
if form_add.submit_add.data and form_add.validate_on_submit():
user = User.query.filter_by(form_add.name.data).first_or_404()
game.game_players.append(GamePlayer(user=user, 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():
user = User(name=form_create.name.data)
user.set_auth_hash()
game.game_players.append(GamePlayer(user=user, 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 User for {game_name}', form_add=form_add, form_create=form_create, game=game)
@bp.route('/game/<game_name>/removeuser/<username>')
@bp.route('/game/<game_name>/removeplayer/<username>')
@login_required
def remove_player(game_name, username):
game = Game.query.filter_by(name=game_name).first_or_404()
if not game.owned_by(current_user):
abort(403)
user = User.query.filter(and_(User.name == username, User.games.contains(game))).first_or_404()
game.players.remove(user)
db.session.commit()
return redirect(url_for('main.game_dashboard', game_name=game.name))
@bp.route('/game/<game_name>/player/<username>', methods=['GET', 'POST'])
@login_required
def game_player(game_name, username):
game = Game.query.filter_by(name=game_name).first_or_404()
if not game.owned_by(current_user):
abort(403)
user = User.query.filter(and_(User.name == username, User.games.contains(game))).first_or_404()
gameplayer = [gameplayer for gameplayer in user.user_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('game_player.html', title=f'{user.name} in {game_name}', game=game, user=user, form=form, json=json, location_encoder=LocationEncoder)
@bp.route('/user/<auth_hash>/qrcode.png')
@login_required
def user_qrcode(auth_hash):
user = User.query.filter_by(auth_hash=auth_hash).first_or_404()
if not current_user.owns_game_played_by(user):
abort(403)
img = generate_qr_code(url_for('main.player', auth_hash=auth_hash, _external=True))
return serve_pil_image(img)
@bp.route('/user/<auth_hash>')
@login_required
def user(auth_hash):
user = User.query.filter_by(auth_hash=auth_hash).first_or_404()
return render_template('auth/user.html', title=f'User: {user.name}', user=user)
@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)