--- /dev/null
+article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}html{font-size:100%;overflow-y:scroll;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}body,button,input,select,textarea{font-family:sans-serif}img{border:0;-ms-interpolation-mode:bicubic}a{color:#00e}a:visited{color:#551a8b}a:focus{outline:thin dotted}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:1em 40px}dfn{font-style:italic}mark{background:#ff0;color:#000}pre,code,kbd,samp{font-family:monospace,monospace;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:75%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol{margin:1em 0;padding:0 0 0 40px}dd{margin:0 0 0 40px}nav ul,nav ol{list-style:none}figure{margin:0}form{margin:0}fieldset{margin:0 2px;padding:.35em .625em .75em}legend{*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal;*overflow:visible}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="checkbox"],input[type="radio"]{box-sizing:border-box}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}th,td{padding:0;text-align:left;vertical-align:middle}
\ No newline at end of file
-@font-face {\r
- font-family: 'Xolonium';\r
- src: url('/static/css/xolonium-webfont.eot');\r
- src: url('/static/css/xolonium-webfont.eot?#iefix') format('embedded-opentype'),\r
- url('/static/css/xolonium-webfont.woff') format('woff'),\r
- url('/static/css/xolonium-webfont.ttf') format('truetype'),\r
- url('/static/css/xolonium-webfont.svg#Xolonium') format('svg');\r
- font-weight: normal;\r
- font-style: normal;\r
-}\r
-\r
-body {\r
- font-family: 'Xolonium', 'Arial', 'Helvetica';\r
- font-size: 12px;\r
- text-align: center;\r
-}\r
-\r
-.scoreboard{\r
- color: #FFFFFF;\r
- text-align: center;\r
-}\r
-\r
-.table-header, .header-cell{\r
- background-color: #E8E8E8;\r
- font-size: 14px;\r
- font-weight: bold;\r
-}\r
-\r
-\r
-.accuracy-table{\r
- text-align: center;\r
-}\r
-\r
-.nick {\r
- font-family: 'Xolonium', 'Arial', 'Helvetica';\r
- font-size: 14px;\r
-}\r
+body{
+ margin-left: auto;
+ margin-right: auto;
+ padding: 10px 10px 10px 10px;
+ width: 960px;
+}
+
+#header{
+ height: 100px;
+ position: relative;
+}
+
+#header h1{
+ position: absolute;
+}
+
+#header h3{
+ position: absolute;
+ top: 45px;
+}
+
+#nav{
+ position: absolute;
+ right: 0;
+ top: 50px;
+}
+
+#nav ul{
+ list-style: none outside none;
+}
+
+#nav li{
+ background-color: #bbbbbb;
+ border-radius: 3px 3px 3px 3px;
+ display: inline;
+ padding: 3px 6px;
+}
+
+#nav li:hover{
+ background-color: #999999;
+}
+
+#top-players, #top-servers, #top-maps{
+ float: left;
+ margin-bottom: 10px;
+ width: 320px;
+}
+
+#leaderboard{
+ display: inline;
+ float: left;
+ width: 320px;
+}
+
+#recent-games{
+ float: right;
+ width: 610px;
+}
+
+#recent-games-table{
+ width: 610px;
+}
+
+#footer{
+ clear: both;
+ text-align: center;
+}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
- <head>
- <title><%block name="title">XonStat - The Xonotic Statistics Database</%block></title>
- <%block name="css">
- <link rel="stylesheet" href="/static/css/style.css" type="text/css" media="screen" />
- </%block>
- <%block name="js"/>
- </head>
- <body>
- <div id="header">
- <%block name="header">
- <h1>XonStat</h1>
- <h2>The Statistics Database for Xonotic</h2>
- <br />
- </%block>
- </div>
-
- ${self.body()}
-
- <div id="footer">
- <%block name="footer"/>
- </div>
- </body>
+ <head>
+ <title><%block name="title">XonStat - Player Statistics for Xonotic</%block></title>
+ <%block name="css">
+ <link rel="stylesheet" href="/static/css/normalize.css" type="text/css" media="screen" />
+ <link rel="stylesheet" href="/static/css/style.css" type="text/css" media="screen" />
+ </%block>
+ <%block name="js">
+ </%block>
+ </head>
+ <body>
+ <div id="header">
+ <%block name="header">
+ <h1><a href="/" title="Home Page">XonStat</a></h1>
+ <h3>Player Statistics for Xonotic</h3>
+ </%block>
+ <ul id="nav">
+ <li><a href="/games" title="Game Index">games</a></li>
+ <li><a href="" title="Map Index">maps</a></li>
+ <li><a href="" title="Server Index">servers</a></li>
+ </ul>
+ </div> <!-- END HEADER -->
+ <div id="main">
+ ${self.body()}
+ </div> <!-- END MAIN -->
+ <div id="footer">
+ <%block name="footer">
+ <p>XonStat is a open source (GPLv2) project created by Antibody. Fork it <a href="https://github.com/antzucaro/XonStat" title="Go to the project page">on Github!</a></p>
+ </%block>
+ </div> <!-- END FOOTER -->
+ </body>
</html>
Main Page - ${parent.title()}\r
</%block>\r
\r
-<table>\r
-<tr>\r
-<th>Nick</th>\r
-<th>Score</th>\r
-</tr>\r
-% for (player_id, nick, score) in top_players:\r
-<tr>\r
-<td>${nick}</td>\r
-<td>${score}</td>\r
-</tr>\r
-% endfor\r
+<div id="leaderboard">\r
\r
-% for i in range(10 - len(top_players)):\r
-<tr>\r
-<td>-</td>\r
-<td>-</td>\r
-</tr>\r
+##### TOP PLAYERS #####\r
+<table id="top-players" border="1">\r
+ <tr>\r
+ <th colspan="3">Top Players</th>\r
+ </tr>\r
+ <tr>\r
+ <th>#</th>\r
+ <th>Nick</th>\r
+ <th>Score</th>\r
+ </tr>\r
+% for (player_id, nick, score) in top_players:\r
+ <tr>\r
+ % if player_id != '-':\r
+ <td><a href="${request.route_url('player_info', id=player_id)}" title="Go to the player info page for this player">${player_id}</a></td>\r
+ % else:\r
+ <td>${player_id}</td>\r
+ % endif\r
+ <td>${nick}</td>\r
+ <td>${score}</td>\r
+ </tr>\r
% endfor\r
</table>\r
\r
-<table>\r
-<tr>\r
-<th>Server</th>\r
-<th>Games</th>\r
-</tr>\r
+##### TOP SERVERS #####\r
+<table id="top-servers" border="1">\r
+ <tr>\r
+ <th colspan="3">Top Servers</th>\r
+ </tr>\r
+ <tr>\r
+ <th>#</th>\r
+ <th>Server</th>\r
+ <th>Games</th>\r
+ </tr>\r
% for (server_id, name, count) in top_servers:\r
-<tr>\r
-<td>${name}</td>\r
-<td>${count}</td>\r
-</tr>\r
-% endfor\r
-\r
-% for i in range(10 - len(top_servers)):\r
-<tr>\r
-<td>-</td>\r
-<td>-</td>\r
-</tr>\r
+ <tr>\r
+ % if server_id != '-':\r
+ <td><a href="${request.route_url('server_info', id=server_id)}" title="Go to the server info page for this server">${server_id}</a></td>\r
+ % else:\r
+ <td>${server_id}</td>\r
+ % endif\r
+ <td>${name}</td>\r
+ <td>${count}</td>\r
+ </tr>\r
% endfor\r
</table>\r
\r
-<table>\r
-<tr>\r
-<th>Map</th>\r
-<th>Times Played</th>\r
-</tr>\r
+##### TOP MAPS #####\r
+<table id="top-maps" border="1">\r
+ <tr>\r
+ <th colspan="3">Top Maps</th>\r
+ </tr>\r
+ <tr>\r
+ <th>#</th>\r
+ <th>Map</th>\r
+ <th>Times Played</th>\r
+ </tr>\r
% for (map_id, name, count) in top_maps:\r
-<tr>\r
-<td>${name}</td>\r
-<td>${count}</td>\r
-</tr>\r
-% endfor\r
-\r
-% for i in range(10 - len(top_maps)):\r
-<tr>\r
-<td>-</td>\r
-<td>-</td>\r
-</tr>\r
+ <tr>\r
+ % if map_id != '-':\r
+ <td><a href="${request.route_url('map_info', id=map_id)}" title="Go to the map info page for this map">${map_id}</a></td>\r
+ % else:\r
+ <td>${map_id}</td>\r
+ % endif\r
+ <td>${name}</td>\r
+ <td>${count}</td>\r
+ </tr>\r
% endfor\r
</table>\r
+</div> <!-- END LEADERBOARD -->\r
+\r
+<div id="recent-games">\r
+\r
+##### RECENT GAMES #####\r
+<table id="recent-games-table" border="1">\r
+ <tr>\r
+ <th colspan="5">Recent Games</th>\r
+ </tr>\r
+ <tr>\r
+ <th>Game #</th>\r
+ <th>Server</th>\r
+ <th>Map</th>\r
+ <th>Time</th>\r
+ <th>Winner</th>\r
+ </tr>\r
+ % for (game, server, map) in recent_games:\r
+ % if game != '-':\r
+ <tr>\r
+ <td>${game.game_id}</td>\r
+ <td>${server.name}</td>\r
+ <td>${map.name}</td>\r
+ <td>${game.start_dt}</td>\r
+ <td>${game.winner}</td>\r
+ </tr>\r
+ % else:\r
+ <tr>\r
+ <td>-</td>\r
+ <td>-</td>\r
+ <td>-</td>\r
+ <td>-</td>\r
+ <td>-</td>\r
+ </tr>\r
+ % endif\r
+ % endfor\r
+</div> <!-- END RECENT GAMES -->\r
import logging
import sqlalchemy.sql.functions as func
+import sqlalchemy.sql.expression as expr
from pyramid.response import Response
from xonstat.models import *
+from xonstat.util import *
log = logging.getLogger(__name__)
def main_index(request):
+ leaderboard_count = 10
+ recent_games_count = 30
+
# top players by score
top_players = DBSession.query(Player.player_id, Player.nick,
func.sum(PlayerGameStat.score)).\
filter(Player.player_id == PlayerGameStat.player_id).\
filter(Player.player_id > 2).\
- order_by(func.sum(PlayerGameStat.score)).\
+ order_by(expr.desc(func.sum(PlayerGameStat.score))).\
group_by(Player.nick).\
group_by(Player.player_id).all()[0:10]
+ top_players = [(player_id, html_colors(nick), score) \
+ for (player_id, nick, score) in top_players]
+
+ for i in range(leaderboard_count-len(top_players)):
+ top_players.append(('-', '-', '-'))
+
# top servers by number of total players played
top_servers = DBSession.query(Server.server_id, Server.name,
func.count()).\
filter(Game.server_id==Server.server_id).\
- order_by(func.count(Game.game_id)).\
+ order_by(expr.desc(func.count(Game.game_id))).\
group_by(Server.server_id).\
group_by(Server.name).all()[0:10]
+ for i in range(leaderboard_count-len(top_servers)):
+ top_servers.append(('-', '-', '-'))
+
# top maps by total times played
top_maps = DBSession.query(Map.map_id, Map.name,
func.count(Game.game_id)).\
filter(Map.map_id==Game.game_id).\
- order_by(func.count(Game.game_id)).\
+ order_by(expr.desc(func.count(Game.game_id))).\
group_by(Map.map_id).\
group_by(Map.name).all()[0:10]
+ for i in range(leaderboard_count-len(top_maps)):
+ top_maps.append(('-', '-', '-'))
+
+ recent_games = DBSession.query(Game, Server, Map).\
+ filter(Game.server_id==Server.server_id).\
+ filter(Game.map_id==Map.map_id).\
+ order_by(expr.desc(Game.start_dt)).all()[0:recent_games_count]
+
+ for i in range(recent_games_count-len(recent_games)):
+ recent_games.append(('-', '-', '-'))
+
return {'top_players':top_players,
'top_servers':top_servers,
'top_maps':top_maps,
+ 'recent_games':recent_games,
}