Browse Source

Move owned_by methods to models file

testing
Burathar 5 years ago
parent
commit
8aea63ab90
  1. 51
      app/main/routes.py
  2. 36
      app/models.py
  3. 113
      app/tests/test_models.py

51
app/main/routes.py

@ -13,6 +13,8 @@ from app.main.forms import CreateGameForm, ObjectiveForm, PlayerAddForm, PlayerC @@ -13,6 +13,8 @@ from app.main.forms import CreateGameForm, ObjectiveForm, PlayerAddForm, PlayerC
@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'])
@ -32,17 +34,28 @@ def create_game(): @@ -32,17 +34,28 @@ def create_game():
@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):
role = current_user.get_role_for_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)
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):
if not game.owned_by(current_user):
abort(403)
form_add = PlayerAddForm()
form_create = PlayerCreateForm()
@ -65,7 +78,7 @@ def add_player(game_name): @@ -65,7 +78,7 @@ def add_player(game_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):
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)
@ -76,7 +89,7 @@ def remove_player(game_name, player_name): @@ -76,7 +89,7 @@ def remove_player(game_name, player_name):
@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):
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]
@ -91,7 +104,7 @@ def game_player(game_name, player_name): @@ -91,7 +104,7 @@ def game_player(game_name, player_name):
@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):
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)
@ -102,25 +115,11 @@ def player(auth_hash): @@ -102,25 +115,11 @@ 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):
if not game.owned_by(current_user):
abort(403)
form = ObjectiveForm()
objective = Objective(name='', latitude=52.0932, longitude=5.12405)
@ -137,9 +136,9 @@ def add_objective(game_name): @@ -137,9 +136,9 @@ def add_objective(game_name):
@login_required
def delete_objective(objective_hash):
objective = Objective.query.filter_by(hash=objective_hash).first_or_404()
if not is_objective_owner(objective):
if not objective.owned_by(current_user):
abort(403)
if is_objective_owner(objective):
else:
db.session.delete(objective)
db.session.commit()
return redirect(url_for('main.game_dashboard', game_name=objective.game.name))
@ -166,7 +165,7 @@ def serve_pil_image(pil_img): @@ -166,7 +165,7 @@ def serve_pil_image(pil_img):
@login_required
def objective_qrcode(objective_hash):
objective = Objective.query.filter_by(hash=objective_hash).first_or_404()
if not is_objective_owner(objective):
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)
@ -175,7 +174,7 @@ def objective_qrcode(objective_hash): @@ -175,7 +174,7 @@ def objective_qrcode(objective_hash):
@login_required
def objective(objective_hash):
objective = Objective.query.filter_by(hash=objective_hash).first_or_404()
owner = is_objective_owner(objective)
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:

36
app/models.py

@ -83,6 +83,20 @@ class Game(db.Model): @@ -83,6 +83,20 @@ class Game(db.Model):
def last_player_locations(self):
return [player.last_location(self) for player in self.players if player.locations]
def bunnies(self):
# pylint: disable=not-an-iterable
return [gameplayer.player for gameplayer in self.game_players if gameplayer.role == Role.bunny]
def last_locations(self, players):
locations = []
for player in players:
locations.append(player.last_location(self))
return locations
def owned_by(self, player):
'''given player is an owner of game'''
return player in [gameplayer.player for gameplayer in self.game_players if gameplayer.role == Role.owner]
class Player(UserMixin, db.Model):
""" !Always call set_auth_hash() after creating new instance! """
__tablename__ = 'player'
@ -142,7 +156,7 @@ class Player(UserMixin, db.Model): @@ -142,7 +156,7 @@ class Player(UserMixin, db.Model):
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def locations_game(self, game):
def locations_during_game(self, game):
# pylint: disable=not-an-iterable
if not self.locations:
return None
@ -158,7 +172,21 @@ class Player(UserMixin, db.Model): @@ -158,7 +172,21 @@ class Player(UserMixin, db.Model):
return None
if game is None:
return max(self.locations, key=lambda location: location.timestamp)
return max(self.locations_game(game), key=lambda location: location.timestamp)
return max(self.locations_during_game(game), key=lambda location: location.timestamp)
def role_in_game(self, game):
'''returns the role as Role enum of player in given game. Returns None if player does not participate in game'''
# pylint: disable=not-an-iterable
gameplayers = [gameplayer for gameplayer in self.player_games if gameplayer.game == game]
if not gameplayers:
return None
return gameplayers[0].role
def owns_game_played_by(self, player):
'''self is an owner of a game the player participates in'''
return self in [gameplayer.player for gameplayers in
[game.game_players for game in player.games]
for gameplayer in gameplayers if gameplayer.role == Role.owner]
@staticmethod
def delete_orphans():
@ -187,6 +215,10 @@ class Objective(db.Model): @@ -187,6 +215,10 @@ class Objective(db.Model):
def set_hash(self):
self.hash = token_hex(16)
def owned_by(self, player):
'''given player is an owner of a game object is part of'''
return player in [gameplayer.player for gameplayer in self.game.game_players if gameplayer.role == Role.owner]
class ObjectiveMinimalEncoder(JSONEncoder):
def default(self, objective):

