From 321dc9df9b227a93ccd40ffee1997b7da4f60186 Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Wed, 16 Jan 2013 18:40:09 +0100 Subject: [PATCH] Add views for player captimes (all the fastest caps per player) and map captimes (all the fastest caps per map) --- xonstat/__init__.py | 17 +++-- xonstat/templates/map_captimes.mako | 40 +++++++++++ xonstat/templates/player_captimes.mako | 41 +++++++++++ xonstat/views/__init__.py | 2 + xonstat/views/map.py | 77 ++++++++++++++++++-- xonstat/views/player.py | 98 +++++++++++++++++++++----- 6 files changed, 248 insertions(+), 27 deletions(-) create mode 100644 xonstat/templates/map_captimes.mako create mode 100644 xonstat/templates/player_captimes.mako diff --git a/xonstat/__init__.py b/xonstat/__init__.py index d4ccfde..93a43d5 100644 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -54,9 +54,9 @@ def main(global_config, **settings): config.add_view(player_elo_info_json, route_name="player_elo_info_json", renderer="jsonp") config.add_route("player_accuracy", "/player/{id:\d+}/accuracy") - config.add_route("player_accuracy_json", "/player/{id:\d+}/accuracy.json") + #config.add_route("player_accuracy_json", "/player/{id:\d+}/accuracy.json") config.add_view(player_accuracy_json, route_name="player_accuracy", renderer="jsonp") - config.add_view(player_accuracy_json, route_name="player_accuracy_json", renderer="jsonp") + #config.add_view(player_accuracy_json, route_name="player_accuracy_json", renderer="jsonp") config.add_route("player_index", "/players") config.add_route("player_index_json", "/players.json") @@ -64,8 +64,12 @@ def main(global_config, **settings): config.add_view(player_index_json, route_name="player_index_json", renderer="jsonp") config.add_route("player_damage", "/player/{id:\d+}/damage") - config.add_view(player_damage_json, route_name="player_damage", - renderer="json") + config.add_view(player_damage_json, route_name="player_damage", renderer="jsonp") + + config.add_route("player_captimes", "/player/{id:\d+}/captimes") + config.add_route("player_captimes_json", "/player/{id:\d+}/captimes.json") + config.add_view(player_captimes, route_name="player_captimes", renderer="player_captimes.mako") + config.add_view(player_captimes_json, route_name="player_captimes_json", renderer="jsonp") # GAME ROUTES config.add_route("game_index", "/games") @@ -113,6 +117,11 @@ def main(global_config, **settings): config.add_view(map_info, route_name="map_info", renderer="map_info.mako") config.add_view(map_info_json, route_name="map_info_json", renderer="jsonp") + config.add_route("map_captimes", "/map/{id:\d+}/captimes") + config.add_route("map_captimes_json", "/map/{id:\d+}/captimes.json") + config.add_view(map_captimes, route_name="map_captimes", renderer="map_captimes.mako") + config.add_view(map_captimes_json, route_name="map_captimes_json", renderer="jsonp") + # SEARCH ROUTES config.add_route("search", "search") config.add_route("search_json", "search.json") diff --git a/xonstat/templates/map_captimes.mako b/xonstat/templates/map_captimes.mako new file mode 100644 index 0000000..1591cc4 --- /dev/null +++ b/xonstat/templates/map_captimes.mako @@ -0,0 +1,40 @@ +<%inherit file="base.mako"/> +<%namespace name="nav" file="nav.mako" /> + +<%block name="title"> +Map captimes + + + +
+
+ +

${map.name}

+

Back to map info page

+ +

Fastest flag capture times:

+ + + + + + + + + + + + + % for ct in captimes: + + + + + + + % endfor + +
GameCaptimeNickServerDate
view${ct.fastest_cap.total_seconds()} seconds${ct.player_nick_html|n}${ct.server_name}${ct.create_dt_fuzzy}
+ +
+
diff --git a/xonstat/templates/player_captimes.mako b/xonstat/templates/player_captimes.mako new file mode 100644 index 0000000..96d8ff7 --- /dev/null +++ b/xonstat/templates/player_captimes.mako @@ -0,0 +1,41 @@ +<%inherit file="base.mako"/> +<%namespace name="nav" file="nav.mako" /> + +<%block name="title"> +Player captimes + + +
+
+ +

