lots of things!
parent
3e2590090d
commit
d93bc0d438
|
@ -5,3 +5,4 @@ dump.rdb
|
||||||
/problems
|
/problems
|
||||||
__pycache__
|
__pycache__
|
||||||
/static/*
|
/static/*
|
||||||
|
/secrets
|
||||||
|
|
29
app.py
29
app.py
|
@ -8,6 +8,7 @@ from peewee import fn
|
||||||
import config
|
import config
|
||||||
import utils
|
import utils
|
||||||
import redis
|
import redis
|
||||||
|
import requests
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
@ -37,10 +38,13 @@ def root():
|
||||||
@app.route('/scoreboard/')
|
@app.route('/scoreboard/')
|
||||||
def scoreboard():
|
def scoreboard():
|
||||||
data = utils.get_complex("scoreboard")
|
data = utils.get_complex("scoreboard")
|
||||||
if not data:
|
graphdata = utils.get_complex("graph")
|
||||||
|
if not data or not graphdata:
|
||||||
data = utils.calculate_scores()
|
data = utils.calculate_scores()
|
||||||
utils.set_complex("scoreboard", data, 10)
|
graphdata = utils.calculate_graph(data)
|
||||||
return render_template("scoreboard.html", data=data)
|
utils.set_complex("scoreboard", data, 120)
|
||||||
|
utils.set_complex("graph", graphdata, 120)
|
||||||
|
return render_template("scoreboard.html", data=data, graphdata=graphdata)
|
||||||
|
|
||||||
@app.route('/login/', methods=["GET", "POST"])
|
@app.route('/login/', methods=["GET", "POST"])
|
||||||
def login():
|
def login():
|
||||||
|
@ -64,12 +68,24 @@ def register():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
return render_template("register.html")
|
return render_template("register.html")
|
||||||
elif request.method == "POST":
|
elif request.method == "POST":
|
||||||
|
if "g-recaptcha-response" not in request.form:
|
||||||
|
flash("Please complete the CAPTCHA.")
|
||||||
|
return render_template("register.html")
|
||||||
|
|
||||||
|
captcha_response = request.form["g-recaptcha-response"]
|
||||||
|
verify_data = dict(secret=config.secret.recaptcha_secret, response=captcha_response, remoteip=utils.get_ip())
|
||||||
|
result = requests.post("https://www.google.com/recaptcha/api/siteverify", verify_data).json()["success"]
|
||||||
|
if not result:
|
||||||
|
flash("Invalid CAPTCHA response.")
|
||||||
|
return render_template("register.html")
|
||||||
|
|
||||||
team_name = request.form["team_name"]
|
team_name = request.form["team_name"]
|
||||||
team_email = request.form["team_email"]
|
team_email = request.form["team_email"]
|
||||||
team_elig = "team_eligibility" in request.form
|
team_elig = "team_eligibility" in request.form
|
||||||
affiliation = request.form["affiliation"]
|
affiliation = request.form["affiliation"]
|
||||||
team_key = utils.generate_team_key()
|
team_key = utils.generate_team_key()
|
||||||
team = Team.create(name=team_name, email=team_email, eligible=team_elig, affiliation=affiliation, key=team_key)
|
team = Team.create(name=team_name, email=team_email, eligible=team_elig, affiliation=affiliation, key=team_key)
|
||||||
|
TeamAccess.create(team=team, ip=utils.get_ip(), time=datetime.now())
|
||||||
session["team_id"] = team.id
|
session["team_id"] = team.id
|
||||||
flash("Team created.")
|
flash("Team created.")
|
||||||
return redirect(url_for('dashboard'))
|
return redirect(url_for('dashboard'))
|
||||||
|
@ -98,7 +114,12 @@ def dashboard():
|
||||||
team_solves = ChallengeSolve.select(ChallengeSolve, Challenge).join(Challenge).where(ChallengeSolve.team == g.team)
|
team_solves = ChallengeSolve.select(ChallengeSolve, Challenge).join(Challenge).where(ChallengeSolve.team == g.team)
|
||||||
team_adjustments = ScoreAdjustment.select().where(ScoreAdjustment.team == g.team)
|
team_adjustments = ScoreAdjustment.select().where(ScoreAdjustment.team == g.team)
|
||||||
team_score = sum([i.challenge.points for i in team_solves] + [i.value for i in team_adjustments])
|
team_score = sum([i.challenge.points for i in team_solves] + [i.value for i in team_adjustments])
|
||||||
return render_template("dashboard.html", team_solves=team_solves, team_adjustments=team_adjustments, team_score=team_score)
|
first_login = False
|
||||||
|
if g.team.first_login:
|
||||||
|
first_login = True
|
||||||
|
g.team.first_login = False
|
||||||
|
g.team.save()
|
||||||
|
return render_template("dashboard.html", team_solves=team_solves, team_adjustments=team_adjustments, team_score=team_score, first_login=first_login)
|
||||||
elif request.method == "POST":
|
elif request.method == "POST":
|
||||||
team_name = request.form["team_name"]
|
team_name = request.form["team_name"]
|
||||||
team_email = request.form["team_email"]
|
team_email = request.form["team_email"]
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
ctf_name = "TJCTF"
|
ctf_name = "TJCTF"
|
||||||
eligibility = "In order to be eligible for prizes, all members of your team must be in high school, and you must not have more than four team members."
|
eligibility = "In order to be eligible for prizes, all members of your team must be in high school, and you must not have more than four team members."
|
||||||
|
tagline = "a cybersecurity competition created by TJHSST students"
|
||||||
competition_is_running = True
|
competition_is_running = True
|
||||||
cdn = True
|
cdn = True
|
||||||
proxied_ip_header = "X-Forwarded-For"
|
proxied_ip_header = "X-Forwarded-For"
|
||||||
flag_rl = 10
|
flag_rl = 10
|
||||||
|
teams_on_graph = 10
|
||||||
|
|
||||||
|
# Don't touch these. Instead, copy secrets.example to secrets and edit that.
|
||||||
|
import yaml
|
||||||
|
from collections import namedtuple
|
||||||
|
with open("secrets") as f:
|
||||||
|
_secret = yaml.load(f)
|
||||||
|
secret = namedtuple('SecretsDict', _secret.keys())(**_secret)
|
||||||
|
|
18
ctftool
18
ctftool
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
from database import *
|
from database import *
|
||||||
|
from datetime import datetime, timedelta
|
||||||
import sys
|
import sys
|
||||||
import yaml
|
import yaml
|
||||||
import random
|
import random
|
||||||
|
@ -26,7 +27,22 @@ elif operation == "gen-challenge":
|
||||||
n = int(sys.argv[2])
|
n = int(sys.argv[2])
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
name = str(random.randint(0, 999999999))
|
name = str(random.randint(0, 999999999))
|
||||||
chal = Challenge.create(name="Challenge {}".format(name), category="Generated", description="Free flags. it's the number in the problem name lorem ipsum dolor sit whatever i don't even care", points=random.randint(50, 400), flag=name)
|
chal = Challenge.create(name="Challenge".format(name), category="Generated", description="Lorem ipsum, dolor sit amet. The flag is {}".format(name), points=random.randint(50, 400), flag=name)
|
||||||
print("Challenge added with id {}".format(chal.id))
|
print("Challenge added with id {}".format(chal.id))
|
||||||
|
|
||||||
|
elif operation == "gen-team":
|
||||||
|
n = int(sys.argv[2])
|
||||||
|
chals = list(Challenge.select())
|
||||||
|
ctz = datetime.now()
|
||||||
|
diff = timedelta(minutes=5)
|
||||||
|
for i in range(n):
|
||||||
|
name = "Team {}".format(i + 1)
|
||||||
|
t = Team.create(name=name, email="none@none.com", affiliation="Autogenerated", eligible=True, key="")
|
||||||
|
t.key = "autogen{}".format(t.id)
|
||||||
|
t.save()
|
||||||
|
print("Team added with id {}".format(t.id))
|
||||||
|
for i in random.sample(chals, 5):
|
||||||
|
ChallengeSolve.create(team=t, challenge=i, time=ctz)
|
||||||
|
ctz = ctz + (diff * random.randint(-10, 10))
|
||||||
|
|
||||||
# vim: syntax=python:ft=python
|
# vim: syntax=python:ft=python
|
||||||
|
|
|
@ -10,6 +10,7 @@ class Team(BaseModel):
|
||||||
email = CharField()
|
email = CharField()
|
||||||
affiliation = CharField()
|
affiliation = CharField()
|
||||||
eligible = BooleanField()
|
eligible = BooleanField()
|
||||||
|
first_login = BooleanField(default=True)
|
||||||
key = CharField()
|
key = CharField()
|
||||||
|
|
||||||
def solved(self, challenge):
|
def solved(self, challenge):
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<title>{{ config.ctf_name }} :: {% block title %}Home{% endblock %}</title>
|
<title>{{ config.ctf_name }} :: {% block title %}Home{% endblock %}</title>
|
||||||
{% if config.cdn %}
|
{% if config.cdn %}
|
||||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.1/css/materialize.min.css" />
|
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.1/css/materialize.min.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.9.0/vis.min.css" />
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||||
{% else %}
|
{% else %}
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='materialize.min.css') }}" />
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='materialize.min.css') }}" />
|
||||||
|
@ -16,8 +17,10 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="nav-wrapper">
|
<div class="nav-wrapper">
|
||||||
<ul class="left">
|
<ul class="left">
|
||||||
{% if config.competition_is_running and logged_in %}
|
{% if config.competition_is_running %}
|
||||||
|
{% if logged_in %}
|
||||||
<li><a href="{{ url_for('challenges') }}">Challenges</a></li>
|
<li><a href="{{ url_for('challenges') }}">Challenges</a></li>
|
||||||
|
{% endif %}
|
||||||
<li><a href="{{ url_for('scoreboard') }}">Scoreboard</a></li>
|
<li><a href="{{ url_for('scoreboard') }}">Scoreboard</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -43,6 +46,7 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.1/js/materialize.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.1/js/materialize.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.4.3/jquery.timeago.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.4.3/jquery.timeago.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.9.0/vis.min.js"></script>
|
||||||
<script>$("abbr.time").timeago();</script>
|
<script>$("abbr.time").timeago();</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
|
||||||
|
@ -53,5 +57,7 @@
|
||||||
Materialize.toast({{ message | tojson }}, 4000);
|
Materialize.toast({{ message | tojson }}, 4000);
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</script>
|
</script>
|
||||||
|
{% block postscript %}
|
||||||
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -36,10 +36,10 @@
|
||||||
<div class="col s12">
|
<div class="col s12">
|
||||||
<div class="card blue darken-1">
|
<div class="card blue darken-1">
|
||||||
<div class="card-content white-text">
|
<div class="card-content white-text">
|
||||||
<span class="card-title">Login information</span>
|
<span class="card-title">Team key: <code>{{ team.key }}</code></span>
|
||||||
<p>Your team key is <code>{{ team.key }}</code>. Share this with your teammates,
|
<p>Share this with your teammates, and keep it in a safe place. <strong>You need your team key
|
||||||
and keep it in a safe place. <strong>You need your team key in order to log in.
|
in order to log in.</strong> If you lose it, an organizer can send it to your team email,
|
||||||
</strong>If you lose it, an organizer can send it to your team email, which is shown below.</p>
|
which is shown below.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -127,4 +127,24 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="right"><strong class="bigger">Your score is {{ team_score }}.</strong></p>
|
<p class="right"><strong class="bigger">Your score is {{ team_score }}.</strong></p>
|
||||||
</section>
|
</section>
|
||||||
|
<div id="firstlogin" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h4>Welcome to {{ config.ctf_name }}!</h4>
|
||||||
|
<p>Hi, {{ team.name }}! Welcome to {{ config.ctf_name }}, {{ config.tagline }}.</p>
|
||||||
|
|
||||||
|
<p>First off, please check the email you signed up with. You must confirm your account to solve problems. If needed, you can change the Team Email or resend confirmation on this page.</p>
|
||||||
|
|
||||||
|
<p>Your Team Key will be under Login Information. It was also sent to your team email. This is the only way to log in, so distribute it to your team members.</p>
|
||||||
|
|
||||||
|
<p>Once that's done, we recommend you read the Rules and FAQ. Then, do some Practice to warm up for the competition, or join the Chat to meet your fellow competitors and ask questions. The competition will begin soon enough, but in the meanwhile, explore the site!</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Dismiss</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block postscript %}
|
||||||
|
{% if first_login %}
|
||||||
|
<script>$("#firstlogin").openModal();</script>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% block head %}
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #1565C0
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Login</h2>
|
<div class="row" style="margin-top: 30px;">
|
||||||
|
<div class="col s8 offset-s2">
|
||||||
|
<div class="card gray">
|
||||||
|
<div class="card-content center">
|
||||||
|
<span class="card-title black-text">Login</span>
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<input id="team-key" name="team_key" type="text" />
|
<input id="team-key" name="team_key" type="text" />
|
||||||
|
@ -9,4 +23,9 @@
|
||||||
</div>
|
</div>
|
||||||
<button class="btn waves-effect waves-light" type="submit">Login</button>
|
<button class="btn waves-effect waves-light" type="submit">Login</button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% block head %}
|
||||||
|
<script src='https://www.google.com/recaptcha/api.js'></script>
|
||||||
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Register a Team</h2>
|
<h2>Register a Team</h2>
|
||||||
<p>After registering, you will be directed to your team's dashboard. This will
|
<p>After registering, you will be directed to your team's dashboard. This will
|
||||||
|
@ -26,8 +29,9 @@ team members.</strong></p>
|
||||||
status before sending you prizes.</p>
|
status before sending you prizes.</p>
|
||||||
<input id="team-eligibility" name="team_eligibility" type="checkbox" />
|
<input id="team-eligibility" name="team_eligibility" type="checkbox" />
|
||||||
<label for="team-eligibility">Eligibility Certification</label>
|
<label for="team-eligibility">Eligibility Certification</label>
|
||||||
<input name="_csrf_token" type="hidden" value="{{ csrf_token() }}" />
|
|
||||||
<br /><br />
|
<br /><br />
|
||||||
|
<div class="g-recaptcha" data-sitekey="{{ config.secret.recaptcha_key }}"></div>
|
||||||
|
<input name="_csrf_token" type="hidden" value="{{ csrf_token() }}" />
|
||||||
<button class="btn waves-effect waves-light" type="submit">Create team</button>
|
<button class="btn waves-effect waves-light" type="submit">Create team</button>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
}
|
}
|
||||||
function hideIneligible() {
|
function hideIneligible() {
|
||||||
$(".teamrow.ineligible").removeClass("visible");
|
$(".teamrow.ineligible").removeClass("visible");
|
||||||
|
$("#toggle").html("Show ineligible teams");
|
||||||
recalcRanks();
|
recalcRanks();
|
||||||
}
|
}
|
||||||
function showIneligible() {
|
function showIneligible() {
|
||||||
$(".teamrow.ineligible").addClass("visible");
|
$(".teamrow.ineligible").addClass("visible");
|
||||||
|
$("#toggle").html("Hide ineligible teams");
|
||||||
recalcRanks();
|
recalcRanks();
|
||||||
}
|
}
|
||||||
function toggleIneligible() {
|
function toggleIneligible() {
|
||||||
|
@ -36,15 +38,35 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Scoreboard</h2>
|
<h2>Scoreboard</h2>
|
||||||
<a href="javascript:toggleIneligible()">Toggle ineligible team display</a>
|
<div id="chart"></div>
|
||||||
|
<a href="javascript:toggleIneligible()" id="toggle">Hide ineligible teams</a>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Rank</th><th>Team</th><th>Affiliation</th><th>Score</th></tr>
|
<tr><th>Rank</th><th>Team</th><th>Affiliation</th><th>Score</th></tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for eligible, teamid, team, affiliation, score in data %}
|
{% for eligible, teamid, team, affiliation, score in data %}
|
||||||
<tr class="teamrow {% if not eligible %}in{% endif %}eligible {% if teamid == session.team_id %}blue lighten-3 {% endif %}visible"><td class="rank">{{ rank }}</td><td>{{ team }}</td><td>{{ affiliation }}</td><td>{{ score }}</td></tr>
|
<tr class="teamrow {% if not eligible %}in{% endif %}eligible {% if eligible and teamid == session.team_id %}blue lighten-3 {% endif %}visible"><td class="rank">{{ rank }}</td><td>{{ team }}</td><td>{{ affiliation }}</td><td>{{ score }}</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block postscript %}
|
||||||
|
<script>
|
||||||
|
var graphData = {{ graphdata | tojson }};
|
||||||
|
var groupn = 0;
|
||||||
|
var groups = new vis.DataSet();
|
||||||
|
var items = [];
|
||||||
|
graphData.forEach(function(team) {
|
||||||
|
var teamName = team[0];
|
||||||
|
var scoreEvents = team[1];
|
||||||
|
groups.add({ id: groupn, content: teamName, options: { drawPoints: false, interpolation: false } });
|
||||||
|
scoreEvents.forEach(function(evt) {
|
||||||
|
items.push({ x: evt[0], y: evt[1], group: groupn });
|
||||||
|
});
|
||||||
|
groupn++;
|
||||||
|
});
|
||||||
|
var dataset = new vis.DataSet(items);
|
||||||
|
var graph = new vis.Graph2d(document.getElementById('chart'), dataset, groups, {legend: true, dataAxis: {left: {range: {min: 0}}}});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
26
utils.py
26
utils.py
|
@ -1,6 +1,7 @@
|
||||||
import random
|
import random
|
||||||
import config
|
import config
|
||||||
import json
|
import json
|
||||||
|
from datetime import datetime
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask import request, session, redirect, url_for, flash, g
|
from flask import request, session, redirect, url_for, flash, g
|
||||||
from database import Team, Challenge, ChallengeSolve, ScoreAdjustment
|
from database import Team, Challenge, ChallengeSolve, ScoreAdjustment
|
||||||
|
@ -37,17 +38,38 @@ def competition_running_required(f):
|
||||||
def calculate_scores():
|
def calculate_scores():
|
||||||
solves = ChallengeSolve.select(ChallengeSolve, Challenge).join(Challenge)
|
solves = ChallengeSolve.select(ChallengeSolve, Challenge).join(Challenge)
|
||||||
adjustments = ScoreAdjustment.select()
|
adjustments = ScoreAdjustment.select()
|
||||||
teams = Team.select(Team.id, Team, ChallengeSolve).join(ChallengeSolve)
|
teams = Team.select()
|
||||||
|
|
||||||
|
team_solves = {team.id: [] for team in teams}
|
||||||
team_mapping = {team.id: team for team in teams}
|
team_mapping = {team.id: team for team in teams}
|
||||||
scores = {team.id: 0 for team in teams}
|
scores = {team.id: 0 for team in teams}
|
||||||
most_recent_solve = {team.id: max([i.time for i in team.solves]) for team in teams}
|
|
||||||
for solve in solves:
|
for solve in solves:
|
||||||
scores[solve.team_id] += solve.challenge.points
|
scores[solve.team_id] += solve.challenge.points
|
||||||
|
team_solves[solve.team_id].append(solve)
|
||||||
for adjustment in adjustments:
|
for adjustment in adjustments:
|
||||||
scores[adjustment.team_id] += adjustment.value
|
scores[adjustment.team_id] += adjustment.value
|
||||||
|
|
||||||
|
most_recent_solve = {tid: max([i.time for i in team_solves[tid]]) for tid in team_solves if team_solves[tid]}
|
||||||
|
scores = {i: j for i, j in scores.items() if i in most_recent_solve}
|
||||||
return [(team_mapping[i[0]].eligible, i[0], team_mapping[i[0]].name, team_mapping[i[0]].affiliation, i[1]) for idx, i in enumerate(sorted(scores.items(), key=lambda k: (-k[1], most_recent_solve[k[0]])))]
|
return [(team_mapping[i[0]].eligible, i[0], team_mapping[i[0]].name, team_mapping[i[0]].affiliation, i[1]) for idx, i in enumerate(sorted(scores.items(), key=lambda k: (-k[1], most_recent_solve[k[0]])))]
|
||||||
|
|
||||||
|
def calculate_graph(scoredata):
|
||||||
|
solves = list(ChallengeSolve.select(ChallengeSolve, Challenge).join(Challenge))
|
||||||
|
adjustments = list(ScoreAdjustment.select())
|
||||||
|
scoredata = [i for i in scoredata if i[0]] # Only eligible teams are on the score graph
|
||||||
|
graph_data = []
|
||||||
|
for eligible, tid, name, affiliation, score in scoredata[:config.teams_on_graph]:
|
||||||
|
our_solves = [i for i in solves if i.team_id == tid]
|
||||||
|
team_data = []
|
||||||
|
s = sum([i.value for i in adjustments if i.team_id == tid])
|
||||||
|
for i in sorted(our_solves, key=lambda k: k.time):
|
||||||
|
team_data.append((str(i.time), s))
|
||||||
|
s += i.challenge.points
|
||||||
|
team_data.append((str(i.time), s))
|
||||||
|
team_data.append((str(datetime.now()), score))
|
||||||
|
graph_data.append((name, team_data))
|
||||||
|
return graph_data
|
||||||
|
|
||||||
def get_complex(key):
|
def get_complex(key):
|
||||||
i = g.redis.get(key)
|
i = g.redis.get(key)
|
||||||
if i is None:
|
if i is None:
|
||||||
|
|
Loading…
Reference in New Issue