Skip to content
This repository has been archived by the owner on Mar 7, 2023. It is now read-only.

Commit

Permalink
Add filtering by image per the demands of the crowd
Browse files Browse the repository at this point in the history
  • Loading branch information
sourque committed Jul 17, 2020
1 parent 19ea598 commit f1acee4
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 63 deletions.
66 changes: 48 additions & 18 deletions engine/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@ def get_time_elapsed():
- start_time.replace(microsecond=0)
return(time_elapsed)

def calc_elapsed_time(time1, time2):
start_time = datetime.strptime(time1, "%Y-%m-%d %H:%M:%S")
end_time = datetime.strptime(time2, "%Y-%m-%d %H:%M:%S")
time_elapsed = end_time.replace(microsecond=0) \
- start_time.replace(microsecond=0)
return time_delta_convert(time_elapsed)

def time_delta_convert(time_input):
days = time_input.days
seconds = time_input.seconds
hours = int(seconds / 3600)
seconds -= hours * 3600
minutes = int(seconds / 60)
seconds -= minutes * 60

if days > 0:
hours += (days * 24)

if hours <= 9:
hours = "0" + str(hours)
if minutes <= 9:
minutes = "0" + str(minutes)
if seconds <= 9:
seconds = "0" + str(seconds)

hours = str(hours)
minutes = str(minutes)
seconds = str(seconds)
return hours + ":" + minutes + ":" + seconds

def get_time_left():
try:
duration = read_running_config()["settings"]["duration"]
Expand Down Expand Up @@ -169,18 +199,24 @@ def get_css_csv(remote, ips):
http_csv = str.encode("")
teams = get_css_teams(remote)
images = get_css_images(remote)
team_times = get_css_all_elapsed_time()
team_scores = []
#ugly_results = execute("select team, image, points from css_results GROUP BY team, image ORDER BY team DESC")
for index, team in enumerate(teams):
team_sum = 0
for image in images:
try:
# TODO: dont make a SQL call for each image, just make one and parse in python
image_sum = execute("SELECT `points` FROM `css_results` WHERE team=? AND image=? ORDER BY time DESC", (team, image), one=True)[0]
if team in ips:
ip = ips[team]
else:
ip = "N/A"
http_csv += str.encode(find_email(index, remote) + "," + find_alias(index, remote) + "," + team + "," + image + "," + str(image_sum) + "," + ip + "," + get_css_play_time(team, image=image) + "," + get_css_elapsed_time(team) + "\n")
try:
team_time = team_times[team]
except:
team_time = "00:00:00"
http_csv += str.encode(find_email(index, remote) + "," + find_alias(index, remote) + "," + team + "," + image + "," + str(image_sum) + "," + ip + "," + get_css_play_time(team, image=image) + "," + team_time + "\n")
except:
# Ignoring images that a team hasn't started yet
pass
Expand All @@ -206,12 +242,16 @@ def get_css_images(remote):
images.append(image[0])
return images

def get_css_scores(remote):
def get_css_scores(remote, image=None):
team_scores = []
try:
# Returns most recent image scores for each team
# with optional image filter
# [(time, team, image, points), ...]
team_data = execute("SELECT DISTINCT max(time) as time, team, image, points FROM css_results GROUP BY team, image")
if image:
team_data = execute("SELECT DISTINCT max(time) as time, team, image, points FROM css_results WHERE image=? GROUP BY team, image", (image,))
else:
team_data = execute("SELECT DISTINCT max(time) as time, team, image, points FROM css_results GROUP BY team, image")
except:
return team_scores

Expand Down Expand Up @@ -303,11 +343,7 @@ def get_css_score(team, remote):
def get_css_elapsed_time(team):
try:
time_records = execute("SELECT `time` FROM `css_results` WHERE team=? ORDER BY time ASC", (team,))
start_time = datetime.strptime(time_records[0][0], "%Y-%m-%d %H:%M:%S")
end_time = datetime.strptime(time_records[-1][0], "%Y-%m-%d %H:%M:%S")
time_elapsed = end_time.replace(microsecond=0) \
- start_time.replace(microsecond=0)
return str(time_elapsed)
return calc_elapsed_time(time_records[0][0], time_records[-1][0])
except:
return "0:00:00"