${player.nick_html_colors()|n}

+

Back to player info page

+ +

Fastest flag capture times:

+ + + + + + + ## + + + + + + + % for ct in captimes: + + + + ## + + + + % endfor + +
GameCaptimeNickMapServerDate
view${ct.fastest_cap.total_seconds()} seconds${ct.html_nick|n}${ct.map_name}${ct.server_name}${ct.create_dt_fuzzy}
+ +
+
diff --git a/xonstat/views/__init__.py b/xonstat/views/__init__.py index 0d9fd13..d3097dd 100644 --- a/xonstat/views/__init__.py +++ b/xonstat/views/__init__.py @@ -5,6 +5,7 @@ from xonstat.views.player import player_index_json, player_info_json from xonstat.views.player import player_game_index_json, player_accuracy_json from xonstat.views.player import player_damage_json, player_hashkey_info_json from xonstat.views.player import player_hashkey_info_text, player_elo_info_json +from xonstat.views.player import player_captimes, player_captimes_json from xonstat.views.game import game_index, game_info, rank_index from xonstat.views.game import game_index_json, game_info_json, rank_index_json @@ -12,6 +13,7 @@ from xonstat.views.game import game_finder from xonstat.views.map import map_info, map_index from xonstat.views.map import map_info_json, map_index_json +from xonstat.views.map import map_captimes, map_captimes_json from xonstat.views.server import server_info, server_game_index, server_index from xonstat.views.server import server_info_json, server_game_index_json diff --git a/xonstat/views/map.py b/xonstat/views/map.py index 6ecbf37..4c65a2d 100644 --- a/xonstat/views/map.py +++ b/xonstat/views/map.py @@ -38,7 +38,7 @@ def map_index(request): def map_index_json(request): """ - Provides a JSON-serialized list of all the current maps. + Provides a JSON-serialized list of all the current maps. """ view_data = _map_index_data(request) @@ -50,7 +50,7 @@ def map_index_json(request): def _map_info_data(request): map_id = request.matchdict['id'] - try: + try: leaderboard_lifetime = int( request.registry.settings['xonstat.leaderboard_lifetime']) except: @@ -77,7 +77,7 @@ def _map_info_data(request): filter(Game.game_id == PlayerGameStat.game_id).\ filter(Game.map_id == map_id).\ filter(Player.player_id > 2).\ - filter(PlayerGameStat.create_dt > + filter(PlayerGameStat.create_dt > (datetime.utcnow() - timedelta(days=leaderboard_lifetime))).\ order_by(expr.desc(func.sum(PlayerGameStat.score))).\ group_by(Player.nick).\ @@ -87,13 +87,13 @@ def _map_info_data(request): for (player_id, nick, score) in top_scorers] # top players by playing time - top_players = DBSession.query(Player.player_id, Player.nick, + top_players = DBSession.query(Player.player_id, Player.nick, func.sum(PlayerGameStat.alivetime)).\ filter(Player.player_id == PlayerGameStat.player_id).\ filter(Game.game_id == PlayerGameStat.game_id).\ filter(Game.map_id == map_id).\ filter(Player.player_id > 2).\ - filter(PlayerGameStat.create_dt > + filter(PlayerGameStat.create_dt > (datetime.utcnow() - timedelta(days=leaderboard_lifetime))).\ order_by(expr.desc(func.sum(PlayerGameStat.alivetime))).\ group_by(Player.nick).\ @@ -103,11 +103,11 @@ def _map_info_data(request): for (player_id, nick, score) in top_players] # top servers using/playing this map - top_servers = DBSession.query(Server.server_id, Server.name, + top_servers = DBSession.query(Server.server_id, Server.name, func.count(Game.game_id)).\ filter(Game.server_id == Server.server_id).\ filter(Game.map_id == map_id).\ - filter(Game.create_dt > + filter(Game.create_dt > (datetime.utcnow() - timedelta(days=leaderboard_lifetime))).\ order_by(expr.desc(func.count(Game.game_id))).\ group_by(Server.name).\ @@ -162,3 +162,66 @@ def map_info_json(request): List the information stored about a given map. JSON. """ return [{'status':'not implemented'}] + + +def map_captimes_data(request): + map_id = int(request.matchdict['id']) + + MapCaptimes = namedtuple('PlayerCaptimes', ['fastest_cap', 'create_dt', 'create_dt_epoch', 'create_dt_fuzzy', + 'player_id', 'player_nick', 'player_nick_stripped', 'player_nick_html', + 'game_id', 'server_id', 'server_name']) + + dbquery = DBSession.query('fastest_cap', 'create_dt', 'player_id', 'game_id', + 'server_id', 'server_name', 'player_nick').\ + from_statement( + "SELECT ct.fastest_cap, " + "ct.create_dt, " + "ct.player_id, " + "ct.game_id, " + "g.server_id, " + "s.name server_name, " + "pgs.nick player_nick " + "FROM player_map_captimes ct, " + "games g, " + "maps m, " + "servers s, " + "player_game_stats pgs " + "WHERE ct.map_id = :map_id " + "AND g.game_id = ct.game_id " + "AND g.server_id = s.server_id " + "AND m.map_id = ct.map_id " + "AND pgs.player_id = ct.player_id " + "AND pgs.game_id = ct.game_id " + "ORDER BY ct.fastest_cap " + ).params(map_id=map_id).all() + + mmap = DBSession.query(Map).filter_by(map_id=map_id).one() + + map_captimes = [] + for row in dbquery: + map_captimes.append(MapCaptimes( + fastest_cap=row.fastest_cap, + create_dt=row.create_dt, + create_dt_epoch=timegm(row.create_dt.timetuple()), + create_dt_fuzzy=pretty_date(row.create_dt), + player_id=row.player_id, + player_nick=row.player_nick, + player_nick_stripped=strip_colors(row.player_nick), + player_nick_html=html_colors(row.player_nick), + game_id=row.game_id, + server_id=row.server_id, + server_name=row.server_name, + )) + + return { + 'captimes':map_captimes, + 'map_id':map_id, + 'map_url':request.route_url('map_info', id=map_id), + 'map':mmap, + } + +def map_captimes(request): + return map_captimes_data(request) + +def map_captimes_json(request): + return map_captimes_data(request) diff --git a/xonstat/views/player.py b/xonstat/views/player.py index 24a6f26..33b4774 100644 --- a/xonstat/views/player.py +++ b/xonstat/views/player.py @@ -12,7 +12,7 @@ from pyramid.url import current_route_url from sqlalchemy import desc, distinct from webhelpers.paginate import Page, PageURL from xonstat.models import * -from xonstat.util import page_url, to_json, pretty_date, datetime_seconds +from xonstat.util import page_url, to_json, pretty_date, datetime_seconds, html_colors from xonstat.views.helpers import RecentGame, recent_games_q log = logging.getLogger(__name__) @@ -272,7 +272,7 @@ def get_fav_maps(player_id, game_type_cd=None): map_id=row.map_id, times_played=row.times_played, game_type_cd=row.game_type_cd) - + # if we aren't given a favorite game_type_cd # then the overall favorite is the one we've # played the most @@ -302,7 +302,7 @@ def get_ranks(player_id): The key to the dictionary is the game type code. There is also an "overall" game_type_cd which is the overall best rank. - """ + """ Rank = namedtuple('Rank', ['rank', 'max_rank', 'percentile', 'game_type_cd']) raw_ranks = DBSession.query("game_type_cd", "rank", "max_rank").\ @@ -412,7 +412,7 @@ def get_accuracy_stats(player_id, weapon_cd, games): # Determine the raw accuracy (hit, fired) numbers for $games games # This is then enumerated to create parameters for a flot graph - raw_accs = DBSession.query(PlayerWeaponStat.game_id, + raw_accs = DBSession.query(PlayerWeaponStat.game_id, PlayerWeaponStat.hit, PlayerWeaponStat.fired).\ filter(PlayerWeaponStat.player_id == player_id).\ filter(PlayerWeaponStat.weapon_cd == weapon_cd).\ @@ -448,7 +448,7 @@ def get_damage_stats(player_id, weapon_cd, games): # Determine the damage efficiency (hit, fired) numbers for $games games # This is then enumerated to create parameters for a flot graph - raw_dmgs = DBSession.query(PlayerWeaponStat.game_id, + raw_dmgs = DBSession.query(PlayerWeaponStat.game_id, PlayerWeaponStat.actual, PlayerWeaponStat.hit).\ filter(PlayerWeaponStat.player_id == player_id).\ filter(PlayerWeaponStat.weapon_cd == weapon_cd).\ @@ -526,7 +526,7 @@ def player_info_json(request): """ # All player_info fields are converted into JSON-formattable dictionaries - player_info = player_info_data(request) + player_info = player_info_data(request) player = player_info['player'].to_dict() @@ -646,11 +646,11 @@ def player_accuracy_data(request): games = len(accs) return { - 'player_id':player_id, - 'player_url':request.route_url('player_info', id=player_id), - 'weapon':weapon_cd, - 'games':games, - 'avg':avg, + 'player_id':player_id, + 'player_url':request.route_url('player_info', id=player_id), + 'weapon':weapon_cd, + 'games':games, + 'avg':avg, 'accs':accs } @@ -703,11 +703,11 @@ def player_damage_data(request): games = len(dmgs) return { - 'player_id':player_id, - 'player_url':request.route_url('player_info', id=player_id), - 'weapon':weapon_cd, - 'games':games, - 'avg':avg, + 'player_id':player_id, + 'player_url':request.route_url('player_info', id=player_id), + 'weapon':weapon_cd, + 'games':games, + 'avg':avg, 'dmgs':dmgs } @@ -868,3 +868,69 @@ def player_elo_info_json(request): 'version': 1, 'elos': elos, }] + +def player_captimes_data(request): + player_id = int(request.matchdict['id']) + if player_id <= 2: + player_id = -1; + + #player_captimes = DBSession.query(PlayerCaptime).\ + # filter(PlayerCaptime.player_id==player_id).\ + # order_by(PlayerCaptime.fastest_cap).\ + # all() + + PlayerCaptimes = namedtuple('PlayerCaptimes', ['fastest_cap', 'create_dt', 'create_dt_epoch', 'create_dt_fuzzy', + 'player_id', 'game_id', 'map_id', 'map_name', 'server_id', 'server_name']) + + dbquery = DBSession.query('fastest_cap', 'create_dt', 'player_id', 'game_id', 'map_id', + 'map_name', 'server_id', 'server_name').\ + from_statement( + "SELECT ct.fastest_cap, " + "ct.create_dt, " + "ct.player_id, " + "ct.game_id, " + "ct.map_id, " + "m.name map_name, " + "g.server_id, " + "s.name server_name " + "FROM player_map_captimes ct, " + "games g, " + "maps m, " + "servers s " + "WHERE ct.player_id = :player_id " + "AND g.game_id = ct.game_id " + "AND g.server_id = s.server_id " + "AND m.map_id = ct.map_id " + #"ORDER BY ct.fastest_cap " + "ORDER BY ct.create_dt desc" + ).params(player_id=player_id).all() + + player = DBSession.query(Player).filter_by(player_id=player_id).one() + + player_captimes = [] + for row in dbquery: + player_captimes.append(PlayerCaptimes( + fastest_cap=row.fastest_cap, + create_dt=row.create_dt, + create_dt_epoch=timegm(row.create_dt.timetuple()), + create_dt_fuzzy=pretty_date(row.create_dt), + player_id=row.player_id, + game_id=row.game_id, + map_id=row.map_id, + map_name=row.map_name, + server_id=row.server_id, + server_name=row.server_name, + )) + + return { + 'captimes':player_captimes, + 'player_id':player_id, + 'player_url':request.route_url('player_info', id=player_id), + 'player':player, + } + +def player_captimes(request): + return player_captimes_data(request) + +def player_captimes_json(request): + return player_captimes_data(request) -- 2.39.2