d3492e32dc8af8a9a749649c3b6a2fc104e4c660
[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         print("in the player_id block")
115         if force_player_id:
116             print("forced player")
117             recent_games_q = recent_games_q.\
118                 filter(PlayerGameStat.player_id==player_id).\
119                 filter(Game.players.contains([player_id]))
120         else:
121             print("in the alias block")
122             recent_games_q = recent_games_q.\
123                 filter(PlayerGameStat.scoreboardpos==1).\
124                 filter(Game.game_id==pgstat_alias.game_id).\
125                 filter(Game.players.contains([player_id])).\
126                 filter(pgstat_alias.player_id==player_id)
127
128             # supports versus queries
129             if player_id_2 is not None:
130                 recent_games_q = recent_games_q.\
131                         filter(Game.players.contains([player_id, player_id_2]))
132
133     else:
134         recent_games_q = recent_games_q.\
135             filter(PlayerGameStat.scoreboardpos==1)
136
137     if game_type_cd is not None:
138         recent_games_q = recent_games_q.\
139             filter(Game.game_type_cd==game_type_cd.lower())
140
141     if cutoff is not None:
142         right_now = datetime.utcnow()
143         recent_games_q = recent_games_q.\
144             filter(expr.between(Game.create_dt, cutoff, right_now))
145
146     if start_game_id is not None:
147         recent_games_q = recent_games_q.filter(Game.game_id <= start_game_id)
148
149     if end_game_id is not None:
150         recent_games_q = recent_games_q.filter(Game.game_id >= end_game_id)
151
152     return recent_games_q