diff --git a/app/main/routes.py b/app/main/routes.py
index 59970c1..c70ad9e 100644
--- a/app/main/routes.py
+++ b/app/main/routes.py
@@ -67,7 +67,7 @@ def game_dashboard(game_name):
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)
+ game=game, json=json, location_encoder=LocationEncoder)
if role == Role.hunter:
return render_template('game_hunter_dashboard.html', title='Game Dashboard',
game=game, json=json, location_encoder=LocationEncoder)
diff --git a/app/main/tests/test_routes.py b/app/main/tests/test_routes.py
index f761372..ac56873 100644
--- a/app/main/tests/test_routes.py
+++ b/app/main/tests/test_routes.py
@@ -1,7 +1,7 @@
import unittest
from app import create_app, db
-from app.models import Player, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
+from app.models import User, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
import app.main.routes as routes
from config import Config
diff --git a/app/models/game_player.py b/app/models/game_player.py
index 1765c62..be21a87 100644
--- a/app/models/game_player.py
+++ b/app/models/game_player.py
@@ -1,3 +1,5 @@
+import json
+
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.schema import UniqueConstraint
@@ -5,6 +7,7 @@ from app import db
from .role import Role
from .notification_player import NotificationPlayer
from .player_found_objective import PlayerFoundObjective
+from .objective import Objective
class GamePlayer(db.Model):
__tablename__ = 'game_player'
@@ -41,3 +44,16 @@ class GamePlayer(db.Model):
def locations_during_game(self):
# pylint: disable=no-member
return self.user.locations_during_game(self.game)
+
+ def encode_objectives(self):
+ # pylint: disable=no-member
+ objectives = ['[']
+ for objective in self.game.objectives:
+ obj = {
+ 'name' : objective.name,
+ 'longitude' : objective.longitude,
+ 'latitude' : objective.latitude,
+ 'found' : objective in self.found_objectives}
+ objectives.append(json.dumps(obj))
+ objectives.append(',')
+ return ''.join(objectives)[:-1] + ']'
diff --git a/app/models/objective.py b/app/models/objective.py
index c75a8f3..45a3204 100644
--- a/app/models/objective.py
+++ b/app/models/objective.py
@@ -36,4 +36,4 @@ class ObjectiveMinimalEncoder(JSONEncoder):
'hash' : objective.hash,
'longitude' : objective.longitude,
'latitude' : objective.latitude
- }
+ }
\ No newline at end of file
diff --git a/app/models/tests/test_game.py b/app/models/tests/test_game.py
new file mode 100644
index 0000000..fb5709c
--- /dev/null
+++ b/app/models/tests/test_game.py
@@ -0,0 +1,40 @@
+import unittest
+from app import create_app, db
+from app.models import User, Game, Role, GamePlayer
+from config import Config
+
+class TestConfig(Config):
+ TESTING = True
+ WTF_CSRF_ENABLED = False
+ DEBUG = False
+ SQLALCHEMY_DATABASE_URI = 'sqlite://'
+
+class GameCase(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')
+ u1 = User(name='Henk')
+ u2 = User(name='Alfred')
+
+ g1.players.append(GamePlayer(user=u1, role=Role.owner))
+ g1.players.append(GamePlayer(user=u2, role=Role.bunny))
+
+ db.session.add(g1)
+ db.session.commit()
+
+ self.assertTrue(g1.owned_by(u1))
+ self.assertFalse(g1.owned_by(u2))
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/app/models/tests/test_game_player.py b/app/models/tests/test_game_player.py
new file mode 100644
index 0000000..5949ef3
--- /dev/null
+++ b/app/models/tests/test_game_player.py
@@ -0,0 +1,61 @@
+import unittest
+import json
+from app import create_app, db
+from app.models import User, Game, Role, GamePlayer, Objective
+from config import Config
+
+class TestConfig(Config):
+ TESTING = True
+ WTF_CSRF_ENABLED = False
+ DEBUG = False
+ SQLALCHEMY_DATABASE_URI = 'sqlite://'
+
+class GamePlayerCase(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_default(self):
+ g1 = Game(name='TestGame')
+ u1 = User(name='Henk')
+ p1 = GamePlayer(user=u1, role=Role.bunny)
+
+ o1 = Objective(name='Objective 1')
+ o2 = Objective(name='Objective 2')
+ o3 = Objective(name='Objective 3')
+
+ o1.set_hash()
+ o2.set_hash()
+ o3.set_hash()
+
+ g1.players.append(p1)
+ g1.objectives.append(o1)
+ g1.objectives.append(o2)
+ g1.objectives.append(o3)
+
+ p1.found_objectives.append(o1)
+
+ db.session.add(g1)
+ db.session.commit()
+
+ # Check if test initiaion succeeded
+ self.assertEqual(len(Game.query.first().objectives), 3)
+ self.assertEqual(User.query.first().user_games[0].found_objectives[0], o1)
+
+ # The actual Test
+ player_objectives = ('[{"name": "Objective 1", "longitude": null, "latitude": null, "found": true},'
+ '{"name": "Objective 2", "longitude": null, "latitude": null, "found": false},'
+ '{"name": "Objective 3", "longitude": null, "latitude": null, "found": false}]')
+ self.assertEqual(p1.encode_objectives(), player_objectives)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/app/models/tests/test_objective.py b/app/models/tests/test_objective.py
new file mode 100644
index 0000000..e04f7ee
--- /dev/null
+++ b/app/models/tests/test_objective.py
@@ -0,0 +1,49 @@
+import unittest
+from app import create_app, db
+from app.models import User, Game, Role, GamePlayer, Objective
+from config import Config
+
+class TestConfig(Config):
+ TESTING = True
+ WTF_CSRF_ENABLED = False
+ DEBUG = False
+ SQLALCHEMY_DATABASE_URI = 'sqlite://'
+
+class ObjectiveCase(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_objective_owner(self):
+ g1 = Game(name='TestGame')
+ g2 = Game(name='AnotherGame')
+ u1 = User(name='Henk')
+
+ g1.players.append(GamePlayer(user=u1, role=Role.owner))
+ g2.players.append(GamePlayer(user=u1, 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(u1))
+ self.assertFalse(o2.owned_by(u1))
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/app/models/tests/test_user.py b/app/models/tests/test_user.py
new file mode 100644
index 0000000..55cb240
--- /dev/null
+++ b/app/models/tests/test_user.py
@@ -0,0 +1,75 @@
+import unittest
+from app import create_app, db
+from app.models import User, Game, GamePlayer, Role
+from config import Config
+
+class TestConfig(Config):
+ TESTING = True
+ WTF_CSRF_ENABLED = False
+ DEBUG = False
+ SQLALCHEMY_DATABASE_URI = 'sqlite://'
+
+class UserCase(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_player_game_owner(self):
+ g1 = Game(name='TestGame')
+ g2 = Game(name='AnotherGame')
+
+ u1 = User(name='Henk')
+ u2 = User(name='Alfred')
+ u3 = User(name='Sasha')
+
+ g1.players.append(GamePlayer(user=u1, role=Role.owner))
+ g1.players.append(GamePlayer(user=u2, role=Role.bunny))
+
+ g2.players.append(GamePlayer(user=u1, role=Role.hunter))
+ g2.players.append(GamePlayer(user=u3, role=Role.bunny))
+
+
+ db.session.add(g1)
+ db.session.add(g2)
+ db.session.commit()
+
+ self.assertTrue(u1.owns_game_played_by(user=u2), "owner owns subject_player's game")
+ self.assertFalse(u1.owns_game_played_by(user=u3), "owner doesn't own subject_player's game")
+ self.assertTrue(u1.owns_game_played_by(user=u1), "owner owns it own's game")
+
+ def test_role_in_game(self):
+ g1 = Game(name='TestGame')
+
+ u1 = User(name='Henk')
+ u2 = User(name='Alfred')
+ u3 = User(name='Sasha')
+ u4 = User(name='Demian')
+ u5 = User(name='Karl')
+
+ g1.players.append(GamePlayer(user=u1, role=Role.owner))
+ g1.players.append(GamePlayer(user=u2, role=Role.bunny))
+ g1.players.append(GamePlayer(user=u3, role=Role.hunter))
+ g1.players.append(GamePlayer(user=u4, role=Role.none))
+
+ db.session.add(g1)
+ db.session.add(u5)
+ db.session.commit()
+
+ self.assertEqual(u1.role_in_game(g1), Role.owner)
+ self.assertEqual(u2.role_in_game(g1), Role.bunny)
+ self.assertEqual(u3.role_in_game(g1), Role.hunter)
+ self.assertEqual(u4.role_in_game(g1), Role.none)
+ self.assertEqual(u5.role_in_game(g1), None)
+ with self.assertRaises(AttributeError):
+ g1.get_role_for_game(None)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/app/static/assets/leaflet/utils.js b/app/static/assets/leaflet/utils.js
new file mode 100644
index 0000000..b432ab0
--- /dev/null
+++ b/app/static/assets/leaflet/utils.js
@@ -0,0 +1,47 @@
+var greenIcon = new L.Icon({
+ iconUrl: '/static/assets/leaflet/images/marker-icon-2x-green.png',
+ shadowUrl: '/static/assets/leaflet/images/marker-shadow.png',
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ popupAnchor: [1, -34],
+ shadowSize: [41, 41]
+});
+
+var goldIcon = new L.Icon({
+ iconUrl: '/static/assets/leaflet/images/marker-icon-2x-gold.png',
+ shadowUrl: '/static/assets/leaflet/images/marker-shadow.png',
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ popupAnchor: [1, -34],
+ shadowSize: [41, 41]
+});
+
+function addObjectiveMarker(map, objective){
+ var objectiveMarker = L.marker([
+ objective['latitude'],
+ objective['longitude']
+ ])
+ if(objective['found']){
+ console.log('test')
+ objectiveMarker.setIcon(goldIcon)
+ }
+ objectiveMarker.addTo(map);
+
+ if(objective['hash']){
+ objectiveMarker.bindTooltip(`${objective['name']}
+ ${objective['hash']}`).openPopup();
+ } else {
+ objectiveMarker.bindTooltip(`${objective['name']}`).openPopup();
+ }
+}
+
+function addPlayerMarker(map, player){
+ var playerMarker = L.marker([
+ player['latitude'],
+ player['longitude']
+ ], {icon: greenIcon}).addTo(map);
+ var timestamp_utc = moment.utc(player['timestamp_utc']).toDate()
+ var timestamp_local = moment(timestamp_utc).local().format('YYYY-MM-DD HH:mm');
+ playerMarker.bindTooltip(`${player['username']}
+ ${timestamp_local}`).openPopup();
+}
\ No newline at end of file
diff --git a/app/templates/game_bunny_dashboard.html b/app/templates/game_bunny_dashboard.html
index 1d77258..bb7c884 100644
--- a/app/templates/game_bunny_dashboard.html
+++ b/app/templates/game_bunny_dashboard.html
@@ -4,11 +4,12 @@
{{ super() }}
+
{% endblock %}
{% block app_content %}
-