Browse Source

Add player last location on map

feature_tests
Burathar 4 years ago
parent
commit
aee2de4a3b
  1. 2
      app/__init__.py
  2. 22
      app/models.py
  3. 4
      app/routes.py
  4. BIN
      app/static/assets/leaflet/images/marker-icon-2x-black.png
  5. BIN
      app/static/assets/leaflet/images/marker-icon-2x-blue.png
  6. BIN
      app/static/assets/leaflet/images/marker-icon-2x-gold.png
  7. BIN
      app/static/assets/leaflet/images/marker-icon-2x-green.png
  8. BIN
      app/static/assets/leaflet/images/marker-icon-2x-grey.png
  9. BIN
      app/static/assets/leaflet/images/marker-icon-2x-orange.png
  10. BIN
      app/static/assets/leaflet/images/marker-icon-2x-red.png
  11. BIN
      app/static/assets/leaflet/images/marker-icon-2x-violet.png
  12. BIN
      app/static/assets/leaflet/images/marker-icon-2x-yellow.png
  13. BIN
      app/static/assets/leaflet/images/marker-icon-black.png
  14. BIN
      app/static/assets/leaflet/images/marker-icon-blue.png
  15. BIN
      app/static/assets/leaflet/images/marker-icon-gold.png
  16. BIN
      app/static/assets/leaflet/images/marker-icon-green.png
  17. BIN
      app/static/assets/leaflet/images/marker-icon-grey.png
  18. BIN
      app/static/assets/leaflet/images/marker-icon-orange.png
  19. BIN
      app/static/assets/leaflet/images/marker-icon-red.png
  20. BIN
      app/static/assets/leaflet/images/marker-icon-violet.png
  21. BIN
      app/static/assets/leaflet/images/marker-icon-yellow.png
  22. BIN
      app/static/assets/leaflet/images/marker-shadow.png
  23. 27
      app/templates/game_dashboard.html

2
app/__init__.py

@ -9,6 +9,7 @@ from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_login import LoginManager from flask_login import LoginManager
from flask_moment import Moment
app = Flask(__name__) app = Flask(__name__)
@ -18,6 +19,7 @@ db = SQLAlchemy(app)
migrate = Migrate(app, db) migrate = Migrate(app, db)
login = LoginManager(app) login = LoginManager(app)
login.login_view = 'login' login.login_view = 'login'
moment = Moment(app)
from app import routes, models, errors from app import routes, models, errors

22
app/models.py

@ -9,7 +9,9 @@ import json
from json import JSONEncoder from json import JSONEncoder
from datetime import datetime from datetime import datetime
import pytz import pytz
from flask_moment import Moment
moment = Moment()
class Role(Enum): class Role(Enum):
none = 0 none = 0
@ -80,6 +82,9 @@ class Game(db.Model):
lazy='select', lazy='select',
backref=db.backref('game', lazy='joined')) backref=db.backref('game', lazy='joined'))
def last_player_locations(self):
return [player.last_location(self) for player in self.players if player.locations]
class Player(UserMixin, db.Model): class Player(UserMixin, db.Model):
""" !Always call set_auth_hash() after creating new instance! """ """ !Always call set_auth_hash() after creating new instance! """
__tablename__ = 'player' __tablename__ = 'player'
@ -143,10 +148,11 @@ class Player(UserMixin, db.Model):
if not self.locations: if not self.locations:
return None return None
if game is None: if game is None:
return max(location.timestamp for location in self.locations) return max(location for location in self.locations)
game_start = game.start_time or datetime.min game_start = game.start_time or datetime.min
game_end = game.end_time or datetime.max game_end = game.end_time or datetime.max
return max(location.timestamp for location in self.locations if location.timestamp > game_start and location.timestamp < game_end) return max((location for location in self.locations if location.timestamp > game_start and location.timestamp < game_end),
key=lambda location: location.timestamp)
@login.user_loader @login.user_loader
def load_user(id): def load_user(id):
@ -188,6 +194,18 @@ class Location(db.Model):
latitude = db.Column(db.Numeric(precision=15, scale=10, asdecimal=False, decimal_return_scale=None),nullable=False) latitude = db.Column(db.Numeric(precision=15, scale=10, asdecimal=False, decimal_return_scale=None),nullable=False)
timestamp = db.Column(db.DateTime, server_default=func.now(), nullable=False) timestamp = db.Column(db.DateTime, server_default=func.now(), nullable=False)
def __str__(self):
return f'{self.longitude}, {self.latitude}'
class LocationEncoder(JSONEncoder):
def default(self, location):
return {
'player_name' : location.player.name,
'longitude' : location.longitude,
'latitude' : location.latitude,
'timestamp_utc' : str(location.timestamp)
}
class Notification(db.Model): class Notification(db.Model):
__tablename__ = 'notification' __tablename__ = 'notification'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)

4
app/routes.py

