mirror of https://github.com/JohnHammond/CTFd.git
add scoreboard freeze (#208)
* add scoreboard freeze * delete excess div close tag * filter out scores from team page when scoreboard freezes * allow teams to see their full score and solves in team page * fix unset place and score * change parameter and filter out /solves for graph * fix utils methods undefined * add small notice about frozen scoreboard and resolve failing tests * Update __init__.py * Update scoreboard.pyselenium-screenshot-testing
parent
a3a7d75ae8
commit
9a9b775e57
|
@ -54,10 +54,13 @@ def admin_config():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
start = None
|
start = None
|
||||||
end = None
|
end = None
|
||||||
|
freeze = None
|
||||||
if request.form.get('start'):
|
if request.form.get('start'):
|
||||||
start = int(request.form['start'])
|
start = int(request.form['start'])
|
||||||
if request.form.get('end'):
|
if request.form.get('end'):
|
||||||
end = int(request.form['end'])
|
end = int(request.form['end'])
|
||||||
|
if request.form.get('freeze'):
|
||||||
|
freeze = int(request.form['freeze'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
view_challenges_unregistered = bool(request.form.get('view_challenges_unregistered', None))
|
view_challenges_unregistered = bool(request.form.get('view_challenges_unregistered', None))
|
||||||
|
@ -103,6 +106,8 @@ def admin_config():
|
||||||
mg_base_url = utils.set_config("mg_base_url", request.form.get('mg_base_url', None))
|
mg_base_url = utils.set_config("mg_base_url", request.form.get('mg_base_url', None))
|
||||||
mg_api_key = utils.set_config("mg_api_key", request.form.get('mg_api_key', None))
|
mg_api_key = utils.set_config("mg_api_key", request.form.get('mg_api_key', None))
|
||||||
|
|
||||||
|
db_freeze = utils.set_config("freeze", freeze)
|
||||||
|
|
||||||
db_start = Config.query.filter_by(key='start').first()
|
db_start = Config.query.filter_by(key='start').first()
|
||||||
db_start.value = start
|
db_start.value = start
|
||||||
|
|
||||||
|
@ -136,6 +141,7 @@ def admin_config():
|
||||||
view_after_ctf = utils.get_config('view_after_ctf')
|
view_after_ctf = utils.get_config('view_after_ctf')
|
||||||
start = utils.get_config('start')
|
start = utils.get_config('start')
|
||||||
end = utils.get_config('end')
|
end = utils.get_config('end')
|
||||||
|
freeze = utils.get_config('freeze')
|
||||||
|
|
||||||
mail_tls = utils.get_config('mail_tls')
|
mail_tls = utils.get_config('mail_tls')
|
||||||
mail_ssl = utils.get_config('mail_ssl')
|
mail_ssl = utils.get_config('mail_ssl')
|
||||||
|
@ -157,6 +163,7 @@ def admin_config():
|
||||||
ctf_theme_config=ctf_theme,
|
ctf_theme_config=ctf_theme,
|
||||||
start=start,
|
start=start,
|
||||||
end=end,
|
end=end,
|
||||||
|
freeze=freeze,
|
||||||
hide_scores=hide_scores,
|
hide_scores=hide_scores,
|
||||||
mail_server=mail_server,
|
mail_server=mail_server,
|
||||||
mail_port=mail_port,
|
mail_port=mail_port,
|
||||||
|
|
|
@ -39,8 +39,8 @@ def admin_team(teamid):
|
||||||
.order_by(last_seen.desc()).all()
|
.order_by(last_seen.desc()).all()
|
||||||
wrong_keys = WrongKeys.query.filter_by(teamid=teamid).order_by(WrongKeys.date.asc()).all()
|
wrong_keys = WrongKeys.query.filter_by(teamid=teamid).order_by(WrongKeys.date.asc()).all()
|
||||||
awards = Awards.query.filter_by(teamid=teamid).order_by(Awards.date.asc()).all()
|
awards = Awards.query.filter_by(teamid=teamid).order_by(Awards.date.asc()).all()
|
||||||
score = user.score()
|
score = user.score(admin=True)
|
||||||
place = user.place()
|
place = user.place(admin=True)
|
||||||
return render_template('admin/team.html', solves=solves, team=user, addrs=addrs, score=score, missing=missing,
|
return render_template('admin/team.html', solves=solves, team=user, addrs=addrs, score=score, missing=missing,
|
||||||
place=place, wrong_keys=wrong_keys, awards=awards)
|
place=place, wrong_keys=wrong_keys, awards=awards)
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
|
|
|
@ -111,8 +111,18 @@ def solves(teamid=None):
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('auth.login', next='solves'))
|
return redirect(url_for('auth.login', next='solves'))
|
||||||
else:
|
else:
|
||||||
solves = Solves.query.filter_by(teamid=teamid).all()
|
solves = Solves.query.filter_by(teamid=teamid)
|
||||||
awards = Awards.query.filter_by(teamid=teamid).all()
|
awards = Awards.query.filter_by(teamid=teamid)
|
||||||
|
|
||||||
|
freeze = utils.get_config('freeze')
|
||||||
|
if freeze:
|
||||||
|
freeze = utils.unix_time_to_utc(freeze)
|
||||||
|
if teamid != session.get('id'):
|
||||||
|
solves = solves.filter(Solves.date < freeze)
|
||||||
|
awards = awards.filter(Awards.date < freeze)
|
||||||
|
|
||||||
|
solves = solves.all()
|
||||||
|
awards = awards.all()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
json = {'solves': []}
|
json = {'solves': []}
|
||||||
for solve in solves:
|
for solve in solves:
|
||||||
|
|
|
@ -159,20 +159,42 @@ class Teams(db.Model):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<team %r>' % self.name
|
return '<team %r>' % self.name
|
||||||
|
|
||||||
def score(self):
|
def score(self, admin=False):
|
||||||
score = db.func.sum(Challenges.value).label('score')
|
score = db.func.sum(Challenges.value).label('score')
|
||||||
team = db.session.query(Solves.teamid, score).join(Teams).join(Challenges).filter(Teams.banned == False, Teams.id == self.id).group_by(Solves.teamid).first()
|
team = db.session.query(Solves.teamid, score).join(Teams).join(Challenges).filter(Teams.banned == False, Teams.id == self.id)
|
||||||
award_score = db.func.sum(Awards.value).label('award_score')
|
award_score = db.func.sum(Awards.value).label('award_score')
|
||||||
award = db.session.query(award_score).filter_by(teamid=self.id).first()
|
award = db.session.query(award_score).filter_by(teamid=self.id)
|
||||||
|
|
||||||
|
if not admin:
|
||||||
|
freeze = Config.query.filter_by(key='freeze').first()
|
||||||
|
if freeze and freeze.value:
|
||||||
|
freeze = int(freeze.value)
|
||||||
|
freeze = datetime.datetime.utcfromtimestamp(freeze)
|
||||||
|
team = team.filter(Solves.date < freeze)
|
||||||
|
award = award.filter(Awards.date < freeze)
|
||||||
|
|
||||||
|
team = team.group_by(Solves.teamid).first()
|
||||||
|
award = award.first()
|
||||||
|
|
||||||
if team:
|
if team:
|
||||||
return int(team.score or 0) + int(award.award_score or 0)
|
return int(team.score or 0) + int(award.award_score or 0)
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def place(self):
|
def place(self, admin=False):
|
||||||
score = db.func.sum(Challenges.value).label('score')
|
score = db.func.sum(Challenges.value).label('score')
|
||||||
quickest = db.func.max(Solves.date).label('quickest')
|
quickest = db.func.max(Solves.date).label('quickest')
|
||||||
teams = db.session.query(Solves.teamid).join(Teams).join(Challenges).filter(Teams.banned == False).group_by(Solves.teamid).order_by(score.desc(), quickest).all()
|
teams = db.session.query(Solves.teamid).join(Teams).join(Challenges).filter(Teams.banned == False)
|
||||||
|
|
||||||
|
if not admin:
|
||||||
|
freeze = Config.query.filter_by(key='freeze').first()
|
||||||
|
if freeze and freeze.value:
|
||||||
|
freeze = int(freeze.value)
|
||||||
|
freeze = datetime.datetime.utcfromtimestamp(freeze)
|
||||||
|
teams = teams.filter(Solves.date < freeze)
|
||||||
|
|
||||||
|
teams = teams.group_by(Solves.teamid).order_by(score.desc(), quickest).all()
|
||||||
|
|
||||||
# http://codegolf.stackexchange.com/a/4712
|
# http://codegolf.stackexchange.com/a/4712
|
||||||
try:
|
try:
|
||||||
i = teams.index((self.id,)) + 1
|
i = teams.index((self.id,)) + 1
|
||||||
|
|
|
@ -9,23 +9,49 @@ scoreboard = Blueprint('scoreboard', __name__)
|
||||||
|
|
||||||
|
|
||||||
def get_standings(admin=False, count=None):
|
def get_standings(admin=False, count=None):
|
||||||
score = db.func.sum(Challenges.value).label('score')
|
scores = db.session.query(
|
||||||
date = db.func.max(Solves.date).label('date')
|
Solves.teamid.label('teamid'),
|
||||||
scores = db.session.query(Solves.teamid.label('teamid'), score, date).join(Challenges).group_by(Solves.teamid)
|
db.func.sum(Challenges.value).label('score'),
|
||||||
awards = db.session.query(Awards.teamid.label('teamid'), db.func.sum(Awards.value).label('score'), db.func.max(Awards.date).label('date')) \
|
db.func.max(Solves.date).label('date')
|
||||||
.group_by(Awards.teamid)
|
).join(Challenges).group_by(Solves.teamid)
|
||||||
|
|
||||||
|
awards = db.session.query(
|
||||||
|
Awards.teamid.label('teamid'),
|
||||||
|
db.func.sum(Awards.value).label('score'),
|
||||||
|
db.func.max(Awards.date).label('date')
|
||||||
|
).group_by(Awards.teamid)
|
||||||
|
|
||||||
|
freeze = utils.get_config('freeze')
|
||||||
|
if not admin and freeze:
|
||||||
|
scores = scores.filter(Solves.date < utils.unix_time_to_utc(freeze))
|
||||||
|
awards = awards.filter(Awards.date < utils.unix_time_to_utc(freeze))
|
||||||
|
|
||||||
results = union_all(scores, awards).alias('results')
|
results = union_all(scores, awards).alias('results')
|
||||||
sumscores = db.session.query(results.columns.teamid, db.func.sum(results.columns.score).label('score'), db.func.max(results.columns.date).label('date')) \
|
|
||||||
.group_by(results.columns.teamid).subquery()
|
sumscores = db.session.query(
|
||||||
|
results.columns.teamid,
|
||||||
|
db.func.sum(results.columns.score).label('score'),
|
||||||
|
db.func.max(results.columns.date).label('date')
|
||||||
|
).group_by(results.columns.teamid).subquery()
|
||||||
|
|
||||||
if admin:
|
if admin:
|
||||||
standings_query = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'), Teams.banned, sumscores.columns.score) \
|
standings_query = db.session.query(
|
||||||
.join(sumscores, Teams.id == sumscores.columns.teamid) \
|
Teams.id.label('teamid'),
|
||||||
.order_by(sumscores.columns.score.desc(), sumscores.columns.date)
|
Teams.name.label('name'),
|
||||||
|
Teams.banned, sumscores.columns.score
|
||||||
|
)\
|
||||||
|
.join(sumscores, Teams.id == sumscores.columns.teamid) \
|
||||||
|
.order_by(sumscores.columns.score.desc(), sumscores.columns.date)
|
||||||
else:
|
else:
|
||||||
standings_query = db.session.query(Teams.id.label('teamid'), Teams.name.label('name'), sumscores.columns.score) \
|
standings_query = db.session.query(
|
||||||
.join(sumscores, Teams.id == sumscores.columns.teamid) \
|
Teams.id.label('teamid'),
|
||||||
.filter(Teams.banned == False) \
|
Teams.name.label('name'),
|
||||||
.order_by(sumscores.columns.score.desc(), sumscores.columns.date)
|
sumscores.columns.score
|
||||||
|
)\
|
||||||
|
.join(sumscores, Teams.id == sumscores.columns.teamid) \
|
||||||
|
.filter(Teams.banned == False) \
|
||||||
|
.order_by(sumscores.columns.score.desc(), sumscores.columns.date)
|
||||||
|
|
||||||
if count is None:
|
if count is None:
|
||||||
standings = standings_query.all()
|
standings = standings_query.all()
|
||||||
else:
|
else:
|
||||||
|
@ -41,7 +67,7 @@ def scoreboard_view():
|
||||||
if utils.hide_scores():
|
if utils.hide_scores():
|
||||||
return render_template('scoreboard.html', errors=['Scores are currently hidden'])
|
return render_template('scoreboard.html', errors=['Scores are currently hidden'])
|
||||||
standings = get_standings()
|
standings = get_standings()
|
||||||
return render_template('scoreboard.html', teams=standings)
|
return render_template('scoreboard.html', teams=standings, score_frozen=utils.is_scoreboard_frozen())
|
||||||
|
|
||||||
|
|
||||||
@scoreboard.route('/scores')
|
@scoreboard.route('/scores')
|
||||||
|
@ -73,8 +99,20 @@ def topteams(count):
|
||||||
standings = get_standings(count=count)
|
standings = get_standings(count=count)
|
||||||
|
|
||||||
for team in standings:
|
for team in standings:
|
||||||
solves = Solves.query.filter_by(teamid=team.teamid).all()
|
solves = Solves.query.filter_by(teamid=team.teamid)
|
||||||
awards = Awards.query.filter_by(teamid=team.teamid).all()
|
awards = Awards.query.filter_by(teamid=team.teamid)
|
||||||
|
|
||||||
|
|
||||||
|
freeze = utils.get_config('freeze')
|
||||||
|
|
||||||
|
if freeze:
|
||||||
|
solves = solves.filter(Solves.date < utils.unix_time_to_utc(freeze))
|
||||||
|
awards = awards.filter(Awards.date < utils.unix_time_to_utc(freeze))
|
||||||
|
|
||||||
|
solves = solves.all()
|
||||||
|
awards = awards.all()
|
||||||
|
|
||||||
|
|
||||||
json['scores'][team.name] = []
|
json['scores'][team.name] = []
|
||||||
for x in solves:
|
for x in solves:
|
||||||
json['scores'][team.name].append({
|
json['scores'][team.name].append({
|
||||||
|
|
|
@ -179,6 +179,9 @@
|
||||||
<li role="presentation">
|
<li role="presentation">
|
||||||
<a href="#end-date" aria-controls="end-date" role="tab" data-toggle="tab">End Time</a>
|
<a href="#end-date" aria-controls="end-date" role="tab" data-toggle="tab">End Time</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li role="presentation">
|
||||||
|
<a href="#freeze-date" aria-controls="freeze-date" role="tab" data-toggle="tab">Freeze Time</a>
|
||||||
|
</li>
|
||||||
<sub style="float:right;">* All time fields required</sub>
|
<sub style="float:right;">* All time fields required</sub>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -307,6 +310,70 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div role="tabpanel" class="tab-pane" id="freeze-date">
|
||||||
|
<div class="row" id="freeze-date">
|
||||||
|
<div class="form-group col-xs-2">
|
||||||
|
<label for="freeze-month">Month:</label>
|
||||||
|
<input class="form-control freeze-date" id='freeze-month' name='freeze-month' min="1" max="12"
|
||||||
|
type='number'>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-2">
|
||||||
|
<label for="freeze-day">Day:</label>
|
||||||
|
<input class="form-control freeze-date" id='freeze-day' name='freeze-day' min="1" max="31"
|
||||||
|
type='number'>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-2">
|
||||||
|
<label for="freeze-year">Year:</label>
|
||||||
|
<input class="form-control freeze-date" id='freeze-year' name='freeze-year' type='number'>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-2">
|
||||||
|
<label for="freeze-hour">Hour:</label>
|
||||||
|
<input class="form-control freeze-date" id='freeze-hour' name='freeze-hour' min="0" max="23"
|
||||||
|
type='number'>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-2">
|
||||||
|
<label for="freeze-minute">Minute:</label>
|
||||||
|
<input class="form-control freeze-date" id='freeze-minute' name='freeze-minute' min="0"
|
||||||
|
max="59" type='number'>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-4">
|
||||||
|
<label for="freeze-timezone">Timezone:</label>
|
||||||
|
<select class="form-control freeze-date" id="freeze-timezone">
|
||||||
|
<script>
|
||||||
|
document.write('<option>' + moment.tz.guess() + '</option>');
|
||||||
|
var tz_names = moment.tz.names();
|
||||||
|
for (var i = 0; i < tz_names.length; i++) {
|
||||||
|
document.write('<option>' + tz_names[i] + '</option>');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-12">
|
||||||
|
<label for="freeze-local">Local Time:</label>
|
||||||
|
<input class="form-control" id='freeze-local' type='text'
|
||||||
|
placeholder="Freeze Date (Local Time)" readonly>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-12">
|
||||||
|
<label for="freeze-zonetime">Timezone Time:</label>
|
||||||
|
<input class="form-control" id='freeze-zonetime' type='text'
|
||||||
|
placeholder="Freeze Date (Timezone Time)" readonly>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group col-xs-12">
|
||||||
|
<label for="freeze">UTC Timestamp:</label>
|
||||||
|
<input class="form-control" id='freeze' name='freeze' type='text'
|
||||||
|
placeholder="Freeze Date (UTC timestamp)"
|
||||||
|
{% if freeze is defined and freeze != None %}value="{{ freeze }}"{% endif %} readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
@ -343,57 +410,30 @@
|
||||||
var timestamp = parseInt(timestamp);
|
var timestamp = parseInt(timestamp);
|
||||||
}
|
}
|
||||||
var m = moment(timestamp * 1000);
|
var m = moment(timestamp * 1000);
|
||||||
if (place == 'start'){
|
console.log('Loading ' + place);
|
||||||
console.log('Loading start');
|
console.log(timestamp);
|
||||||
console.log(timestamp);
|
console.log(m.toISOString());
|
||||||
console.log(m.toISOString());
|
console.log(m.unix());
|
||||||
console.log(m.unix());
|
var month = $('#' + place + '-month').val(m.month() + 1); // Months are zero indexed (http://momentjs.com/docs/#/get-set/month/)
|
||||||
var month = $('#start-month').val(m.month() + 1); // Months are zero indexed (http://momentjs.com/docs/#/get-set/month/)
|
var day = $('#' + place + '-day').val(m.date());
|
||||||
var day = $('#start-day').val(m.date());
|
var year = $('#' + place + '-year').val(m.year());
|
||||||
var year = $('#start-year').val(m.year());
|
var hour = $('#' + place + '-hour').val(m.hour());
|
||||||
var hour = $('#start-hour').val(m.hour());
|
var minute = $('#' + place + '-minute').val(m.minute());
|
||||||
var minute = $('#start-minute').val(m.minute());
|
load_date_values(place);
|
||||||
load_date_values('start');
|
|
||||||
} else if (place == 'end'){
|
|
||||||
console.log('Loading end');
|
|
||||||
console.log(timestamp);
|
|
||||||
console.log(m.toISOString());
|
|
||||||
console.log(m.unix());
|
|
||||||
var month = $('#end-month').val(m.month() + 1);
|
|
||||||
var day = $('#end-day').val(m.date());
|
|
||||||
var year = $('#end-year').val(m.year());
|
|
||||||
var hour = $('#end-hour').val(m.hour());
|
|
||||||
var minute = $('#end-minute').val(m.minute());
|
|
||||||
load_date_values('end');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_date_values(place){
|
function load_date_values(place){
|
||||||
if (place == "start"){
|
var month = $('#' + place + '-month').val();
|
||||||
var month = $('#start-month').val();
|
var day = $('#' + place + '-day').val();
|
||||||
var day = $('#start-day').val();
|
var year = $('#' + place + '-year').val();
|
||||||
var year = $('#start-year').val();
|
var hour = $('#' + place + '-hour').val();
|
||||||
var hour = $('#start-hour').val();
|
var minute = $('#' + place + '-minute').val();
|
||||||
var minute = $('#start-minute').val();
|
var timezone = $('#' + place + '-timezone').val();
|
||||||
var timezone = $('#start-timezone').val();
|
|
||||||
} else if (place == "end") {
|
|
||||||
var month = $('#end-month').val();
|
|
||||||
var day = $('#end-day').val();
|
|
||||||
var year = $('#end-year').val();
|
|
||||||
var hour = $('#end-hour').val();
|
|
||||||
var minute = $('#end-minute').val();
|
|
||||||
var timezone = $('#end-timezone').val();
|
|
||||||
}
|
|
||||||
var utc = convert_date_to_moment(month, day, year, hour, minute, timezone);
|
var utc = convert_date_to_moment(month, day, year, hour, minute, timezone);
|
||||||
if (place == "start") {
|
$('#' + place).val(utc.unix());
|
||||||
$('#start').val(utc.unix());
|
$('#' + place + '-local').val(utc.local().format("dddd, MMMM Do YYYY, h:mm:ss a zz"));
|
||||||
$('#start-local').val(utc.local().format("dddd, MMMM Do YYYY, h:mm:ss a zz"));
|
$('#' + place + '-zonetime').val(utc.tz(timezone).format("dddd, MMMM Do YYYY, h:mm:ss a zz"));
|
||||||
$('#start-zonetime').val(utc.tz(timezone).format("dddd, MMMM Do YYYY, h:mm:ss a zz"));
|
|
||||||
} else if (place == "end") {
|
|
||||||
$('#end').val(utc.unix());
|
|
||||||
$('#end-local').val(utc.local().format("dddd, MMMM Do YYYY, h:mm:ss a zz"));
|
|
||||||
$('#end-zonetime').val(utc.tz(timezone).format("dddd, MMMM Do YYYY, h:mm:ss a zz"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function convert_date_to_moment(month, day, year, hour, minute, timezone){
|
function convert_date_to_moment(month, day, year, hour, minute, timezone){
|
||||||
|
@ -431,6 +471,10 @@
|
||||||
load_date_values('end');
|
load_date_values('end');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.freeze-date').change(function () {
|
||||||
|
load_date_values('freeze');
|
||||||
|
});
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
var hash = window.location.hash;
|
var hash = window.location.hash;
|
||||||
|
@ -446,6 +490,7 @@
|
||||||
|
|
||||||
var start = $('#start').val();
|
var start = $('#start').val();
|
||||||
var end = $('#end').val();
|
var end = $('#end').val();
|
||||||
|
var freeze = $('#freeze').val();
|
||||||
console.log(start);
|
console.log(start);
|
||||||
console.log(end);
|
console.log(end);
|
||||||
if (start){
|
if (start){
|
||||||
|
@ -454,6 +499,9 @@
|
||||||
if (end){
|
if (end){
|
||||||
load_timestamp('end', end);
|
load_timestamp('end', end);
|
||||||
}
|
}
|
||||||
|
if (freeze) {
|
||||||
|
load_timestamp('freeze', freeze);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -16,6 +16,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
|
{% if score_frozen %}
|
||||||
|
<div class="container main-container">
|
||||||
|
<div class="row">
|
||||||
|
<h1>Scoreboard has been frozen.</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="score-graph"></div>
|
<div id="score-graph"></div>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,15 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
|
{% if score_frozen %}
|
||||||
|
<div class="container main-container">
|
||||||
|
<div class="row">
|
||||||
|
<h1>Scoreboard has been frozen.</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="team-info">
|
<div class="team-info">
|
||||||
<h2 id="team-place" class="text-center">
|
<h2 id="team-place" class="text-center">
|
||||||
{%if place %}
|
{%if place %}
|
||||||
|
|
|
@ -212,6 +212,18 @@ def view_after_ctf():
|
||||||
return bool(get_config('view_after_ctf'))
|
return bool(get_config('view_after_ctf'))
|
||||||
|
|
||||||
|
|
||||||
|
def is_scoreboard_frozen():
|
||||||
|
freeze = get_config('freeze')
|
||||||
|
|
||||||
|
if freeze:
|
||||||
|
freeze = int(freeze)
|
||||||
|
if freeze < time.time():
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ctftime():
|
def ctftime():
|
||||||
""" Checks whether it's CTF time or not. """
|
""" Checks whether it's CTF time or not. """
|
||||||
|
|
||||||
|
@ -274,6 +286,10 @@ def unix_time_millis(dt):
|
||||||
return unix_time(dt) * 1000
|
return unix_time(dt) * 1000
|
||||||
|
|
||||||
|
|
||||||
|
def unix_time_to_utc(t):
|
||||||
|
return datetime.datetime.utcfromtimestamp(t)
|
||||||
|
|
||||||
|
|
||||||
def get_ip():
|
def get_ip():
|
||||||
""" Returns the IP address of the currently in scope request. The approach is to define a list of trusted proxies
|
""" Returns the IP address of the currently in scope request. The approach is to define a list of trusted proxies
|
||||||
(in this case the local network), and only trust the most recently defined untrusted IP address.
|
(in this case the local network), and only trust the most recently defined untrusted IP address.
|
||||||
|
|
|
@ -56,11 +56,12 @@ def setup():
|
||||||
</div>""".format(request.script_root))
|
</div>""".format(request.script_root))
|
||||||
|
|
||||||
# max attempts per challenge
|
# max attempts per challenge
|
||||||
max_tries = utils.set_config("max_tries", 0)
|
max_tries = utils.set_config('max_tries', 0)
|
||||||
|
|
||||||
# Start time
|
# Start time
|
||||||
start = utils.set_config('start', None)
|
start = utils.set_config('start', None)
|
||||||
end = utils.set_config('end', None)
|
end = utils.set_config('end', None)
|
||||||
|
freeze = utils.set_config('freeze', None)
|
||||||
|
|
||||||
# Challenges cannot be viewed by unregistered users
|
# Challenges cannot be viewed by unregistered users
|
||||||
view_challenges_unregistered = utils.set_config('view_challenges_unregistered', None)
|
view_challenges_unregistered = utils.set_config('view_challenges_unregistered', None)
|
||||||
|
@ -102,7 +103,7 @@ def setup():
|
||||||
# Custom CSS handler
|
# Custom CSS handler
|
||||||
@views.route('/static/user.css')
|
@views.route('/static/user.css')
|
||||||
def custom_css():
|
def custom_css():
|
||||||
return Response(utils.get_config("css"), mimetype='text/css')
|
return Response(utils.get_config('css'), mimetype='text/css')
|
||||||
|
|
||||||
|
|
||||||
# Static HTML files
|
# Static HTML files
|
||||||
|
@ -139,11 +140,23 @@ def team(teamid):
|
||||||
if utils.get_config('view_scoreboard_if_utils.authed') and not utils.authed():
|
if utils.get_config('view_scoreboard_if_utils.authed') and not utils.authed():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
errors = []
|
errors = []
|
||||||
|
freeze = utils.get_config('freeze')
|
||||||
user = Teams.query.filter_by(id=teamid).first_or_404()
|
user = Teams.query.filter_by(id=teamid).first_or_404()
|
||||||
solves = Solves.query.filter_by(teamid=teamid)
|
solves = Solves.query.filter_by(teamid=teamid)
|
||||||
awards = Awards.query.filter_by(teamid=teamid).all()
|
awards = Awards.query.filter_by(teamid=teamid)
|
||||||
score = user.score()
|
|
||||||
place = user.place()
|
place = user.place()
|
||||||
|
score = user.score()
|
||||||
|
|
||||||
|
if freeze:
|
||||||
|
freeze = utils.unix_time_to_utc(freeze)
|
||||||
|
if teamid != session.get('id'):
|
||||||
|
solves = solves.filter(Solves.date < freeze)
|
||||||
|
awards = awards.filter(Awards.date < freeze)
|
||||||
|
|
||||||
|
solves = solves.all()
|
||||||
|
awards = awards.all()
|
||||||
|
|
||||||
db.session.close()
|
db.session.close()
|
||||||
|
|
||||||
if utils.hide_scores() and teamid != session.get('id'):
|
if utils.hide_scores() and teamid != session.get('id'):
|
||||||
|
@ -153,7 +166,7 @@ def team(teamid):
|
||||||
return render_template('team.html', team=user, errors=errors)
|
return render_template('team.html', team=user, errors=errors)
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return render_template('team.html', solves=solves, awards=awards, team=user, score=score, place=place)
|
return render_template('team.html', solves=solves, awards=awards, team=user, score=score, place=place, score_frozen=utils.is_scoreboard_frozen())
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
json = {'solves': []}
|
json = {'solves': []}
|
||||||
for x in solves:
|
for x in solves:
|
||||||
|
|
Loading…
Reference in New Issue