Skip to content

Commit

Permalink
fix get_belts() and remove obsolete code
Browse files Browse the repository at this point in the history
  • Loading branch information
zardus committed Jan 13, 2024
1 parent 2db10ec commit c37872d
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 100 deletions.
36 changes: 12 additions & 24 deletions dojo_plugin/api/v1/belts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from CTFd.cache import cache
from CTFd.models import db, Users, Solves

from ...utils import belt_challenges
from ...models import Dojos
from ...utils.dojo import BELT_REQUIREMENTS


belts_namespace = Namespace("belts", description="Endpoint to manage belts")
Expand All @@ -17,33 +18,20 @@ def get_belts():
"users": {},
}

for color, challenges in belt_challenges().items():
for n,(color,dojo_id) in enumerate(BELT_REQUIREMENTS.items()):
result["dates"][color] = {}

belted_users = (
db.session.query(Users.id, Users.name, db.func.max(Solves.date))
.join(Solves, Users.id == Solves.user_id)
.filter(Solves.challenge_id.in_(challenges.subquery()))
.group_by(Users.id)
.having(db.func.count() == challenges.count())
.order_by(db.func.max(Solves.date))
)

for user_id, handle, date in belted_users:
result["dates"][color][user_id] = str(date)
result["users"][user_id] = {
"handle": handle,
dojo = Dojos.query.filter_by(id=dojo_id).first()

for user,date in dojo.completions():
if result["users"].get(user.id, {"rank_id":-1})["rank_id"] != n-1:
continue
result["dates"][color][user.id] = str(date)
result["users"][user.id] = {
"handle": user.name,
"color": color,
"rank_id": n,
}

# TODO: support belt deadlines
for user_id, belt in list(result["users"].items()):
if belt["color"] == "yellow":
received = datetime.datetime.fromisoformat(result["dates"]["yellow"][user_id])
if received > datetime.datetime.fromisoformat("2022-10-01"):
del result["users"][user_id]
del result["dates"]["yellow"][user_id]

return result


Expand Down
2 changes: 1 addition & 1 deletion dojo_plugin/api/v1/scoreboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from sqlalchemy.orm.session import Session

from ...models import Dojos, DojoChallenges, DojoUsers, DojoMembers, DojoAdmins, DojoStudents, DojoModules, DojoChallengeVisibilities
from ...utils import dojo_standings, dojo_completions, user_dojos, first_bloods, daily_solve_counts
from ...utils import dojo_standings, user_dojos, first_bloods, daily_solve_counts
from ...utils.dojo import dojo_route, dojo_accessible
from .belts import get_belts

Expand Down
9 changes: 7 additions & 2 deletions dojo_plugin/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,16 @@ def viewable(cls, id=None, user=None):
def solves(self, **kwargs):
return DojoChallenges.solves(dojo=self, **kwargs)

def completers(self):
def completions(self):
"""
Returns a list of (User, completion_timestamp) tuples for users, sorted by time in ascending order.
"""
sq = Solves.query.join(DojoChallenges, Solves.challenge_id == DojoChallenges.challenge_id).add_columns(
Solves.user_id.label("solve_user_id"), db.func.count().label("solve_count"), db.func.max(Solves.date).label("last_solve")
).filter(DojoChallenges.dojo == self).group_by(Solves.user_id).subquery()
return Users.query.join(sq).filter_by(solve_count=len(self.challenges)).order_by(sq.columns.last_solve).all()
return Users.query.join(sq).filter_by(
solve_count=len(self.challenges)
).add_column(sq.columns.last_solve).order_by(sq.columns.last_solve).all()

def completed(self, user):
return self.solves(user=user, ignore_visibility=True, ignore_admins=False).count() == len(self.challenges)
Expand Down
69 changes: 0 additions & 69 deletions dojo_plugin/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,35 +238,6 @@ def load_dojo(dojo_id, dojo_spec, user=None, dojo_dir=None, commit=True, log=log
db.session.rollback()


def dojo_completions():
all_solves = (
db.session.query(DojoChallenges.dojo_id.label("dojo_id"))
.join(Solves, DojoChallenges.challenge_id == Solves.challenge_id)
.add_columns(
db.func.count(Solves.id).label("solves"),
Solves.user_id,
db.func.max(Solves.date).label("last_solve"),
db.func.min(Solves.date).label("first_solve"),
)
.group_by(Solves.user_id, DojoChallenges.dojo_id)
.order_by("last_solve")
).all()
all_challenges = (
db.session.query(Dojos.id.label("dojo_id"))
.join(DojoChallenges, DojoChallenges.dojo_id == Dojos.id)
.add_columns(db.func.count(DojoChallenges.challenge_id).label("challenges"))
.group_by(Dojos.id)
).all()

chal_counts = { d.dojo_id: d.challenges for d in all_challenges }
completions = { }
for s in all_solves:
if s.solves == chal_counts[s.dojo_id]:
completions.setdefault(s.user_id, []).append({
"dojo": s.dojo_id, "last_solve": s.last_solve, "first_solve": s.first_solve
})
return completions

def first_bloods():
first_blood_string = db.func.min(Solves.date.cast(String)+"|"+Solves.user_id.cast(String))
first_blood_query = (
Expand Down Expand Up @@ -295,46 +266,6 @@ def daily_solve_counts():
).all()
return counts


def belt_challenges():
# TODO: move this concept into dojo yml

yellow_categories = [
"embryoio",
"babysuid",
"embryoasm",
"babyshell",
"babyjail",
"embryogdb",
"babyrev",
"babymem",
"toddlerone",
]

blue_categories = [
*yellow_categories,
"babyrop",
"babyheap",
"babyrace",
"babykernel",
"toddlertwo",
]

color_categories = {
"yellow": yellow_categories,
"blue": blue_categories,
}

return {
color: db.session.query(Challenges.id).filter(
Challenges.state == "visible",
Challenges.value > 0,
Challenges.id < 1000,
Challenges.category.in_(categories),
)
for color, categories in color_categories.items()
}

# based on https://stackoverflow.com/questions/36408496/python-logging-handler-to-append-to-list
class ListHandler(logging.Handler): # Inherit from logging.Handler
def __init__(self, log_list):
Expand Down
8 changes: 4 additions & 4 deletions dojo_plugin/utils/dojo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,10 @@ def get_current_dojo_challenge(user=None):
)

BELT_REQUIREMENTS = {
"orange": ["intro-to-cybersecurity"],
"yellow": ["program-security"],
"green": ["system-security"],
"blue": ["software-exploitation"],
"orange": "intro-to-cybersecurity",
"yellow": "program-security",
"green": "system-security",
"blue": "software-exploitation",
}

def get_user_belts(user):
Expand Down

0 comments on commit c37872d

Please sign in to comment.