Expand All @@ -318,31 +354,25 @@ def get_css_all_elapsed_time():
all_times.sort(key=lambda tup: tup[0]) # Sort by time
all_times.sort(key=lambda tup: tup[1]) # Sort by team

time_string = "%Y-%m-%d %H:%M:%S"
current_team = all_times[0][1]
first_time = all_times[0][0]
last_time = first_time

for time_item in all_times:
if current_team != time_item[1]: # If new team
# Calculate previous team's elapsed time
first_time = datetime.strptime(first_time, time_string)
last_time = datetime.strptime(last_time, time_string)
team_times[current_team] = str(last_time.replace(microsecond=0) - first_time.replace(microsecond=0))
team_times[current_team] = calc_elapsed_time(first_time, last_time)

# Assign new accurate current_team value
current_team = time_item[1]
first_time = time_item[0]
last_time = time_item[0]

# Catch the last team
start_time = datetime.strptime(first_time, time_string)
end_time = datetime.strptime(last_time, time_string)
team_times[current_team] = str(end_time.replace(microsecond=0) - start_time.replace(microsecond=0))
team_times[current_team] = calc_elapsed_time(first_time, last_time)

return team_times


def get_css_play_time(team, image=None):
try:
if not image:
Expand All @@ -359,9 +389,9 @@ def get_css_play_time(team, image=None):
- time1.replace(microsecond=0)
if time_diff < time_threshold:
play_time += time_diff
return str(play_time)
return time_delta_convert(play_time)
except:
return "0:00:00"
return "00:00:00"

def insert_css_score(team, image, points, vulns):
execute("INSERT INTO `css_results` ('team', 'image', 'points', 'vulns') VALUES (?, ?, ?, ?)", (team, image, points, vulns))
Expand Down
28 changes: 21 additions & 7 deletions engine/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ def css():
if not team in teams:
team = db.remove_alias(team, em.remote)
if team in teams:

if team not in team_data or (team in team_data and (datetime.now() - team_data[team]["refresh_time"]) > refresh_threshold):
print("[INFO] Refreshing data for team", team)
labels, image_data, scores = db.get_css_score(team, em.remote)
Expand Down Expand Up @@ -245,15 +244,29 @@ def css():
else:
print("[ERROR] Invalid team specified:", request.args["team"])

# If filter by image:
images = db.get_css_images(em.remote)
image = None
if "image" in request.args:
image = request.args["image"]
if image not in images:
print("[ERROR] Invalid image specified:", image)
image = None
else:
print("[INFO] Fetching CSS scoreboard for image", image)
team_scores = db.get_css_scores(em.remote, image=image)

# Main scoreboard view
time_since_refresh = datetime.now() - scoreboard_time_refresh
if time_since_refresh > refresh_threshold:
print("[INFO] Refreshing CSS scoreboard...")
team_scores = db.get_css_scores(em.remote)
scoreboard_time_refresh = datetime.now()
if not image:
time_since_refresh = datetime.now() - scoreboard_time_refresh
if time_since_refresh > refresh_threshold:
print("[INFO] Refreshing CSS scoreboard...")
team_scores = db.get_css_scores(em.remote)
scoreboard_time_refresh = datetime.now()
if "team_aliases" in em.remote:
team_scores = db.apply_aliases(team_scores, em.remote)
return render_template("scores_css.html", team_scores=team_scores, event=event, css_mode=css_mode)

return render_template("scores_css.html", team_scores=team_scores, event=event, css_mode=css_mode, images=images, image=image)

@app.route('/scores/css/update', methods=['POST'])
def css_update():
Expand Down Expand Up @@ -377,6 +390,7 @@ def css_status():
return("OK")

@app.route('/scores/css/export')
@admin_required
def css_csv():
em.load()
csv_buffer = BytesIO()
Expand Down
1 change: 1 addition & 0 deletions engine/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="/static/js/feather.min.js"></script>
<script src="/static/js/bootstrap-4.0.0.min.js"></script>
<script src="/static/js/scripts.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
{% block head %}
{% endblock%}
</head>
Expand Down
143 changes: 105 additions & 38 deletions engine/templates/scores_css.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
{% if css_mode %}
{% extends 'css_base.html' %}
{% extends 'css_base.html' %}
{% else %}
{% extends 'base.html' %}
{% extends 'base.html' %}
{% endif %}