@ -2,7 +2,7 @@ from flask import render_template, flash, redirect, url_for, request, abort, sen
from flask_login import login_user, logout_user, current_user, login_required from flask_login import login_user, logout_user, current_user, login_required
from sqlalchemy import and_ from sqlalchemy import and_
from app import app, db from app import app, db
from app.models import Player, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder from app.models import Player, Game, Role, GamePlayer, Objective, ObjectiveMinimalEncoder, LocationEncoder
from app.forms import LoginForm, RegistrationForm, CreateGameForm, ObjectiveForm from app.forms import LoginForm, RegistrationForm, CreateGameForm, ObjectiveForm
import json import json
import qrcode import qrcode
@ -69,7 +69,7 @@ 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(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() game = Game.query.filter_by(name = game_name).first_or_404()
if not is_game_owner(game): abort(403) if not is_game_owner(game): abort(403)
return render_template('game_dashboard.html', title = 'Game Dashboard', game=game, json=json, encoder=ObjectiveMinimalEncoder) return render_template('game_dashboard.html', title = 'Game Dashboard', game=game, json=json, objective_encoder=ObjectiveMinimalEncoder, location_encoder=LocationEncoder)
@app.route('/game/<game_name>/player/<player_name>') @app.route('/game/<game_name>/player/<player_name>')
@login_required @login_required

BIN
app/static/assets/leaflet/images/marker-icon-2x-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-blue.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-gold.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-green.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-grey.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-orange.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-red.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-violet.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
app/static/assets/leaflet/images/marker-icon-2x-yellow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
app/static/assets/leaflet/images/marker-icon-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/static/assets/leaflet/images/marker-icon-blue.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/static/assets/leaflet/images/marker-icon-gold.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/static/assets/leaflet/images/marker-icon-green.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/static/assets/leaflet/images/marker-icon-grey.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/static/assets/leaflet/images/marker-icon-orange.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/static/assets/leaflet/images/marker-icon-red.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/static/assets/leaflet/images/marker-icon-violet.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/static/assets/leaflet/images/marker-icon-yellow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/static/assets/leaflet/images/marker-shadow.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 608 B

27
app/templates/game_dashboard.html

@ -32,7 +32,10 @@
<td>{{ player.found_objectives | selectattr('game', '==', game)|list|length}}</td> <td>{{ player.found_objectives | selectattr('game', '==', game)|list|length}}</td>
<td>{{ player.caught_players | selectattr('game', '==', game)|list|length}}</td> <td>{{ player.caught_players | selectattr('game', '==', game)|list|length}}</td>
<td>{{ player.caught_by_players | selectattr('game', '==', game)|list|length}}</td> <td>{{ player.caught_by_players | selectattr('game', '==', game)|list|length}}</td>
<td>{{ player.last_location(game) }}<td> <td>{% with location = player.last_location(game) %}
{% if location %}{{ moment(location.timestamp).fromNow()}}: {% endif %}
{{ location }}
<td>{% endwith %}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@ -77,6 +80,7 @@
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
{{ moment.include_moment() }}
<script type="text/javascript", crossorigin="anonymous"> <script type="text/javascript", crossorigin="anonymous">
// Leaflet Map // Leaflet Map
var map = L.map( 'map', { var map = L.map( 'map', {
@ -92,7 +96,7 @@
attribution: 'Kaartgegevens &copy; <a href="kadaster.nl">Kadaster</a>' attribution: 'Kaartgegevens &copy; <a href="kadaster.nl">Kadaster</a>'
}).addTo( map ); }).addTo( map );
var objectives = JSON.parse('{{ json.dumps(game.objectives, cls=encoder)|safe }}') var objectives = JSON.parse('{{ json.dumps(game.objectives, cls=objective_encoder)|safe }}')
for (var i = 0; i < objectives.length; i++){ for (var i = 0; i < objectives.length; i++){
var objectiveMarker = L.marker([ var objectiveMarker = L.marker([
@ -103,7 +107,26 @@
${objectives[i]['hash']}`).openPopup(); ${objectives[i]['hash']}`).openPopup();
} }
var greenIcon = new L.Icon({
iconUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-icon-2x-green.png') }}",
shadowUrl: "{{ url_for('static', filename='assets/leaflet/images/marker-shadow.png') }}",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var players = JSON.parse('{{ json.dumps(game.last_player_locations(), cls=location_encoder)|safe }}')
for (var i = 0; i < players.length; i++){
var playerMarker = L.marker([
players[i]['latitude'],
players[i]['longitude']
], {icon: greenIcon}).addTo(map);
var timestamp_utc = moment.utc(players[i]['timestamp_utc']).toDate()
var timestamp_local = moment(timestamp_utc).local().format('YYYY-MM-DD HH:mm');
playerMarker.bindTooltip(`<b>${players[i]['player_name']}</b><br>
${timestamp_local}`).openPopup();
}
</script> </script>
{% endblock %} {% endblock %}
Loading…
Cancel
Save