From 4b9a60559ce8dc20131d867b0d08c576adb8d43f Mon Sep 17 00:00:00 2001 From: Ant Zucaro Date: Sat, 8 Jul 2017 10:00:24 -0400 Subject: [PATCH] Add the 'topactive' view to maps as well. Work-in-progress. --- xonstat/__init__.py | 6 +++ xonstat/templates/map_top_active.mako | 57 +++++++++++++++++++++ xonstat/views/__init__.py | 2 +- xonstat/views/map.py | 71 ++++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 xonstat/templates/map_top_active.mako diff --git a/xonstat/__init__.py b/xonstat/__init__.py index f72e5b9..72e849d 100644 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -167,6 +167,12 @@ def main(global_config, **settings): config.add_view(view=MapTopScorers, route_name="map_top_scorers", attr="json", renderer="json", accept="application/json") + config.add_route("map_top_active", "/map/{id:\d+}/topactive") + config.add_view(view=MapTopPlayers, route_name="map_top_active", attr="html", + renderer="map_top_active.mako", accept="text/html") + config.add_view(view=MapTopPlayers, route_name="map_top_active", attr="json", + renderer="json", accept="application/json") + config.add_route("map_info", "/map/{id:\d+}") config.add_view(map_info, route_name="map_info", renderer="map_info.mako") diff --git a/xonstat/templates/map_top_active.mako b/xonstat/templates/map_top_active.mako new file mode 100644 index 0000000..291f7e4 --- /dev/null +++ b/xonstat/templates/map_top_active.mako @@ -0,0 +1,57 @@ +<%inherit file="base.mako"/> +<%namespace name="nav" file="nav.mako" /> + +<%block name="navigation"> + ${nav.nav('maps')} + + +<%block name="title"> + Map Active Players Index + + +% if not top_players and last is not None: +

Sorry, no more active players!

+ +% elif not top_players and last is None: +

No active players found. Yikes, get playing!

+ +% else: + ##### ACTIVE PLAYERS ##### +
+
+ + + + + + + + + + + % for tp in top_players: + + + + + + % endfor + +
#NickPlay Time
${tp.rank}${tp.nick|n}${tp.alivetime}
+

Note: these figures are from the past ${lifetime} days +

+
+ + % if len(top_players) == 20: +
+
+ +
+
+ % endif + +% endif diff --git a/xonstat/views/__init__.py b/xonstat/views/__init__.py index e947cb0..13564e0 100644 --- a/xonstat/views/__init__.py +++ b/xonstat/views/__init__.py @@ -13,7 +13,7 @@ from xonstat.views.game import game_info, rank_index from xonstat.views.game import game_info_json, rank_index_json from xonstat.views.game import game_finder, game_finder_json -from xonstat.views.map import MapIndex, MapTopScorers +from xonstat.views.map import MapIndex, MapTopScorers, MapTopPlayers from xonstat.views.map import map_info, map_info_json from xonstat.views.map import map_captimes, map_captimes_json diff --git a/xonstat/views/map.py b/xonstat/views/map.py index 702d280..9642ac9 100644 --- a/xonstat/views/map.py +++ b/xonstat/views/map.py @@ -25,7 +25,6 @@ class MapIndex(object): def __init__(self, request): """Common parameter parsing.""" self.request = request - self.page = request.params.get("page", 1) self.last = request.params.get("last", None) # all views share this data, so we'll pre-calculate @@ -96,7 +95,6 @@ class MapTopScorers(MapInfoBase): def get_top_scorers(self): """Top players by score. Shared by all renderers.""" cutoff = self.now - timedelta(days=self.lifetime) - cutoff = self.now - timedelta(days=120) top_scorers_q = DBSession.query( fg.row_number().over(order_by=expr.desc(func.sum(PlayerGameStat.score))).label("rank"), @@ -154,6 +152,75 @@ class MapTopScorers(MapInfoBase): } +class MapTopPlayers(MapInfoBase): + """Returns the top players by time on a given map.""" + + def __init__(self, request, limit=INDEX_COUNT, last=None): + """Common parameter parsing.""" + super(MapTopPlayers, self).__init__(request, limit, last) + self.top_players = self.get_top_players() + + def get_top_players(self): + """Top players by score. Shared by all renderers.""" + cutoff = self.now - timedelta(days=self.lifetime) + + top_players_q = DBSession.query( + fg.row_number().over(order_by=expr.desc(func.sum(PlayerGameStat.alivetime))).label("rank"), + Player.player_id, Player.nick, func.sum(PlayerGameStat.alivetime).label("alivetime"))\ + .filter(Player.player_id == PlayerGameStat.player_id)\ + .filter(Game.game_id == PlayerGameStat.game_id)\ + .filter(Game.map_id == self.map_id)\ + .filter(Player.player_id > 2)\ + .filter(PlayerGameStat.create_dt > cutoff)\ + .order_by(expr.desc(func.sum(PlayerGameStat.alivetime)))\ + .group_by(Player.nick)\ + .group_by(Player.player_id) + + if self.last: + top_players_q = top_players_q.offset(self.last) + + if self.limit: + top_players_q = top_players_q.limit(self.limit) + + top_players = top_players_q.all() + + return top_players + + def html(self): + """Returns the HTML-ready representation.""" + TopPlayer = namedtuple("TopPlayer", ["rank", "player_id", "nick", "alivetime"]) + + top_players = [TopPlayer(tp.rank, tp.player_id, html_colors(tp.nick), tp.alivetime) + for tp in self.top_players] + + # build the query string + query = {} + if len(top_players) > 1: + query['last'] = top_players[-1].rank + + return { + "map_id": self.map_id, + "top_players": top_players, + "lifetime": self.lifetime, + "last": query.get("last", None), + "query": query, + } + + def json(self): + """For rendering this data using JSON.""" + top_players = [{ + "rank": ts.rank, + "player_id": ts.player_id, + "nick": ts.nick, + "time": ts.alivetime.total_seconds(), + } for ts in self.top_players] + + return { + "map_id": self.map_id, + "top_players": top_players, + } + + def _map_info_data(request): map_id = int(request.matchdict['id']) -- 2.39.2