Skip to content

Commit

Permalink
Speedup scoreboard
Browse files Browse the repository at this point in the history
  • Loading branch information
ConnorNelson committed Oct 6, 2023
1 parent 2463522 commit 46fadc0
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 46 deletions.
24 changes: 21 additions & 3 deletions dojo_plugin/api/v1/scoreboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

from ...models import DojoChallenges
from ...utils import dojo_standings, dojo_completions, user_dojos, first_bloods, daily_solve_counts
from ...utils.dojo import dojo_route, dojo_accessible, dojo_scoreboard_data
from ...utils.dojo import dojo_route, dojo_accessible
from .belts import get_belts


Expand Down Expand Up @@ -42,8 +42,25 @@ def belt_asset(color):
return url_for("views.themes", path=f"img/dojo/{belt}")


def get_scoreboard_page(dojo, module=None, duration=None, page=1, per_page=20):
query = dojo_scoreboard_data(dojo, module, duration=duration, fields=[Users.name, Users.email])
def get_scoreboard_page(model, duration=None, page=1, per_page=20):
duration_filter = (
Solves.date >= datetime.datetime.utcnow() - datetime.timedelta(days=duration)
if duration else True
)
solves = db.func.count().label("solves")
rank = (
db.func.row_number()
.over(order_by=(solves.desc(), db.func.max(Solves.id)))
.label("rank")
)
query = (
model.solves()
.join(Users, Users.id == Solves.user_id)
.filter(duration_filter)
.group_by(Solves.user_id)
.order_by(rank)
.with_entities(rank, solves, Solves.user_id, Users.name, Users.email)
)
pagination = query.paginate(page=page, per_page=per_page)

def standing(item):
Expand All @@ -64,6 +81,7 @@ def standing(item):

user = get_current_user()
if user:
# TODO PERF: This makes the entire function ~2x slower.
me = standing(db.session.query(query.subquery()).filter_by(user_id=user.id).first())
if me:
pages.add((me["rank"] - 1) // per_page + 1)
Expand Down
23 changes: 8 additions & 15 deletions dojo_plugin/pages/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,24 @@

from ..models import Dojos, DojoModules, DojoChallenges
from ..utils import DATA_DIR
from ..utils.dojo import dojo_scoreboard_data


users = Blueprint("pwncollege_users", __name__)


def hacker_rank(user, dojo, module=None):
return (
dojo_scoreboard_data(dojo, module, fields=[])
.filter(Users.id == user.id)
.first()
)


def view_hacker(user):
current_user_dojos = set(Dojos.viewable(user=get_current_user()))
dojos = [dojo for dojo in Dojos.viewable(user=user) if dojo in current_user_dojos]

def competitors(dojo, module=None, user=None):
query = dojo_scoreboard_data(dojo, module)
if user:
return db.session.query(query.subquery()).filter_by(user_id=user.id).first()
return query
def ranking(model, user):
solves = db.func.count().label("solves")
rank = db.func.row_number().over(order_by=(solves.desc(), db.func.max(Solves.id))).label("rank")
rankings = model.solves().group_by(Solves.user_id).with_entities(rank, Solves.user_id).all()
user_rank = next((ranking.rank for ranking in rankings if ranking.user_id == user.id), None)
max_rank = len(rankings)
return user_rank, max_rank

return render_template("hacker.html", dojos=dojos, user=user, competitors=competitors)
return render_template("hacker.html", dojos=dojos, user=user, ranking=ranking)

@users.route("/hacker/<int:user_id>")
def view_other(user_id):
Expand Down
22 changes: 0 additions & 22 deletions dojo_plugin/utils/dojo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,25 +388,3 @@ def get_current_dojo_challenge(user=None):
DojoChallenges.dojo == Dojos.from_id(container.labels.get("dojo.dojo_id")).first())
.first()
)


def dojo_scoreboard_data(dojo, module=None, duration=None, fields=None):
fields = fields or []

duration_filter = (
Solves.date >= datetime.datetime.utcnow() - datetime.timedelta(days=duration)
if duration else True
)
order_by = (db.func.count().desc(), db.func.max(Solves.id))
result = (
DojoChallenges.solves(dojo=dojo, module=module)
.filter(DojoChallenges.visible(Solves.date), duration_filter)
.group_by(Solves.user_id)
.order_by(*order_by)
.join(Users, Users.id == Solves.user_id)
.with_entities(db.func.row_number().over(order_by=order_by).label("rank"),
db.func.count().label("solves"),
Solves.user_id,
*fields)
)
return result
10 changes: 4 additions & 6 deletions dojo_theme/templates/hacker.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,15 @@ <h3 class="d-block">

<div class="container">
{% for dojo in dojos if dojo.solves(user=user, ignore_visibility=True).count() > 0 %}
{% set competitor = competitors(dojo, user=user) %}
{% set competitor_count = competitors(dojo).count() %}
{% set rank, max_rank = ranking(dojo, user) %}
{% set solves = dojo.solves(user=user, ignore_visibility=True).all() | map(attribute="challenge_id") | list %}
<a class="text-decoration-none" href="{{ url_for('pwncollege_dojo.listing', dojo=dojo.reference_id) }}">
<h2>{{ dojo.name }}</h2>
<h4>
<i class="fas fa-flag pt-3 pr-3" title="Solves"></i>
<td>{{ solves | length }} / {{ dojo.challenges | length }}</td>
<i class="fas fa-trophy pt-3 pr-3 pl-5 " title="Rank"></i>
<td>{{ competitor.rank or "-" }} / {{ competitor_count }}</td>
<td>{{ rank or "-" }} / {{ max_rank or "-" }}</td>
</h4>
</a>

Expand All @@ -58,16 +57,15 @@ <h4>
<div class="accordion" id="{{dojo.reference_id}}-modules">
{% for module in dojo.modules %}
{% set solves = dojo.solves(user=user, module=module, ignore_visibility=True).all() | map(attribute="challenge_id") | list %}
{% set competitor = competitors(dojo, module, user=user) %}
{% set competitor_count = competitors(dojo, module).count() %}
{% set rank, max_rank = ranking(module, user) %}
{% call(header) accordion_item("{}-modules".format(dojo.reference_id), loop.index) %}
{% if header %}
<h4 class="accordion-item-name">{{ module.name }}</h4>
<span class="total-solves">
<i class="fas fa-flag pr-1" title="Solves"></i>
<td>{{ solves | length }} / {{ module.challenges | length }}</td>
<i class="fas fa-trophy pr-1 pl-3 " title="Rank"></i>
<td>{{ competitor.rank or "-" }} / {{ competitor_count }}</td>
<td>{{ rank or "-" }} / {{ max_rank or "-" }}</td>
</span>
{% else %}
{% for challenge in module.challenges %}
Expand Down

0 comments on commit 46fadc0

Please sign in to comment.