From 85414da21d923afb839ba8f937b73ba41cec6266 Mon Sep 17 00:00:00 2001 From: Ant Zucaro Date: Sun, 23 Oct 2016 07:47:36 -0400 Subject: [PATCH] Add rank-fetching in the view, make the template easier to handle. --- xonstat/templates/server_info.mako | 61 ++++++++++++------------ xonstat/views/server.py | 76 +++++++++++++++++++++--------- 2 files changed, 86 insertions(+), 51 deletions(-) diff --git a/xonstat/templates/server_info.mako b/xonstat/templates/server_info.mako index 41a9a25..8bafa06 100644 --- a/xonstat/templates/server_info.mako +++ b/xonstat/templates/server_info.mako @@ -11,6 +11,16 @@ % endif +<%def name="empty_rows(list, max_empty_rows)"> + % for i in range(max_empty_rows - len(list)): + + - + - + - + + % endfor + + % if server is None:

Sorry, that server wasn't found!

@@ -45,19 +55,16 @@ - <% i = 1 %> - % for (score_player_id, score_nick, score_value) in top_scorers: + % for ts in top_scorers: - ${i} - % if score_player_id != '-': - ${score_nick|n} - % else: - ${score_nick} - % endif - ${score_value} + ${ts.rank} + ${ts.nick|n} + ${ts.total_score} - <% i = i+1 %> % endfor + + ${empty_rows(top_scorers, 10)} + @@ -73,19 +80,16 @@ - <% i = 1 %> - % for (player_id, nick, alivetime) in top_players: + % for tp in top_players: - ${i} - % if player_id != '-': - ${nick|n} - % else: - ${nick} - % endif - ${alivetime} + ${tp.rank} + ${tp.nick|n} + ${tp.alivetime} - <% i = i+1 %> % endfor + + ${empty_rows(top_players, 10)} + @@ -101,19 +105,16 @@ - <% i = 1 %> - % for (map_id, name, count) in top_maps: + % for tm in top_maps: - ${i} - % if map_id != '-': - ${name} - % else: - ${name} - % endif - ${count} + ${tm.rank} + ${tm.name} + ${tm.times_played} - <% i = i+1 %> % endfor + + ${empty_rows(top_maps, 10)} + diff --git a/xonstat/views/server.py b/xonstat/views/server.py index e83848e..953d6b7 100644 --- a/xonstat/views/server.py +++ b/xonstat/views/server.py @@ -1,8 +1,10 @@ import logging import sqlalchemy.sql.functions as func import sqlalchemy.sql.expression as expr +from collections import namedtuple from datetime import datetime, timedelta from pyramid.httpexceptions import HTTPNotFound +from sqlalchemy import func as fg from webhelpers.paginate import Page from xonstat.models import DBSession, Player, Server, Map, Game, PlayerGameStat from xonstat.util import page_url, html_colors @@ -79,7 +81,9 @@ class ServerTopMaps(ServerInfoBase): def raw(self): """Returns the raw data shared by all renderers.""" try: - top_maps_q = DBSession.query(Game.map_id, Map.name, func.count())\ + top_maps_q = DBSession.query( + fg.row_number().over(order_by=expr.desc(func.count())).label("rank"), + Game.map_id, Map.name, func.count().label("times_played"))\ .filter(Map.map_id==Game.map_id)\ .filter(Game.server_id==self.server_id)\ .filter(Game.create_dt > (self.now - timedelta(days=self.lifetime)))\ @@ -94,17 +98,23 @@ class ServerTopMaps(ServerInfoBase): top_maps_q = top_maps_q.limit(self.limit) top_maps = top_maps_q.all() - except: + except Exception as e: + log.debug(e) raise HTTPNotFound return top_maps + def html(self): + """Returns the HTML-ready representation.""" + return self.top_maps + def json(self): """For rendering this data using JSON.""" top_maps = [{ + "rank": tm.rank, "map_id": tm.map_id, "map_name": tm.name, - "times_played": tm[2], + "times_played": tm.times_played, } for tm in self.top_maps] return top_maps @@ -121,8 +131,11 @@ class ServerTopScorers(ServerInfoBase): def raw(self): """Top scorers on this server by total score.""" try: - top_scorers_q = DBSession.query(Player.player_id, Player.nick, - func.sum(PlayerGameStat.score))\ + top_scorers_q = DBSession.query( + fg.row_number().over( + order_by=expr.desc(func.sum(PlayerGameStat.score))).label("rank"), + Player.player_id, Player.nick, + func.sum(PlayerGameStat.score).label("total_score"))\ .filter(Player.player_id == PlayerGameStat.player_id)\ .filter(Game.game_id == PlayerGameStat.game_id)\ .filter(Game.server_id == self.server_id)\ @@ -141,17 +154,27 @@ class ServerTopScorers(ServerInfoBase): top_scorers = top_scorers_q.all() - except: + except Exception as e: + log.debug(e) raise HTTPNotFound return top_scorers + def html(self): + """Returns an HTML-ready representation.""" + TopScorer = namedtuple("TopScorer", ["rank", "player_id", "nick", "total_score"]) + + top_scorers = [TopScorer(ts.rank, ts.player_id, html_colors(ts.nick), ts.total_score) + for ts in self.top_scorers] + return top_scorers + def json(self): """For rendering this data using JSON.""" top_scorers = [{ + "rank": ts.rank, "player_id": ts.player_id, "nick": ts.nick, - "score": ts[2], + "score": ts.total_score, } for ts in self.top_scorers] return top_scorers @@ -168,8 +191,11 @@ class ServerTopPlayers(ServerInfoBase): def raw(self): """Top players on this server by total playing time.""" try: - top_players_q = DBSession.query(Player.player_id, Player.nick, - func.sum(PlayerGameStat.alivetime))\ + 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.server_id == self.server_id)\ @@ -187,17 +213,28 @@ class ServerTopPlayers(ServerInfoBase): top_players = top_players_q.all() - except: + except Exception as e: + log.debug(e) raise HTTPNotFound 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] + + return top_players + def json(self): """For rendering this data using JSON.""" top_players = [{ + "rank": ts.rank, "player_id": ts.player_id, "nick": ts.nick, - "time": ts[2].total_seconds(), + "time": ts.alivetime.total_seconds(), } for ts in self.top_players] return top_players @@ -234,16 +271,13 @@ class ServerInfo(ServerInfoBase): def html(self): """For rendering this data using something HTML-based.""" - server_info = self.raw() - - # convert the nick into HTML for both scorers and players - server_info["top_scorers"] = [(player_id, html_colors(nick), score) - for (player_id, nick, score) in server_info["top_scorers"]] - - server_info["top_players"] = [(player_id, html_colors(nick), score) - for (player_id, nick, score) in server_info["top_players"]] - - return server_info + return { + 'server': self.server, + 'top_players': self.top_players_v.html(), + 'top_scorers': self.top_scorers_v.html(), + 'top_maps': self.top_maps_v.html(), + 'recent_games': self.recent_games, + } def json(self): """For rendering this data using JSON.""" -- 2.39.2