113
app/tests/test_models.py

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
import unittest
from app import create_app, db
from app.models import Player, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
from config import Config
class TestConfig(Config):
TESTING = True
WTF_CSRF_ENABLED = False
DEBUG = False
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class ModelsCase(unittest.TestCase):
# implement this: https://stackoverflow.com/questions/47294304/how-to-mock-current-user-in-flask-templates
def setUp(self):
self.app = create_app(TestConfig)
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_is_game_owner(self):
g1 = Game(name='TestGame')
p1 = Player(name='Henk')
p2 = Player(name='Alfred')
g1.game_players.append(GamePlayer(player=p1, role=Role.owner))
g1.game_players.append(GamePlayer(player=p2, role=Role.bunny))
db.session.add(g1)
db.session.commit()
self.assertTrue(g1.is_game_owner(p1))
self.assertFalse(g1.is_game_owner(p2))
def test_is_player_game_owner(self):
g1 = Game(name='TestGame')
g2 = Game(name='AnotherGame')
p1 = Player(name='Henk')
p2 = Player(name='Alfred')
p3 = Player(name='Sasha')
g1.game_players.append(GamePlayer(player=p1, role=Role.owner))
g1.game_players.append(GamePlayer(player=p2, role=Role.bunny))
g2.game_players.append(GamePlayer(player=p1, role=Role.hunter))
g2.game_players.append(GamePlayer(player=p3, role=Role.bunny))
db.session.add(g1)
db.session.add(g2)
db.session.commit()
self.assertTrue(p1.owns_game_played_by(player=p2), "owner owns subject_player's game")
self.assertFalse(p1.owns_game_played_by(player=p3), "owner doesn't own subject_player's game")
self.assertTrue(p1.owns_game_played_by(player=p1), "owner owns it own's game")
def test_is_objective_owner(self):
g1 = Game(name='TestGame')
g2 = Game(name='AnotherGame')
p1 = Player(name='Henk')
g1.game_players.append(GamePlayer(player=p1, role=Role.owner))
g2.game_players.append(GamePlayer(player=p1, role=Role.bunny))
o1 = Objective(name='o1')
o1.set_hash()
o2 = Objective(name='o2')
o2.set_hash()
g1.objectives.append(o1)
g2.objectives.append(o2)
db.session.add(g1)
db.session.add(g2)
db.session.commit()
self.assertTrue(o1.owned_by(p1))
self.assertFalse(o2.owned_by(p1))
def test_role_in_game(self):
g1 = Game(name='TestGame')
p1 = Player(name='Henk')
p2 = Player(name='Alfred')
p3 = Player(name='Sasha')
p4 = Player(name='Demian')
p5 = Player(name='Karl')
g1.game_players.append(GamePlayer(player=p1, role=Role.owner))
g1.game_players.append(GamePlayer(player=p2, role=Role.bunny))
g1.game_players.append(GamePlayer(player=p3, role=Role.hunter))
g1.game_players.append(GamePlayer(player=p4, role=Role.none))
db.session.add(g1)
db.session.add(p5)
db.session.commit()
self.assertEqual(p1.role_in_game(g1), Role.owner)
self.assertEqual(p2.role_in_game(g1), Role.bunny)
self.assertEqual(p3.role_in_game(g1), Role.hunter)
self.assertEqual(p4.role_in_game(g1), Role.none)
self.assertEqual(p5.role_in_game(g1), None)
with self.assertRaises(AttributeError):
g1.get_role_for_game(None)
if __name__ == '__main__':
unittest.main(verbosity=2)
Loading…
Cancel
Save