From ccc6418a1dea2ac63e99cb9c3d57e87b943644fa Mon Sep 17 00:00:00 2001 From: Ant Zucaro Date: Sun, 3 Sep 2017 11:09:45 -0400 Subject: [PATCH] Add separate views for the top servers on a map. --- xonstat/__init__.py | 6 ++++ xonstat/views/__init__.py | 2 +- xonstat/views/map.py | 67 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/xonstat/__init__.py b/xonstat/__init__.py index 72e849d..f1e3571 100644 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -173,6 +173,12 @@ def main(global_config, **settings): config.add_view(view=MapTopPlayers, route_name="map_top_active", attr="json", renderer="json", accept="application/json") + config.add_route("map_top_servers", "/map/{id:\d+}/topservers") + config.add_view(view=MapTopServers, route_name="map_top_servers", attr="html", + renderer="map_top_servers.mako", accept="text/html") + config.add_view(view=MapTopServers, route_name="map_top_servers", 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/views/__init__.py b/xonstat/views/__init__.py index 13564e0..830eabd 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, MapTopPlayers +from xonstat.views.map import MapIndex, MapTopScorers, MapTopPlayers, MapTopServers 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 9642ac9..ddbae28 100644 --- a/xonstat/views/map.py +++ b/xonstat/views/map.py @@ -221,6 +221,73 @@ class MapTopPlayers(MapInfoBase): } +class MapTopServers(MapInfoBase): + """Returns the top servers by the number of times they've played a given map.""" + + def __init__(self, request, limit=INDEX_COUNT, last=None): + """Common parameter parsing.""" + super(MapTopServers, self).__init__(request, limit, last) + self.top_servers = self.get_top_servers() + + def get_top_servers(self): + """Top servers by the number of times they have played the map. Shared by all renderers.""" + cutoff = self.now - timedelta(days=self.lifetime) + + top_servers_q = DBSession.query( + fg.row_number().over(order_by=expr.desc(func.count(Game.game_id))).label("rank"), + Server.server_id, Server.name, func.count(Game.game_id).label("games"))\ + .filter(Game.server_id == Server.server_id)\ + .filter(Game.map_id == self.map_id)\ + .filter(Game.create_dt > cutoff)\ + .order_by(expr.desc(func.count(Game.game_id)))\ + .group_by(Server.name)\ + .group_by(Server.server_id) + + if self.last: + top_servers_q = top_servers_q.offset(self.last) + + if self.limit: + top_servers_q = top_servers_q.limit(self.limit) + + top_servers = top_servers_q.all() + + return top_servers + + def html(self): + """Returns the HTML-ready representation.""" + TopServer = namedtuple("TopServer", ["rank", "server_id", "server_name", "games"]) + + top_servers = [TopServer(ts.rank, ts.server_id, ts.name, ts.games) + for ts in self.top_servers] + + # build the query string + query = {} + if len(top_servers) > 1: + query['last'] = top_servers[-1].rank + + return { + "map_id": self.map_id, + "top_servers": top_servers, + "lifetime": self.lifetime, + "last": query.get("last", None), + "query": query, + } + + def json(self): + """For rendering this data using JSON.""" + top_servers = [{ + "rank": ts.rank, + "server_id": ts.server_id, + "server_name": ts.server_name, + "games": ts.games, + } for ts in self.top_servers] + + return { + "map_id": self.map_id, + "top_servers": top_servers, + } + + def _map_info_data(request): map_id = int(request.matchdict['id']) -- 2.39.2