2 from collections import namedtuple
3 from datetime import datetime, timedelta
5 import sqlalchemy.sql.expression as expr
6 import sqlalchemy.sql.functions as func
7 from pyramid.httpexceptions import HTTPNotFound
8 from webhelpers.paginate import Page
9 from xonstat.models import DBSession, Server, Map, Game, PlayerGameStat, Player, PlayerCaptime
10 from xonstat.models.map import MapCapTime
11 from xonstat.util import page_url, html_colors
12 from xonstat.views.helpers import RecentGame, recent_games_q
14 log = logging.getLogger(__name__)
20 class MapIndex(object):
21 """Returns a list of maps."""
23 def __init__(self, request):
24 """Common parameter parsing."""
25 self.request = request
26 self.page = request.params.get("page", 1)
28 # all views share this data, so we'll precalculate
29 self.maps = self.map_index()
32 """Returns the raw data shared by all renderers."""
34 map_q = DBSession.query(Map).order_by(Map.map_id.desc())
35 maps = Page(map_q, self.page, items_per_page=INDEX_COUNT, url=page_url)
37 except Exception as e:
44 """For rendering this data using something HTML-based."""
50 """For rendering this data using JSON."""
52 'maps': [m.to_dict() for m in self.maps],
56 def _map_info_data(request):
57 map_id = int(request.matchdict['id'])
60 leaderboard_lifetime = int(
61 request.registry.settings['xonstat.leaderboard_lifetime'])
63 leaderboard_lifetime = 30
65 leaderboard_count = 10
66 recent_games_count = 20
69 Captime = namedtuple('Captime', ['player_id', 'nick_html_colors',
70 'fastest_cap', 'game_id'])
73 gmap = DBSession.query(Map).filter_by(map_id=map_id).one()
75 # recent games played in descending order
76 rgs = recent_games_q(map_id=map_id).limit(recent_games_count).all()
77 recent_games = [RecentGame(row) for row in rgs]
79 # top players by score
80 top_scorers = DBSession.query(Player.player_id, Player.nick,
81 func.sum(PlayerGameStat.score)).\
82 filter(Player.player_id == PlayerGameStat.player_id).\
83 filter(Game.game_id == PlayerGameStat.game_id).\
84 filter(Game.map_id == map_id).\
85 filter(Player.player_id > 2).\
86 filter(PlayerGameStat.create_dt >
87 (datetime.utcnow() - timedelta(days=leaderboard_lifetime))).\
88 order_by(expr.desc(func.sum(PlayerGameStat.score))).\
89 group_by(Player.nick).\
90 group_by(Player.player_id).all()[0:leaderboard_count]
92 top_scorers = [(player_id, html_colors(nick), score) \
93 for (player_id, nick, score) in top_scorers]
95 # top players by playing time
96 top_players = DBSession.query(Player.player_id, Player.nick,
97 func.sum(PlayerGameStat.alivetime)).\
98 filter(Player.player_id == PlayerGameStat.player_id).\
99 filter(Game.game_id == PlayerGameStat.game_id).\
100 filter(Game.map_id == map_id).\
101 filter(Player.player_id > 2).\
102 filter(PlayerGameStat.create_dt >
103 (datetime.utcnow() - timedelta(days=leaderboard_lifetime))).\
104 order_by(expr.desc(func.sum(PlayerGameStat.alivetime))).\
105 group_by(Player.nick).\
106 group_by(Player.player_id).all()[0:leaderboard_count]
108 top_players = [(player_id, html_colors(nick), score) \
109 for (player_id, nick, score) in top_players]
111 # top servers using/playing this map
112 top_servers = DBSession.query(Server.server_id, Server.name,
113 func.count(Game.game_id)).\
114 filter(Game.server_id == Server.server_id).\
115 filter(Game.map_id == map_id).\
116 filter(Game.create_dt >
117 (datetime.utcnow() - timedelta(days=leaderboard_lifetime))).\
118 order_by(expr.desc(func.count(Game.game_id))).\
119 group_by(Server.name).\
120 group_by(Server.server_id).all()[0:leaderboard_count]
122 # TODO make this a configuration parameter to be set in the settings
124 captimes_raw = DBSession.query(Player.player_id, Player.nick,
125 PlayerCaptime.fastest_cap, PlayerCaptime.game_id).\
126 filter(PlayerCaptime.map_id == map_id).\
127 filter(Player.player_id == PlayerCaptime.player_id).\
128 order_by(PlayerCaptime.fastest_cap).\
132 captimes = [Captime(c.player_id, html_colors(c.nick),
133 c.fastest_cap, c.game_id) for c in captimes_raw]
135 except Exception as e:
138 'recent_games':recent_games,
139 'top_scorers':top_scorers,
140 'top_players':top_players,
141 'top_servers':top_servers,
146 def map_info(request):
148 List the information stored about a given map.
150 mapinfo_data = _map_info_data(request)
152 # FIXME: code clone, should get these from _map_info_data
153 leaderboard_count = 10
154 recent_games_count = 20
156 for i in range(leaderboard_count-len(mapinfo_data['top_scorers'])):
157 mapinfo_data['top_scorers'].append(('-', '-', '-'))
159 for i in range(leaderboard_count-len(mapinfo_data['top_players'])):
160 mapinfo_data['top_players'].append(('-', '-', '-'))
162 for i in range(leaderboard_count-len(mapinfo_data['top_servers'])):
163 mapinfo_data['top_servers'].append(('-', '-', '-'))
168 def map_info_json(request):
170 List the information stored about a given map. JSON.
172 return [{'status':'not implemented'}]
175 def map_captimes_data(request):
176 map_id = int(request.matchdict['id'])
178 current_page = request.params.get('page', 1)
181 mmap = DBSession.query(Map).filter_by(map_id=map_id).one()
183 mct_q = DBSession.query(PlayerCaptime.fastest_cap, PlayerCaptime.create_dt,
184 PlayerCaptime.player_id, PlayerCaptime.game_id,
185 Game.server_id, Server.name.label('server_name'),
186 PlayerGameStat.nick.label('player_nick')).\
187 filter(PlayerCaptime.map_id==map_id).\
188 filter(PlayerCaptime.game_id==Game.game_id).\
189 filter(PlayerCaptime.map_id==Map.map_id).\
190 filter(Game.server_id==Server.server_id).\
191 filter(PlayerCaptime.player_id==PlayerGameStat.player_id).\
192 filter(PlayerCaptime.game_id==PlayerGameStat.game_id).\
193 order_by(expr.asc(PlayerCaptime.fastest_cap))
195 except Exception as e:
196 raise httpexceptions.HTTPNotFound
198 map_captimes = Page(mct_q, current_page, items_per_page=20, url=page_url)
200 map_captimes.items = [MapCapTime(row) for row in map_captimes.items]
205 'captimes':map_captimes,
208 def map_captimes(request):
209 return map_captimes_data(request)
211 def map_captimes_json(request):
212 current_page = request.params.get('page', 1)
213 data = map_captimes_data(request)
216 "map": data["map"].to_dict(),
217 "captimes": [e.to_dict() for e in data["captimes"].items],
218 "page": current_page,