]> de.git.xonotic.org Git - xonotic/xonstat.git/blob - xonstat/views/helpers.py
Return something useful for a game's JSON view.
[xonotic/xonstat.git] / xonstat / views / helpers.py
1 import logging
2 from calendar import timegm
3 from datetime import datetime
4
5 import sqlalchemy.sql.expression as expr
6 from sqlalchemy.orm import aliased
7 from xonstat.models import DBSession, Server, Map, Game, PlayerGameStat, GameType
8 from xonstat.util import pretty_date, html_colors
9
10 log = logging.getLogger(__name__)
11
12 class RecentGame(object):
13     '''
14     This is a helper class to facilitate showing recent games
15     data within mako. The idea is to take the results of a query
16     and transform it into class members easily accessible later.
17     It is like a namedtuple but a little easier to form.
18
19     The constructor takes a query row that has been fetched, and
20     it requires the following columns to be present in the row:
21
22         game_id, game_type_cd, game_type_descr, winner, start_dt,
23         server_id, server_name, map_id, map_name, player_id, nick,
24         rank, team
25
26     The following columns are optional:
27
28         elo_delta
29
30     This class is meant to be used in conjunction with recent_games_q,
31     which will return rows matching this specification.
32     '''
33     def __init__(self, row):
34         self.game_id          = row.game_id
35         self.game_type_cd     = row.game_type_cd
36         self.game_type_descr  = row.game_type_descr
37         self.winner           = row.winner
38         self.start_dt         = row.start_dt
39         self.fuzzy_date       = pretty_date(row.start_dt)
40         self.epoch            = timegm(row.start_dt.timetuple())
41         self.server_id        = row.server_id
42         self.server_name      = row.server_name
43         self.map_id           = row.map_id
44         self.map_name         = row.map_name
45         self.player_id        = row.player_id
46         self.nick             = row.nick
47         self.nick_html_colors = html_colors(row.nick)
48         self.rank             = row.rank
49         self.team             = row.team
50
51         try:
52             self.elo_delta = row.elo_delta
53         except:
54             self.elo_delta = None
55
56     def to_dict(self):
57         return {
58             "game_id"      : self.game_id,
59             "game_type_cd" : self.game_type_cd,
60             "winning_team" : self.winner,
61             "fuzzy_dt"     : self.fuzzy_date,
62             "epoch"        : self.epoch,
63             "server_id"    : self.server_id,
64             "server_name"  : self.server_name,
65             "map_id"       : self.map_id,
66             "map_name"     : self.map_name,
67             "player_id"    : self.player_id,
68             "winner"       : self.nick,
69             }
70
71     def __repr__(self):
72         return "<RecentGame(id=%s, gametype=%s, server=%s, map=%s)>" % (self.game_id, self.game_type_cd, self.server_name, self.map_name)
73
74
75 def recent_games_q(server_id=None, map_id=None, player_id=None,
76         game_type_cd=None, cutoff=None, force_player_id=False,
77         start_game_id=None, end_game_id=None, player_id_2=None):
78     '''
79     Returns a SQLA query of recent game data. Parameters filter
80     the results returned if they are provided. If not, it is
81     assumed that results from all servers and maps is desired.
82
83     The cutoff parameter provides a way to limit how far back to
84     look when querying. Only games that happened on or after the
85     cutoff (which is a datetime object) will be returned.
86     '''
87     pgstat_alias = aliased(PlayerGameStat, name='pgstat_alias')
88
89     recent_games_q = DBSession.query(Game.game_id, GameType.game_type_cd,
90             Game.winner, Game.start_dt, GameType.descr.label('game_type_descr'),
91             Server.server_id, Server.name.label('server_name'), Map.map_id,
92             Map.name.label('map_name'), PlayerGameStat.player_id,
93             PlayerGameStat.nick, PlayerGameStat.rank, PlayerGameStat.team,
94             PlayerGameStat.elo_delta).\
95             filter(Game.server_id==Server.server_id).\
96             filter(Game.map_id==Map.map_id).\
97             filter(Game.game_id==PlayerGameStat.game_id).\
98             filter(Game.game_type_cd==GameType.game_type_cd).\
99             order_by(expr.desc(Game.create_dt))
100
101     # the various filters provided get tacked on to the query
102     if server_id is not None:
103         recent_games_q = recent_games_q.\
104             filter(Server.server_id==server_id)
105
106     if map_id is not None:
107         recent_games_q = recent_games_q.\
108             filter(Map.map_id==map_id)
109
110     # Note: force_player_id makes the pgstat row returned be from the
111     # specified player_id. Otherwise it will just look for a game
112     # *having* that player_id, but returning the #1 player's pgstat row
113     if player_id is not None:
114         if force_player_id:
115             recent_games_q = recent_games_q.\
116                 filter(PlayerGameStat.player_id==player_id).\
117                 filter(Game.players.contains([player_id]))
118         else:
119             recent_games_q = recent_games_q.\
120                 filter(PlayerGameStat.scoreboardpos==1).\
121                 filter(Game.game_id==pgstat_alias.game_id).\
122                 filter(Game.players.contains([player_id])).\
123                 filter(pgstat_alias.player_id==player_id)
124
125             # supports versus queries
126             if player_id_2 is not None:
127                 recent_games_q = recent_games_q.\
128                         filter(Game.players.contains([player_id, player_id_2]))
129
130     else:
131         recent_games_q = recent_games_q.\
132             filter(PlayerGameStat.scoreboardpos==1)
133
134     if game_type_cd is not None:
135         recent_games_q = recent_games_q.\
136             filter(Game.game_type_cd==game_type_cd.lower())
137
138     if cutoff is not None:
139         right_now = datetime.utcnow()
140         recent_games_q = recent_games_q.\
141             filter(expr.between(Game.create_dt, cutoff, right_now))
142
143     if start_game_id is not None:
144         recent_games_q = recent_games_q.filter(Game.game_id <= start_game_id)
145
146     if end_game_id is not None:
147         recent_games_q = recent_games_q.filter(Game.game_id >= end_game_id)
148
149     return recent_games_q