{% block content %}

{% if css_mode %}
<style>
<style>

.table td {
margin: 0;
padding: 0;
}

.table td a {
display: block;
padding: 16px;
text-decoration: none;
}

.btn-group a {
display: block;
text-decoration: none;
}

{% if css_mode %}
body {
background-color: #212529;
}
Expand All @@ -31,9 +48,7 @@
td {
cursor: pointer;
}
</style>
{% else %}
<style>
{% else %}
h2, h4, h6 {
text-align: center;
}
Expand All @@ -45,40 +60,92 @@
td {
cursor: pointer;
}
</style>
{% endif %}
<br/>

<h2>Leaderboard</h2>
{% if current_user.is_admin %}
<h6><a href="/scores/css/export"><i>Export CSV</i></a></h6>
{% endif %}
{% if event %}
<h4><i>{{ event }}</i></h4>
{% endif %}<br>
{% if css_mode %}
<table class="table table-borderless table-dark table-hover">
</style>

<h2>Leaderboard</h2>
<br>
{% if current_user.is_admin %}
<h6><a href="/scores/css/export"><i>Export CSV</i></a></h6>
{% endif %}
{% if event %}
<h4><i>{{ event }}</i></h4>
{% endif %}
<div style="display: flex; justify-content: center; align-items: baseline;">
{% if image %}
<p style="color: white; margin-right: 1rem;">
Only showing <b>{{ image }}!</b>
</p>
{% else %}
<table class="table table-bordered table-hover">
<p style="color: white; margin-right: 1rem;">
Filter by image:
</p>
{% endif %}
<thead class="thead-dark">
<th>Team</th>
<th>Scored Images</th>
<th>Elapsed Time</th>
<th>Current Score</th>
</thead>
<tbody>
{% for team in team_scores %}
<tr>
<td class='clickable' data-href='/scores/css?team={{ team[0] }}'>{{ team[0] }}</td>
<td class='clickable' data-href='/scores/css?team={{ team[0] }}'>{{ team[1] }}</td>
<td class='clickable' data-href='/scores/css?team={{ team[0] }}'>{{ team[2] }}</td>
<td class='clickable' data-href='/scores/css?team={{ team[0] }}'>{{ team[3] }}</td>
</tr>

{% endfor %}
</tbody>
</table>
<div class="btn-group btn-group-sm" role="group" aria-label="Basic example">
{% for image_item in images %}
<button type="button" class="btn btn-dark">
<a href="/scores/css?image={{ image_item }}">
{{ image_item }}
</a>
</button>
&nbsp;
{% endfor %}
{% if image %}
<button type="button" class="btn btn-dark">
<a href="/scores/css">
All
</a>
</button>
{% endif %}
</div>
</div>
<br>
{% if css_mode %}
<table class="table table-borderless table-dark table-hover">
{% else %}
<table class="table table-bordered table-hover">
{% endif %}
<thead class="thead-dark">
<th>Team</th>
<th>Scored Image(s)</th>
<th>Elapsed Time</th>
<th>Current Score</th>
</thead>
<tbody>
{% for team in team_scores %}
<tr>
<td>
<a href="/scores/css?team={{ team[0] }}">
{{ team[0] }}
</a>
</td>
{% if not image %}
<td>
<a href="/scores/css?team={{ team[0] }}">
{{ team[1] }}
</a>
</td>
{% else %}
<td>
<a href="/scores/css?team={{ team[0] }}">
{{ image }}
</a>
</td>
{% endif %}
<td>
<a href="/scores/css?team={{ team[0] }}">
{{ team[2] }}
</a>
</td>
<td>
<a href="/scores/css?team={{ team[0] }}">
{{ team[3] }}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>

<br/><br/>

Expand Down
3 changes: 3 additions & 0 deletions engine/templates/scores_css_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ <h2>{{ team_name }}</h2><br>

<!-- Graph of scores over time -->
<br><br><h4>Scores Over Time</h4><br>
<noscript>
<p style="color: white; text-align: center">The score graph uses Chart.js, and thus doesn't function without JavaScript.</p>
</noscript>
<canvas id="scoresOverTime" height="100%"></canvas>

<script>
Expand Down

0 comments on commit f1acee4

Please sign in to comment.