from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
- from xonstat.util import strip_colors, html_colors, pretty_date
+ from xonstat.util import qfont_decode, strip_colors, html_colors, pretty_date
log = logging.getLogger(__name__)
# define objects for all tables
class Player(object):
- def nick_html_colors(self):
+ def nick_html_colors(self, limit=None):
if self.nick is None:
return "Anonymous Player"
else:
- return html_colors(self.nick)
+ return html_colors(self.nick, limit)
def nick_strip_colors(self):
if self.nick is None:
return {'player_id':self.player_id, 'nick':self.nick,
'joined':self.create_dt.strftime('%Y-%m-%dT%H:%M:%SZ'),
'active_ind':self.active_ind, 'location':self.location,
- 'stripped_nick':self.stripped_nick}
+ 'stripped_nick':qfont_decode(self.stripped_nick)}
def epoch(self):
return timegm(self.create_dt.timetuple())
class Game(object):
- def __init__(self, game_id=None, start_dt=None, game_type_cd=None,
+ def __init__(self, game_id=None, start_dt=None, game_type_cd=None,
server_id=None, map_id=None, winner=None):
self.game_id = game_id
self.start_dt = start_dt
else:
return strip_colors(self.nick)
- def nick_html_colors(self):
+ def nick_html_colors(self, limit=None):
if self.nick is None:
return "Anonymous Player"
else:
- return html_colors(self.nick)
+ return html_colors(self.nick, limit)
def team_html_color(self):
if self.team == 5:
class PlayerNick(object):
def __repr__(self):
- return "<PlayerNick(%s, %s)>" % (self.player_id, self.stripped_nick)
+ return "<PlayerNick(%s, %s)>" % (self.player_id, qfont_decode(self.stripped_nick))
def to_dict(self):
- return {'player_id':self.player_id, 'name':self.stripped_nick}
+ return {'player_id':self.player_id, 'name':qfont_decode(self.stripped_nick)}
class PlayerElo(object):
class PlayerRank(object):
- def nick_html_colors(self):
+ def nick_html_colors(self, limit=None):
if self.nick is None:
return "Anonymous Player"
else:
- return html_colors(self.nick)
+ return html_colors(self.nick, limit)
def __repr__(self):
return "<PlayerRank(pid=%s, gametype=%s, rank=%s)>" % (self.player_id, self.game_type_cd, self.rank)
float: left;
}
++/* elo colors */
+.eloup { color: green; }
+.elodown { color: rgb(190,0,0); }
+.eloneutral { color: gray; }
+
++/* limit player nick lengths */
+ .player-nick {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
/* Navigation links */
.pagination > li > a, .pagination > li > span {
background-color: #111111;
- @font-face{font-family:'XoloniumNormal';src:url('fonts/xolonium-webfont.eot');src:url('fonts/xolonium-webfont.eot?#iefix') format('embedded-opentype'),url('fonts/xolonium-webfont.woff') format('woff'),url('fonts/xolonium-webfont.ttf') format('truetype'),url('fonts/xolonium-webfont.svg#XoloniumNormal') format('svg');font-weight:normal;font-style:normal}body{background:url("img/web_background_4.jpg") no-repeat fixed center center / cover black;background-color:black;color:#d0d0d0;font-family:"XoloniumNormal","Helvetica Neue",Helvetica,Arial,sans-serif}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{line-height:27px;font-size:18px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}table{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.7);border:1px solid #436688}table th{border:1px solid #436688;background-color:#001021}table td{border:1px solid #436688;font-size:10px}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#222}.table th,.table td{border:1px solid #436688}.table td{vertical-align:middle}.table .tdcenter{text-align:center}.accordion-group{border:1px solid #272525}.accordion-inner{border:0}#statline{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;position:relative;top:-25px}#xonborder{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.5);border-radius:15px 15px 15px 15px;margin-bottom:30px;margin-left:0;padding:20px}#title{color:#08c;font-size:30px;margin-bottom:15px;position:relative;text-align:center;text-shadow:2px 2px 3px #333}.indexform{margin:20px 0 20px 0}.indexbox{width:250px}.navbar-brand{margin-left:0;padding-bottom:0;padding-top:10px;text-align:left}.navbar-inverse{background:none repeat scroll 0 0 rgba(0,0,0,0.6)}.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{background:none repeat scroll 0 0 rgba(49,49,49,0.6)}.navbar-inverse .nav>li>a,.navbar-brand{font-family:XoloniumNormal}.search,input[type="search"]{background-color:#606060;border:1px solid #202020;color:#aaa;width:100px}.game{float:left;margin-bottom:30px;min-width:700px;padding:10px 7px}.game a{color:#CCC}.game a:hover{color:#d95f00;text-decoration:none}.game tr{background-color:#000}.game tr.red{background-color:#4d0000}.game tr.blue{background-color:#00004d}.game tr.yellow{background-color:#4d4d00}.game tr.pink{background-color:#4d004d}.game tr:hover{background-color:#222}.weapon-nav{height:70px;margin-bottom:20px}.weapon-nav ul{display:block;list-style:none outside none}.weapon-nav li{cursor:pointer;float:left;margin-right:10px}.weapon-nav li:hover{border-bottom:2px solid #001021}.weapon-nav .weapon-active{border-bottom:2px solid #436688}.weapon-nav p{text-align:center}.flot table,.flot td{background-color:black;border:0}#gbtabcontainer{margin-top:10px}#gbtab{font-size:12px}.tabbable p{font-size:14px}.tabs-below .nav-tabs>li>a{border-radius:4px 4px 4px 4px}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{background-color:#111;color:#aaa;border-color:#222}.nav-tabs>li>a{border-radius:4px 4px 4px 4px;text-align:center}.nav-tabs>li>a:hover{background-color:#111;border-color:#333}.nav-tabs{border-bottom:0 solid #000}.table .tdcenter{text-align:center}.game-detail img{float:left;margin-right:10px;margin-bottom:5px}.game img{float:left;margin-right:5px;margin-bottom:5px}.game-detail p,.game h4{float:left}.eloup{color:green}.elodown{color:#be0000}.eloneutral{color:gray}.pagination>li>a,.pagination>li>span{background-color:#111;border-color:#313131;color:#797979}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>.active>a,.pagination>.active>span{background-color:#2b2222}@media(min-width:768px){.navbar-form{float:right}}
-@font-face{font-family:'XoloniumNormal';src:url('fonts/xolonium-webfont.eot');src:url('fonts/xolonium-webfont.eot?#iefix') format('embedded-opentype'),url('fonts/xolonium-webfont.woff') format('woff'),url('fonts/xolonium-webfont.ttf') format('truetype'),url('fonts/xolonium-webfont.svg#XoloniumNormal') format('svg');font-weight:normal;font-style:normal}body{background:url("img/web_background_4.jpg") no-repeat fixed center center / cover black;background-color:black;color:#d0d0d0;font-family:"XoloniumNormal","Helvetica Neue",Helvetica,Arial,sans-serif}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{line-height:27px;font-size:18px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}table{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.7);border:1px solid #436688}table th{border:1px solid #436688;background-color:#001021}table td{border:1px solid #436688;font-size:10px}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#222}.table th,.table td{border:1px solid #436688}.table td{vertical-align:middle}.table .tdcenter{text-align:center}.accordion-group{border:1px solid #272525}.accordion-inner{border:0}#statline{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;position:relative;top:-25px}#xonborder{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.5);border-radius:15px 15px 15px 15px;margin-bottom:30px;margin-left:0;padding:20px}#title{color:#08c;font-size:30px;margin-bottom:15px;position:relative;text-align:center;text-shadow:2px 2px 3px #333}.indexform{margin:20px 0 20px 0}.indexbox{width:250px}.navbar-brand{margin-left:0;padding-bottom:0;padding-top:10px;text-align:left}.navbar-inverse{background:none repeat scroll 0 0 rgba(0,0,0,0.6)}.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{background:none repeat scroll 0 0 rgba(49,49,49,0.6)}.navbar-inverse .nav>li>a,.navbar-brand{font-family:XoloniumNormal}.search,input[type="search"]{background-color:#606060;border:1px solid #202020;color:#aaa;width:100px}.game{float:left;margin-bottom:30px;min-width:700px;padding:10px 7px}.game a{color:#CCC}.game a:hover{color:#d95f00;text-decoration:none}.game tr{background-color:#000}.game tr.red{background-color:#4d0000}.game tr.blue{background-color:#00004d}.game tr.yellow{background-color:#4d4d00}.game tr.pink{background-color:#4d004d}.game tr:hover{background-color:#222}.weapon-nav{height:70px;margin-bottom:20px}.weapon-nav ul{display:block;list-style:none outside none}.weapon-nav li{cursor:pointer;float:left;margin-right:10px}.weapon-nav li:hover{border-bottom:2px solid #001021}.weapon-nav .weapon-active{border-bottom:2px solid #436688}.weapon-nav p{text-align:center}.flot table,.flot td{background-color:black;border:0}#gbtabcontainer{margin-top:10px}#gbtab{font-size:12px}.tabbable p{font-size:14px}.tabs-below .nav-tabs>li>a{border-radius:4px 4px 4px 4px}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{background-color:#111;color:#aaa;border-color:#222}.nav-tabs>li>a{border-radius:4px 4px 4px 4px;text-align:center}.nav-tabs>li>a:hover{background-color:#111;border-color:#333}.nav-tabs{border-bottom:0 solid #000}.table .tdcenter{text-align:center}.game-detail img{float:left;margin-right:10px;margin-bottom:5px}.game img{float:left;margin-right:5px;margin-bottom:5px}.game-detail p,.game h4{float:left}.player-nick{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}.pagination>li>a,.pagination>li>span{background-color:#111;border-color:#313131;color:#797979}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>.active>a,.pagination>.active>span{background-color:#2b2222}@media(min-width:768px){.navbar-form{float:right}}
++@font-face{font-family:'XoloniumNormal';src:url('fonts/xolonium-webfont.eot');src:url('fonts/xolonium-webfont.eot?#iefix') format('embedded-opentype'),url('fonts/xolonium-webfont.woff') format('woff'),url('fonts/xolonium-webfont.ttf') format('truetype'),url('fonts/xolonium-webfont.svg#XoloniumNormal') format('svg');font-weight:normal;font-style:normal}body{background:url("img/web_background_4.jpg") no-repeat fixed center center / cover black;background-color:black;color:#d0d0d0;font-family:"XoloniumNormal","Helvetica Neue",Helvetica,Arial,sans-serif}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{line-height:27px;font-size:18px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}table{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.7);border:1px solid #436688}table th{border:1px solid #436688;background-color:#001021}table td{border:1px solid #436688;font-size:10px}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#222}.table th,.table td{border:1px solid #436688}.table td{vertical-align:middle}.table .tdcenter{text-align:center}.accordion-group{border:1px solid #272525}.accordion-inner{border:0}#statline{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;position:relative;top:-25px}#xonborder{background:#000;background:none repeat scroll 0 0 rgba(0,0,0,0.5);border-radius:15px 15px 15px 15px;margin-bottom:30px;margin-left:0;padding:20px}#title{color:#08c;font-size:30px;margin-bottom:15px;position:relative;text-align:center;text-shadow:2px 2px 3px #333}.indexform{margin:20px 0 20px 0}.indexbox{width:250px}.navbar-brand{margin-left:0;padding-bottom:0;padding-top:10px;text-align:left}.navbar-inverse{background:none repeat scroll 0 0 rgba(0,0,0,0.6)}.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{background:none repeat scroll 0 0 rgba(49,49,49,0.6)}.navbar-inverse .nav>li>a,.navbar-brand{font-family:XoloniumNormal}.search,input[type="search"]{background-color:#606060;border:1px solid #202020;color:#aaa;width:100px}.game{float:left;margin-bottom:30px;min-width:700px;padding:10px 7px}.game a{color:#CCC}.game a:hover{color:#d95f00;text-decoration:none}.game tr{background-color:#000}.game tr.red{background-color:#4d0000}.game tr.blue{background-color:#00004d}.game tr.yellow{background-color:#4d4d00}.game tr.pink{background-color:#4d004d}.game tr:hover{background-color:#222}.weapon-nav{height:70px;margin-bottom:20px}.weapon-nav ul{display:block;list-style:none outside none}.weapon-nav li{cursor:pointer;float:left;margin-right:10px}.weapon-nav li:hover{border-bottom:2px solid #001021}.weapon-nav .weapon-active{border-bottom:2px solid #436688}.weapon-nav p{text-align:center}.flot table,.flot td{background-color:black;border:0}#gbtabcontainer{margin-top:10px}#gbtab{font-size:12px}.tabbable p{font-size:14px}.tabs-below .nav-tabs>li>a{border-radius:4px 4px 4px 4px}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{background-color:#111;color:#aaa;border-color:#222}.nav-tabs>li>a{border-radius:4px 4px 4px 4px;text-align:center}.nav-tabs>li>a:hover{background-color:#111;border-color:#333}.nav-tabs{border-bottom:0 solid #000}.table .tdcenter{text-align:center}.game-detail img{float:left;margin-right:10px;margin-bottom:5px}.game img{float:left;margin-right:5px;margin-bottom:5px}.game-detail p,.game h4{float:left}.eloup{color:green}.elodown{color:#be0000}.eloneutral{color:gray}.player-nick{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pagination>li>a,.pagination>li>span{background-color:#111;border-color:#313131;color:#797979}.pagination>li>a:hover,.pagination>li>a:focus,.pagination>.active>a,.pagination>.active>span{background-color:#2b2222}@media(min-width:768px){.navbar-form{float:right}}
% for r in rs:
<tr>
<td>${i}</td>
- <td><a href="${request.route_url('player_info', id=r.player_id)}" title="Go to the player info page for this player">${r.nick_html_colors(18)|n}</a></td>
- <td class="player-nick" style="max-width: 16em;"><a href="${request.route_url('player_info', id=r.player_id)}" title="Go to the player info page for this player">${r.nick_html_colors()|n}</a></td>
- <td>${round(r.elo, 3)}</td>
++ <td><a href="${request.route_url('player_info', id=r.player_id)}" title="Go to the player info page for this player">${r.nick_html_colors()|n}</a></td>
+ <td>${int(round(r.elo))}</td>
</tr>
<% i = i+1 %>
% endfor
<tr>
<td>${i}</td>
% if player_id != '-':
- <td><a href="${request.route_url('player_info', id=player_id)}" title="Go to the player info page for this player">${nick|n}</a></td>
+ <td class="player-nick"><a href="${request.route_url('player_info', id=player_id)}" title="Go to the player info page for this player">${nick|n}</a></td>
% else:
<td>${nick|n}</td>
% endif
<td><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
<td><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the map detail page for this map">${rg.map_name}</a></td>
<td><span class="abstime" data-epoch="${rg.epoch}" title="${rg.start_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${rg.fuzzy_date}</span></td>
- <td>
+ <td class="player-nick">
% if rg.player_id > 2:
<a href="${request.route_url('player_info', id=rg.player_id)}" title="Go to the player info page for this player">${rg.nick_html_colors|n}</a></td>
% else:
<th style="width:100px;">Player ID</th>
<th>Nick</th>
<th class="create-dt">Joined</th>
+ <th></th>
</tr>
% for player in players:
<tr>
<td>${player.player_id}</th>
- <td><a href="${request.route_url("player_info", id=player.player_id)}" title="Go to this player's info page">${player.nick_html_colors()|n}</a></th>
+ <td class="player-nick"><a href="${request.route_url("player_info", id=player.player_id)}" title="Go to this player's info page">${player.nick_html_colors()|n}</a></th>
<td><span class="abstime" data-epoch="${player.epoch()}" title="${player.create_dt.strftime('%a, %d %b %Y %H:%M:%S UTC')}">${player.joined_pretty_date()}</span></th>
+ <td class="tdcenter">
+ <a href="${request.route_url("player_game_index", player_id=player.player_id, page=1)}" title="View recent games by this player">
+ <i class="glyphicon glyphicon-list"></i>
+ </a>
+ </td>
</tr>
% endfor
</table>
% if g.game_type_cd in fav_maps:
Favorite Map: <small>${fav_maps[g.game_type_cd].map_name} <br /></small>
% endif
+
+ % if g.game_type_cd == 'ctf':
+ % if overall_stats[g.game_type_cd].total_captures is not None:
+ <small><a href="${request.route_url("player_captimes", id=player.player_id)}">Fastest flag captures...</a></small>
+ % endif
+ % else:
+ <small><br /></small>
+ % endif
+
</p>
</div>
<div class="span5">
% if overall_stats[g.game_type_cd].cap_ratio is not None:
Cap Ratio: <small>${round(overall_stats[g.game_type_cd].cap_ratio,2)} (${overall_stats[g.game_type_cd].total_captures} captures, ${overall_stats[g.game_type_cd].total_pickups} pickups) <br /></small>
% endif
+ % else:
+ <small><br /></small>
% endif
</p>
</div>
<ul id="gbtab" class="nav nav-tabs">
% for g in games_played:
<li>
- <a href="#tab-${g.game_type_cd}" data-toggle="tab">
+ <a href="#tab-${g.game_type_cd}" data-toggle="tab" alt="${g.game_type_cd}" title="">
<span class="sprite sprite-${g.game_type_cd}"> </span><br />
${g.game_type_cd} <br />
<small>(${g.games})</small>
<div class="row">
<div class="span12">
<h3>Accuracy</h3>
- <div id="acc-graph" class="flot" style="width:100%; height:200px;">
+ <div id="acc-graph" class="flot" style="width:95%; height:200px;">
</div>
<div class="weapon-nav accuracy-nav">
<div class="row">
<div class="span12">
<h3>Damage Efficiency</h3>
- <div id="dmg-graph" class="flot" style="width:100%; height:200px;">
+ <div id="dmg-graph" class="flot" style="width:95%; height:200px;">
</div>
<div class="weapon-nav damage-nav">
<tr>
<td class="tdcenter"><a class="btn btn-primary btn-small" href="${request.route_url('game_info', id=rg.game_id)}" title="View detailed information about this game">view</a></td>
<td class="tdcenter"><span class="sprite sprite-${rg.game_type_cd}" alt="${rg.game_type_cd}" title="${rg.game_type_descr}"></span></td>
- <td>${rg.server_name}</td>
- <td>${rg.map_name}</td>
+ <td><a href="${request.route_url('server_info', id=rg.server_id)}" title="Go to the detail page for this server">${rg.server_name}</a></td>
+ <td><a href="${request.route_url('map_info', id=rg.map_id)}" title="Go to the detail page for this map">${rg.map_name}</a></td>
<td>
% if rg.team != None:
% if rg.team == rg.winner:
<a href="${request.route_url('game_info', id=rg.game_id, _query={'show_elo':1})}" title="View detailed information about this game">
% if rg.elo_delta is not None:
% if round(rg.elo_delta,2) > 0:
- <span title="Elo went up by ${round(rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-up"></i></span>
+ <span class="eloup" title="Elo went up by ${round(rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-up"></i></span>
% elif round(rg.elo_delta,2) < 0:
- <span title="Elo went down by ${round(-rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-down"></i></span>
+ <span class="elodown" title="Elo went down by ${round(-rg.elo_delta,2)}"><i class="glyphicon glyphicon-arrow-down"></i></span>
% else:
- <span title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
+ <span class="eloneutral" title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
% endif
% else:
- <span title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
+ <span class="eloneutral" title="Elo did not change"><i class="glyphicon glyphicon-minus"></i></span>
% endif
</a>
</td>