Files
CTFd/CTFd/admin/challenges.py
Kevin Chung 1725e632cf 3.0.0a2 dev (#1528)
# 3.0.0a2 / 2020-07-09

**General**

* Accept additional profile fields during registration (affiliation, website, country)
  * This does not add additional inputs. Themes or additional JavaScript can add the form inputs.

**Admin Panel**

* Redesign the challenge creation form to use a radio button with challenge type selection instead of a select input

**API**

* Admins can no longer ban themselves through `PATCH /api/v1/users/[user_id]`

**Themes**

* Spinner centering has been switched from a hard coded margin in CSS to flexbox CSS classes from Bootstrap

**Plugins**

* Revert plugin menu (`register_admin_plugin_menu_bar`, `register_user_page_menu_bar`) changes to 2.x code

**Miscellaneous**

* Fix issue with `Configs.ctf_name` returning incorrect value
* Add prerender step back into challenges.js
* Better handling of missing challenge types. Missing challenge types no longer bring down all other challenges.
2020-07-09 13:40:35 -04:00

79 lines
2.2 KiB
Python

from flask import abort, render_template, request, url_for
from CTFd.admin import admin
from CTFd.models import Challenges, Flags, Solves
from CTFd.plugins.challenges import CHALLENGE_CLASSES, get_chal_class
from CTFd.utils.decorators import admins_only
@admin.route("/admin/challenges")
@admins_only
def challenges_listing():
q = request.args.get("q")
field = request.args.get("field")
filters = []
if q:
# The field exists as an exposed column
if Challenges.__mapper__.has_property(field):
filters.append(getattr(Challenges, field).like("%{}%".format(q)))
query = Challenges.query.filter(*filters).order_by(Challenges.id.asc())
challenges = query.all()
total = query.count()
return render_template(
"admin/challenges/challenges.html",
challenges=challenges,
total=total,
q=q,
field=field,
)
@admin.route("/admin/challenges/<int:challenge_id>")
@admins_only
def challenges_detail(challenge_id):
challenges = dict(
Challenges.query.with_entities(Challenges.id, Challenges.name).all()
)
challenge = Challenges.query.filter_by(id=challenge_id).first_or_404()
solves = (
Solves.query.filter_by(challenge_id=challenge.id)
.order_by(Solves.date.asc())
.all()
)
flags = Flags.query.filter_by(challenge_id=challenge.id).all()
try:
challenge_class = get_chal_class(challenge.type)
except KeyError:
abort(
500,
f"The underlying challenge type ({challenge.type}) is not installed. This challenge can not be loaded.",
)
update_j2 = render_template(
challenge_class.templates["update"].lstrip("/"), challenge=challenge
)
update_script = url_for(
"views.static_html", route=challenge_class.scripts["update"].lstrip("/")
)
return render_template(
"admin/challenges/challenge.html",
update_template=update_j2,
update_script=update_script,
challenge=challenge,
challenges=challenges,
solves=solves,
flags=flags,
)
@admin.route("/admin/challenges/new")
@admins_only
def challenges_new():
types = CHALLENGE_CLASSES.keys()
return render_template("admin/challenges/new.html", types=types)