get team information
This commit is contained in:
parent
19a475199a
commit
f6fb0cb00a
6 changed files with 136 additions and 35 deletions
|
@ -48,8 +48,6 @@ def api_wrapper(f):
|
||||||
return response
|
return response
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
import user # Must go below api_wrapper to prevent import loops
|
|
||||||
|
|
||||||
def login_required(f):
|
def login_required(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated_function(*args, **kwargs):
|
def decorated_function(*args, **kwargs):
|
||||||
|
@ -58,6 +56,8 @@ def login_required(f):
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
|
import user # Must go below api_wrapper to prevent import loops
|
||||||
|
|
||||||
def admins_only(f):
|
def admins_only(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated_function(*args, **kwargs):
|
def decorated_function(*args, **kwargs):
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from flask.ext.sqlalchemy import SQLAlchemy
|
from flask.ext.sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
import traceback
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
db = SQLAlchemy()
|
db = SQLAlchemy()
|
||||||
|
@ -33,11 +35,14 @@ class Teams(db.Model):
|
||||||
teamname_lower = db.Column(db.String(64), unique=True)
|
teamname_lower = db.Column(db.String(64), unique=True)
|
||||||
school = db.Column(db.Text)
|
school = db.Column(db.Text)
|
||||||
owner = db.Column(db.Integer)
|
owner = db.Column(db.Integer)
|
||||||
|
observer = db.Column(db.Boolean)
|
||||||
|
|
||||||
def __init__(self, teamname, owner):
|
def __init__(self, teamname, school, owner, observer):
|
||||||
self.teamname = teamname
|
self.teamname = teamname
|
||||||
self.teamname_lower = teamname.lower()
|
self.teamname_lower = teamname.lower()
|
||||||
|
self.school = school
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
|
self.observer = observer
|
||||||
|
|
||||||
def get_members(self):
|
def get_members(self):
|
||||||
members = [ ]
|
members = [ ]
|
||||||
|
@ -47,6 +52,25 @@ class Teams(db.Model):
|
||||||
})
|
})
|
||||||
return members
|
return members
|
||||||
|
|
||||||
|
def points(self):
|
||||||
|
score = db.func.sum(Problems.value).label("score")
|
||||||
|
team = db.session.query(Solves.tid, score).join(Teams).join(Problems).filter(Teams.tid==self.tid).group_by(Solves.tid).first()
|
||||||
|
if team:
|
||||||
|
return team.score
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def place(self):
|
||||||
|
score = db.func.sum(Problems.value).label("score")
|
||||||
|
quickest = db.func.max(Solves.date).label("quickest")
|
||||||
|
teams = db.session.query(Solves.tid).join(Teams).join(Problems).filter().group_by(Solves.tid).order_by(score.desc(), quickest).all()
|
||||||
|
try:
|
||||||
|
i = teams.index((self.tid,)) + 1
|
||||||
|
k = i % 10
|
||||||
|
return (i, "%d%s" % (i, "tsnrhtdd"[(i / 10 % 10 != 1) * (k < 4) * k::4]))
|
||||||
|
except ValueError:
|
||||||
|
return (-1, "--")
|
||||||
|
|
||||||
class Problems(db.Model):
|
class Problems(db.Model):
|
||||||
pid = db.Column(db.Integer, primary_key=True)
|
pid = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String(128))
|
name = db.Column(db.String(128))
|
||||||
|
@ -77,13 +101,19 @@ class Files(db.Model):
|
||||||
|
|
||||||
class Solves(db.Model):
|
class Solves(db.Model):
|
||||||
sid = db.Column(db.Integer, primary_key=True)
|
sid = db.Column(db.Integer, primary_key=True)
|
||||||
pid = db.Column(db.Integer)
|
pid = db.Column(db.Integer, db.ForeignKey("problems.pid"))
|
||||||
tid = db.Column(db.Integer)
|
tid = db.Column(db.Integer, db.ForeignKey("teams.tid"))
|
||||||
date = db.Column(db.Integer, default=utils.get_time_since_epoch())
|
date = db.Column(db.Integer, default=utils.get_time_since_epoch())
|
||||||
|
team = db.relationship("Teams", foreign_keys="Solves.tid", lazy="joined")
|
||||||
|
prob = db.relationship("Problems", foreign_keys="Solves.pid", lazy="joined")
|
||||||
|
correct = db.Column(db.Boolean)
|
||||||
|
flag = db.Column(db.Text)
|
||||||
|
|
||||||
def __init__(self, pid, tid):
|
def __init__(self, pid, tid, flag, correct):
|
||||||
self.pid = pid
|
self.pid = pid
|
||||||
self.tid = tid
|
self.tid = tid
|
||||||
|
self.flag = flag
|
||||||
|
self.correct = correct
|
||||||
|
|
||||||
##########
|
##########
|
||||||
# TOKENS #
|
# TOKENS #
|
||||||
|
|
|
@ -4,9 +4,9 @@ from voluptuous import Schema, Length, Required
|
||||||
|
|
||||||
from models import db, Teams, Users
|
from models import db, Teams, Users
|
||||||
from decorators import api_wrapper, login_required, WebException
|
from decorators import api_wrapper, login_required, WebException
|
||||||
from user import in_team, get_user, is_logged_in
|
|
||||||
from schemas import verify_to_schema, check
|
from schemas import verify_to_schema, check
|
||||||
|
|
||||||
|
import user
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
blueprint = Blueprint("team", __name__)
|
blueprint = Blueprint("team", __name__)
|
||||||
|
@ -20,18 +20,19 @@ blueprint = Blueprint("team", __name__)
|
||||||
@login_required
|
@login_required
|
||||||
def team_create():
|
def team_create():
|
||||||
params = utils.flat_multi(request.form)
|
params = utils.flat_multi(request.form)
|
||||||
user = get_user().first()
|
_user = user.get_user().first()
|
||||||
if user.tid is not None or user.tid >= 0 or get_team(owner=user.uid).first() is not None:
|
if _user.tid is not None or _user.tid >= 0 or get_team(owner=_user.uid).first() is not None:
|
||||||
raise WebException("You're already in a team!")
|
raise WebException("You're already in a team!")
|
||||||
|
|
||||||
verify_to_schema(TeamSchema, params)
|
verify_to_schema(TeamSchema, params)
|
||||||
teamname = params.get("teamname")
|
teamname = params.get("teamname")
|
||||||
|
school = params.get("school")
|
||||||
|
|
||||||
team = Teams(teamname, user.uid)
|
team = Teams(teamname, school, _user.uid, _user.utype != 1)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.session.add(team)
|
db.session.add(team)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
Users.query.filter_by(uid=user.uid).update({ "tid": team.tid })
|
Users.query.filter_by(uid=_user.uid).update({ "tid": team.tid })
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return { "success": 1, "message": "Success!" }
|
return { "success": 1, "message": "Success!" }
|
||||||
|
@ -39,8 +40,8 @@ def team_create():
|
||||||
@blueprint.route("/info", methods=["GET"])
|
@blueprint.route("/info", methods=["GET"])
|
||||||
@api_wrapper
|
@api_wrapper
|
||||||
def team_info():
|
def team_info():
|
||||||
logged_in = is_logged_in()
|
logged_in = user.is_logged_in()
|
||||||
me = False
|
me = False
|
||||||
teamname = utils.flat_multi(request.args).get("teamname")
|
teamname = utils.flat_multi(request.args).get("teamname")
|
||||||
if logged_in:
|
if logged_in:
|
||||||
my_team = get_team().first()
|
my_team = get_team().first()
|
||||||
|
@ -57,7 +58,8 @@ def team_info():
|
||||||
raise WebException("Team not found.")
|
raise WebException("Team not found.")
|
||||||
|
|
||||||
teamdata = {
|
teamdata = {
|
||||||
"teamname": team.teamname
|
"teamname": team.teamname,
|
||||||
|
"school": team.school
|
||||||
}
|
}
|
||||||
teamdata["in_team"] = me
|
teamdata["in_team"] = me
|
||||||
return { "success": 1, "team": teamdata }
|
return { "success": 1, "team": teamdata }
|
||||||
|
@ -74,8 +76,25 @@ TeamSchema = Schema({
|
||||||
([utils.__check_ascii], "Please only use ASCII characters in your teamname."),
|
([utils.__check_ascii], "Please only use ASCII characters in your teamname."),
|
||||||
([__check_teamname], "This teamname is taken, did you forget your password?")
|
([__check_teamname], "This teamname is taken, did you forget your password?")
|
||||||
),
|
),
|
||||||
|
Required("school"): check(
|
||||||
|
([str, Length(min=4, max=60)], "Your school name should be between 4 and 60 characters long."),
|
||||||
|
([utils.__check_ascii], "Please only use ASCII characters in your school name."),
|
||||||
|
),
|
||||||
}, extra=True)
|
}, extra=True)
|
||||||
|
|
||||||
|
def get_team_info(tid=None, teamname=None, teamname_lower=None, owner=None):
|
||||||
|
team = get_team(tid=tid, teamname=teamname, teamname_lower=teamname_lower, owner=owner).first()
|
||||||
|
place_number, place = team.place()
|
||||||
|
result = {
|
||||||
|
"tid": team.tid,
|
||||||
|
"teamname": team.teamname,
|
||||||
|
"school": team.school,
|
||||||
|
"place": place,
|
||||||
|
"place_number": place_number,
|
||||||
|
"points": team.points()
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
def get_team(tid=None, teamname=None, teamname_lower=None, owner=None):
|
def get_team(tid=None, teamname=None, teamname_lower=None, owner=None):
|
||||||
match = {}
|
match = {}
|
||||||
if teamname != None:
|
if teamname != None:
|
||||||
|
@ -86,10 +105,10 @@ def get_team(tid=None, teamname=None, teamname_lower=None, owner=None):
|
||||||
match.update({ "tid": tid })
|
match.update({ "tid": tid })
|
||||||
elif owner != None:
|
elif owner != None:
|
||||||
match.update({ "owner": owner })
|
match.update({ "owner": owner })
|
||||||
elif is_logged_in():
|
elif user.is_logged_in():
|
||||||
user = get_user().first()
|
_user = user.get_user().first()
|
||||||
if user.tid is not None:
|
if _user.tid is not None:
|
||||||
match.update({ "tid": user.tid })
|
match.update({ "tid": _user.tid })
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
result = Teams.query.filter_by(**match)
|
result = Teams.query.filter_by(**match)
|
||||||
return result
|
return result
|
|
@ -10,6 +10,7 @@ import datetime
|
||||||
import logger
|
import logger
|
||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
|
import team
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
@ -97,9 +98,10 @@ def user_info():
|
||||||
me = False if not("username" in session) else username.lower() == session["username"].lower()
|
me = False if not("username" in session) else username.lower() == session["username"].lower()
|
||||||
user = get_user(username_lower=username.lower()).first()
|
user = get_user(username_lower=username.lower()).first()
|
||||||
if user is None:
|
if user is None:
|
||||||
raise WebException("User not found.")
|
raise WebException("User not found.")
|
||||||
|
|
||||||
show_email = me if logged_in else False
|
show_email = me if logged_in else False
|
||||||
|
user_in_team = in_team(user)
|
||||||
userdata = {
|
userdata = {
|
||||||
"user_found": True,
|
"user_found": True,
|
||||||
"name": user.name,
|
"name": user.name,
|
||||||
|
@ -108,10 +110,13 @@ def user_info():
|
||||||
"admin": user.admin,
|
"admin": user.admin,
|
||||||
"registertime": datetime.datetime.fromtimestamp(user.registertime).isoformat() + "Z",
|
"registertime": datetime.datetime.fromtimestamp(user.registertime).isoformat() + "Z",
|
||||||
"me": me,
|
"me": me,
|
||||||
"show_email": show_email
|
"show_email": show_email,
|
||||||
|
"in_team": user_in_team
|
||||||
}
|
}
|
||||||
if show_email:
|
if show_email:
|
||||||
userdata["email"] = user.email
|
userdata["email"] = user.email
|
||||||
|
if user_in_team:
|
||||||
|
userdata["team"] = team.get_team_info(tid=user.tid)
|
||||||
return { "success": 1, "user": userdata }
|
return { "success": 1, "user": userdata }
|
||||||
|
|
||||||
##################
|
##################
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="col-sm-3 col-xs-12">
|
<div class="col-sm-3 col-xs-12">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<img src="//www.gravatar.com/avatar/?size=512" id="avatar" style="max-width:100%;" />
|
<img src="//www.gravatar.com/avatar/?size=512" id="avatar" style="width:100%;max-width:100%;" />
|
||||||
<small style="display:block;text-align:right;" ng-show="user['me']==true"><a href="http://en.gravatar.com/emails/" target="_blank">Edit Picture</a></small>
|
<small style="display:block;text-align:right;" ng-show="user['me']==true"><a href="http://en.gravatar.com/emails/" target="_blank">Edit Picture</a></small>
|
||||||
<h2 style="margin:0px;font-weight:bold;font-size:2em;">{{ user.name }}</h2>
|
<h2 style="margin:0px;font-weight:bold;font-size:2em;">{{ user.name }}</h2>
|
||||||
<small style="display:block;font-size:1.5em;color:#999;">@{{ user.username }}</small>
|
<small style="display:block;font-size:1.5em;color:#999;">@{{ user.username }}</small>
|
||||||
|
@ -38,13 +38,29 @@
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">Team Information</h4>
|
<h4 class="panel-title">Team Information</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="table-responsive" ng-show="user['in_team']==true">
|
||||||
<div ng-show="user['in_team']==true">
|
<table class="table table-bordered">
|
||||||
</div>
|
<tr>
|
||||||
<div ng-show="user['in_team']!=true">
|
<th>Team Name</th>
|
||||||
<p>{{ user['me']==true ? "You're" : "This user is" }} not a part of a team.</p>
|
<td>{{ user.team['teamname'] }}</td>
|
||||||
<a href="/team" class="btn btn-primary" ng-show="user['me']==true">Join or create one now »</a>
|
</tr>
|
||||||
</div>
|
<tr>
|
||||||
|
<th>School</th>
|
||||||
|
<td>{{ user.team['school'] }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Points</th>
|
||||||
|
<td>{{ user.team['points'] }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Rank</th>
|
||||||
|
<td>{{ user.team['place'] }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body" ng-show="user['in_team']!=true">
|
||||||
|
<p>{{ user['me']==true ? "You're" : "This user is" }} not a part of a team.</p>
|
||||||
|
<a href="/team" class="btn btn-primary" ng-show="user['me']==true">Join or create one now »</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
|
|
@ -45,13 +45,44 @@
|
||||||
<div id="create_team_msg"></div>
|
<div id="create_team_msg"></div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="container-fluid">
|
<fieldset class="container-fluid">
|
||||||
<div class="row">
|
<div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
|
||||||
<div class="input-group">
|
<div class="panel panel-default">
|
||||||
<input class="form-control input-lg" type="text" required name="teamname" id="teamname" placeholder="Choose a team name..." autocomplete="off" />
|
<div class="panel-heading">
|
||||||
<span class="input-group-btn">
|
<h2 class="panel-title">Create a Team</h2>
|
||||||
<input type="hidden" id="_csrf" value="{{ csrf_token }}" />
|
</div>
|
||||||
<input type="submit" class="btn btn-success btn-lg" value="Create Team" />
|
<div class="panel-body">
|
||||||
</span>
|
<form class="form-horizontal" onsubmit="login_form(); return false;" id="login_form">
|
||||||
|
<fieldset>
|
||||||
|
<div id="login_msg"></div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 form-group">
|
||||||
|
<label class="col-sm-12" for="teamname"><small>Team Name</small></label>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<input class="form-control" type="text" required name="teamname" id="teamname" placeholder="Create a team name..." autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 form-group">
|
||||||
|
<label class="col-sm-12" for="school"><small>School Name</small></label>
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<input class="form-control" type="text" required name="school" id="school" placeholder="School Name" autocomplete="off" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 form-group">
|
||||||
|
<center>
|
||||||
|
<input type="hidden" id="_csrf" value="{{ csrf_token }}" />
|
||||||
|
<input type="submit" class="btn btn-success btn-lg" value="Create Team" />
|
||||||
|
</center>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
Loading…
Reference in a new issue