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 wrapper
|
||||
|
||||
import user # Must go below api_wrapper to prevent import loops
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
|
@ -58,6 +56,8 @@ def login_required(f):
|
|||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
import user # Must go below api_wrapper to prevent import loops
|
||||
|
||||
def admins_only(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
|
||||
import time
|
||||
import traceback
|
||||
import utils
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
@ -33,11 +35,14 @@ class Teams(db.Model):
|
|||
teamname_lower = db.Column(db.String(64), unique=True)
|
||||
school = db.Column(db.Text)
|
||||
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_lower = teamname.lower()
|
||||
self.school = school
|
||||
self.owner = owner
|
||||
self.observer = observer
|
||||
|
||||
def get_members(self):
|
||||
members = [ ]
|
||||
|
@ -47,6 +52,25 @@ class Teams(db.Model):
|
|||
})
|
||||
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):
|
||||
pid = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(128))
|
||||
|
@ -77,13 +101,19 @@ class Files(db.Model):
|
|||
|
||||
class Solves(db.Model):
|
||||
sid = db.Column(db.Integer, primary_key=True)
|
||||
pid = db.Column(db.Integer)
|
||||
tid = db.Column(db.Integer)
|
||||
pid = db.Column(db.Integer, db.ForeignKey("problems.pid"))
|
||||
tid = db.Column(db.Integer, db.ForeignKey("teams.tid"))
|
||||
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.tid = tid
|
||||
self.flag = flag
|
||||
self.correct = correct
|
||||
|
||||
##########
|
||||
# TOKENS #
|
||||
|
|
|
@ -4,9 +4,9 @@ from voluptuous import Schema, Length, Required
|
|||
|
||||
from models import db, Teams, Users
|
||||
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
|
||||
|
||||
import user
|
||||
import utils
|
||||
|
||||
blueprint = Blueprint("team", __name__)
|
||||
|
@ -20,18 +20,19 @@ blueprint = Blueprint("team", __name__)
|
|||
@login_required
|
||||
def team_create():
|
||||
params = utils.flat_multi(request.form)
|
||||
user = get_user().first()
|
||||
if user.tid is not None or user.tid >= 0 or get_team(owner=user.uid).first() is not None:
|
||||
_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:
|
||||
raise WebException("You're already in a team!")
|
||||
|
||||
verify_to_schema(TeamSchema, params)
|
||||
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():
|
||||
db.session.add(team)
|
||||
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()
|
||||
|
||||
return { "success": 1, "message": "Success!" }
|
||||
|
@ -39,7 +40,7 @@ def team_create():
|
|||
@blueprint.route("/info", methods=["GET"])
|
||||
@api_wrapper
|
||||
def team_info():
|
||||
logged_in = is_logged_in()
|
||||
logged_in = user.is_logged_in()
|
||||
me = False
|
||||
teamname = utils.flat_multi(request.args).get("teamname")
|
||||
if logged_in:
|
||||
|
@ -57,7 +58,8 @@ def team_info():
|
|||
raise WebException("Team not found.")
|
||||
|
||||
teamdata = {
|
||||
"teamname": team.teamname
|
||||
"teamname": team.teamname,
|
||||
"school": team.school
|
||||
}
|
||||
teamdata["in_team"] = me
|
||||
return { "success": 1, "team": teamdata }
|
||||
|
@ -74,8 +76,25 @@ TeamSchema = Schema({
|
|||
([utils.__check_ascii], "Please only use ASCII characters in your teamname."),
|
||||
([__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)
|
||||
|
||||
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):
|
||||
match = {}
|
||||
if teamname != None:
|
||||
|
@ -86,10 +105,10 @@ def get_team(tid=None, teamname=None, teamname_lower=None, owner=None):
|
|||
match.update({ "tid": tid })
|
||||
elif owner != None:
|
||||
match.update({ "owner": owner })
|
||||
elif is_logged_in():
|
||||
user = get_user().first()
|
||||
if user.tid is not None:
|
||||
match.update({ "tid": user.tid })
|
||||
elif user.is_logged_in():
|
||||
_user = user.get_user().first()
|
||||
if _user.tid is not None:
|
||||
match.update({ "tid": _user.tid })
|
||||
with app.app_context():
|
||||
result = Teams.query.filter_by(**match)
|
||||
return result
|
|
@ -10,6 +10,7 @@ import datetime
|
|||
import logger
|
||||
import re
|
||||
import requests
|
||||
import team
|
||||
import utils
|
||||
|
||||
###############
|
||||
|
@ -100,6 +101,7 @@ def user_info():
|
|||
raise WebException("User not found.")
|
||||
|
||||
show_email = me if logged_in else False
|
||||
user_in_team = in_team(user)
|
||||
userdata = {
|
||||
"user_found": True,
|
||||
"name": user.name,
|
||||
|
@ -108,10 +110,13 @@ def user_info():
|
|||
"admin": user.admin,
|
||||
"registertime": datetime.datetime.fromtimestamp(user.registertime).isoformat() + "Z",
|
||||
"me": me,
|
||||
"show_email": show_email
|
||||
"show_email": show_email,
|
||||
"in_team": user_in_team
|
||||
}
|
||||
if show_email:
|
||||
userdata["email"] = user.email
|
||||
if user_in_team:
|
||||
userdata["team"] = team.get_team_info(tid=user.tid)
|
||||
return { "success": 1, "user": userdata }
|
||||
|
||||
##################
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="col-sm-3 col-xs-12">
|
||||
<div class="panel panel-default">
|
||||
<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>
|
||||
<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>
|
||||
|
@ -38,13 +38,29 @@
|
|||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Team Information</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div ng-show="user['in_team']==true">
|
||||
</div>
|
||||
<div 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 class="table-responsive" ng-show="user['in_team']==true">
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>Team Name</th>
|
||||
<td>{{ user.team['teamname'] }}</td>
|
||||
</tr>
|
||||
<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 class="panel panel-default">
|
||||
|
|
|
@ -45,13 +45,44 @@
|
|||
<div id="create_team_msg"></div>
|
||||
</fieldset>
|
||||
<fieldset class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="input-group">
|
||||
<input class="form-control input-lg" type="text" required name="teamname" id="teamname" placeholder="Choose a team name..." autocomplete="off" />
|
||||
<span class="input-group-btn">
|
||||
<input type="hidden" id="_csrf" value="{{ csrf_token }}" />
|
||||
<input type="submit" class="btn btn-success btn-lg" value="Create Team" />
|
||||
</span>
|
||||
<div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Create a Team</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<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>
|
||||
</fieldset>
|
||||
|
|
Loading…
Reference in a new issue