]> de.git.xonotic.org Git - xonotic/xonstat.git/blob - xonstat/views/server.py
No newlines for beneath the init methods.
[xonotic/xonstat.git] / xonstat / views / server.py
1 import logging
2 import sqlalchemy.sql.functions as func
3 import sqlalchemy.sql.expression as expr
4 from datetime import datetime, timedelta
5 from pyramid.httpexceptions import HTTPNotFound
6 from webhelpers.paginate import Page
7 from xonstat.models import DBSession, Player, Server, Map, Game, PlayerGameStat
8 from xonstat.util import page_url, html_colors
9 from xonstat.views.helpers import RecentGame, recent_games_q
10
11 log = logging.getLogger(__name__)
12
13
14 # Defaults
15 LEADERBOARD_LIFETIME = 30
16 LEADERBOARD_COUNT = 10
17 RECENT_GAMES_COUNT = 20
18
19
20 class ServerIndex(object):
21     """Returns a list of servers."""
22
23     def __init__(self, request):
24         """Common parameter parsing."""
25         self.request = request
26         self.page = request.params.get("page", 1)
27         self.servers = self.raw()
28
29     def raw(self):
30         """Returns the raw data shared by all renderers."""
31         try:
32             server_q = DBSession.query(Server).order_by(Server.server_id.desc())
33             servers = Page(server_q, self.page, items_per_page=25, url=page_url)
34
35         except:
36             servers = None
37
38         return servers
39
40     def html(self):
41         """For rendering this data using something HTML-based."""
42         return {
43             'servers': self.servers,
44         }
45
46     def json(self):
47         """For rendering this data using JSON."""
48         return {
49             'servers': [s.to_dict() for s in self.servers],
50         }
51
52
53 class ServerInfoBase(object):
54     """Baseline parameter parsing for Server URLs with a server_id in them."""
55
56     def __init__(self, request):
57         """Common parameter parsing."""
58         self.request = request
59         self.server_id = request.matchdict.get("id", None)
60
61         raw_lifetime = request.registry.settings.get('xonstat.leaderboard_lifetime',
62                                                      LEADERBOARD_LIFETIME)
63         self.lifetime = int(raw_lifetime)
64
65         self.now = datetime.utcnow()
66
67
68 class ServerTopMaps(ServerInfoBase):
69     """Returns the top maps played on a given server."""
70
71     def __init__(self, request):
72         """Common parameter parsing."""
73         super(ServerTopMaps, self).__init__(request)
74         self.top_maps = self.raw()
75
76     def raw(self):
77         """Returns the raw data shared by all renderers."""
78         try:
79             top_maps = DBSession.query(Game.map_id, Map.name, func.count())\
80                 .filter(Map.map_id==Game.map_id)\
81                 .filter(Game.server_id==self.server_id)\
82                 .filter(Game.create_dt > (self.now - timedelta(days=self.lifetime)))\
83                 .group_by(Game.map_id)\
84                 .group_by(Map.name) \
85                 .order_by(expr.desc(func.count()))\
86                 .limit(LEADERBOARD_COUNT)\
87                 .all()
88         except:
89             top_maps = None
90
91         return top_maps
92
93     def json(self):
94         """For rendering this data using JSON."""
95         top_maps = [{
96             "map_id": tm.map_id,
97             "map_name": tm.name,
98             "times_played": tm[2],
99         } for tm in self.top_maps]
100
101         return top_maps
102
103
104 class ServerTopScorers(ServerInfoBase):
105     """Returns the top scorers on a given server."""
106
107     def __init__(self, request):
108         """Common parameter parsing."""
109         super(ServerTopScorers, self).__init__(request)
110         self.top_scorers = self.raw()
111
112     def raw(self):
113         """Top scorers on this server by total score."""
114         try:
115             top_scorers = DBSession.query(Player.player_id, Player.nick,
116                                           func.sum(PlayerGameStat.score))\
117                 .filter(Player.player_id == PlayerGameStat.player_id)\
118                 .filter(Game.game_id == PlayerGameStat.game_id)\
119                 .filter(Game.server_id == self.server_id)\
120                 .filter(Player.player_id > 2)\
121                 .filter(PlayerGameStat.create_dt >
122                         (self.now - timedelta(days=LEADERBOARD_LIFETIME)))\
123                 .order_by(expr.desc(func.sum(PlayerGameStat.score)))\
124                 .group_by(Player.nick)\
125                 .group_by(Player.player_id)\
126                 .limit(LEADERBOARD_COUNT)
127
128         except:
129             top_scorers = None
130
131         return top_scorers
132
133     def json(self):
134         """For rendering this data using JSON."""
135         top_scorers = [{
136             "player_id": ts.player_id,
137             "nick": ts.nick,
138             "score": ts[2],
139         } for ts in self.top_scorers]
140
141         return top_scorers
142
143
144 class ServerTopPlayers(ServerInfoBase):
145     """Returns the top players by playing time on a given server."""
146
147     def __init__(self, request):
148         """Common parameter parsing."""
149         super(ServerTopPlayers, self).__init__(request)
150         self.top_players = self.raw()
151
152     def raw(self):
153         """Top players on this server by total playing time."""
154         try:
155             top_players = DBSession.query(Player.player_id, Player.nick,
156                                           func.sum(PlayerGameStat.alivetime))\
157                 .filter(Player.player_id == PlayerGameStat.player_id)\
158                 .filter(Game.game_id == PlayerGameStat.game_id)\
159                 .filter(Game.server_id == self.server_id)\
160                 .filter(Player.player_id > 2)\
161                 .filter(PlayerGameStat.create_dt > (self.now - timedelta(days=self.lifetime)))\
162                 .order_by(expr.desc(func.sum(PlayerGameStat.alivetime)))\
163                 .group_by(Player.nick)\
164                 .group_by(Player.player_id)\
165                 .limit(LEADERBOARD_COUNT)
166
167         except:
168             top_players = None
169
170         return top_players
171
172     def json(self):
173         """For rendering this data using JSON."""
174         top_players = [{
175             "player_id": ts.player_id,
176             "nick": ts.nick,
177             "time": ts[2].total_seconds(),
178         } for ts in self.top_players]
179
180         return top_players
181
182
183 class ServerInfo(ServerInfoBase):
184     """Returns detailed information about a particular server."""
185
186     def __init__(self, request):
187         """Common parameter parsing."""
188         super(ServerInfo, self).__init__(request)
189
190     def raw(self):
191         """Returns the raw data shared by all renderers."""
192         try:
193             server = DBSession.query(Server).filter_by(server_id=self.server_id).one()
194
195             top_maps = ServerTopMaps(self.request).top_maps
196
197             top_scorers_raw = ServerTopScorers(self.request).top_scorers
198             top_scorers = [(player_id, html_colors(nick), score)
199                            for (player_id, nick, score) in top_scorers_raw]
200
201             top_players_raw = ServerTopPlayers(self.request).top_players
202             top_players = [(player_id, html_colors(nick), score)
203                            for (player_id, nick, score) in top_players_raw]
204
205             rgs = recent_games_q(server_id=self.server_id).limit(RECENT_GAMES_COUNT).all()
206             recent_games = [RecentGame(row) for row in rgs]
207         except:
208             raise HTTPNotFound
209
210         return {
211             'server': server,
212             'recent_games': recent_games,
213             'top_players': top_players,
214             'top_scorers': top_scorers,
215             'top_maps': top_maps,
216         }
217
218     def html(self):
219         """For rendering this data using something HTML-based."""
220         return self.raw()
221
222     def json(self):
223         """For rendering this data using JSON."""
224         try:
225             server_raw = DBSession.query(Server).filter_by(server_id=self.server_id).one()
226             server = server_raw.to_dict()
227             top_maps = ServerTopMaps(self.request).json()
228             top_scorers = ServerTopScorers(self.request).json()
229             top_players = ServerTopPlayers(self.request).json()
230             rgs = recent_games_q(server_id=self.server_id).limit(RECENT_GAMES_COUNT).all()
231             recent_games = [RecentGame(row).to_dict() for row in rgs]
232         except:
233             raise HTTPNotFound
234
235         return {
236             'server': server,
237             'recent_games': recent_games,
238             'top_players': top_players,
239             'top_scorers': top_scorers,
240             'top_maps': top_maps,
241         }