team info validations fixes #9 plus admin impersonate and toggle

eligibility lock
master
Fox Wilson 2015-11-30 23:37:45 -05:00
parent a36184f9dc
commit d4dd155ed6
6 changed files with 72 additions and 14 deletions

38
app.py
View File

@ -86,10 +86,22 @@ def register():
flash(message) flash(message)
return render_template("register.html") return render_template("register.html")
team_name = request.form["team_name"] team_name = request.form["team_name"].strip()
team_email = request.form["team_email"] team_email = request.form["team_email"].strip()
team_elig = "team_eligibility" in request.form team_elig = "team_eligibility" in request.form
affiliation = request.form["affiliation"] affiliation = request.form["affiliation"].strip()
if len(team_name) > 50 or not team_name:
flash("You must have a team name!")
return render_template("register.html")
if not (team_email and "." in team_email and "@" in team_email):
flash("You must have a valid team email!")
return render_template("register.html")
if not affiliation:
affiliation = "No affiliation"
team_key = misc.generate_team_key() team_key = misc.generate_team_key()
confirmation_key = misc.generate_confirmation_key() confirmation_key = misc.generate_confirmation_key()
@ -141,12 +153,22 @@ def dashboard():
flash("You're changing your information too fast!") flash("You're changing your information too fast!")
return redirect(url_for('dashboard')) return redirect(url_for('dashboard'))
g.redis.set("ul{}".format(session["team_id"]), str(datetime.now()), 120) team_name = request.form["team_name"].strip()
team_name = request.form["team_name"] team_email = request.form["team_email"].strip()
team_email = request.form["team_email"] affiliation = request.form["affiliation"].strip()
affiliation = request.form["affiliation"]
team_elig = "team_eligibility" in request.form team_elig = "team_eligibility" in request.form
if len(team_name) > 50 or not team_name:
flash("You must have a team name!")
return render_template("dashboard.html")
if not (team_email and "." in team_email and "@" in team_email):
flash("You must have a valid team email!")
return render_template("dashboard.html")
if not affiliation:
affiliation = "No affiliation"
email_changed = (team_email != g.team.email) email_changed = (team_email != g.team.email)
g.team.name = team_name g.team.name = team_name
@ -155,6 +177,8 @@ def dashboard():
if not g.team.eligibility_locked: if not g.team.eligibility_locked:
g.team.eligible = team_elig g.team.eligible = team_elig
g.redis.set("ul{}".format(session["team_id"]), str(datetime.now()), 120)
if email_changed: if email_changed:
g.team.email_confirmation_key = misc.generate_confirmation_key() g.team.email_confirmation_key = misc.generate_confirmation_key()
g.team.email_confirmed = False g.team.email_confirmed = False

View File

@ -3,7 +3,7 @@ from database import AdminUser, Team, Challenge, ChallengeSolve, ChallengeFailur
import utils import utils
import utils.admin import utils.admin
import utils.scoreboard import utils.scoreboard
from utils.decorators import admin_required from utils.decorators import admin_required, csrf_check
from utils.notification import make_link from utils.notification import make_link
from datetime import datetime from datetime import datetime
admin = Blueprint("admin", "admin", url_prefix="/admin") admin = Blueprint("admin", "admin", url_prefix="/admin")
@ -87,6 +87,23 @@ def admin_show_team(tid):
team = Team.get(Team.id == tid) team = Team.get(Team.id == tid)
return render_template("admin/team.html", team=team) return render_template("admin/team.html", team=team)
@admin.route("/team/<int:tid>/<csrf>/impersonate/")
@csrf_check
@admin_required
def admin_impersonate_team(tid):
session["team_id"] = tid
return redirect(url_for("scoreboard"))
@admin.route("/team/<int:tid>/<csrf>/toggle_eligibility_lock/")
@csrf_check
@admin_required
def admin_toggle_eligibility_lock(tid):
team = Team.get(Team.id == tid)
team.eligibility_locked = not team.eligibility_locked
team.save()
flash("Eligibility lock set to {}".format(team.eligibility_locked))
return redirect(url_for(".admin_show_team", tid=tid))
@admin.route("/logout/") @admin.route("/logout/")
def admin_logout(): def admin_logout():
del session["admin"] del session["admin"]

View File

@ -1,11 +1,12 @@
{% extends "admin/base.html" %} {% extends "admin/base.html" %}
{% block content %} {% block content %}
<h2>{{ team.name }}</h2> <h2>{{ team.name }}</h2>
<p>This team is <strong>{{ "eligible" if team.eligible else "not eligible" }}</strong>.</p> <a href="{{ url_for('admin.admin_impersonate_team', tid=team.id, csrf=csrf_token()) }}">Impersonate team</a><br />
<p>This team is <strong>{{ "eligible" if team.eligible else "not eligible" }}</strong>. Eligibility is <strong>{{ "locked" if team.eligibility_locked else "unlocked" }}</strong> (<a href="{{ url_for('admin.admin_toggle_eligibility_lock', tid=team.id, csrf=csrf_token()) }}">toggle</a>).</p>
<p>This team's affiliation is <strong>{{ team.affiliation }}</strong></p> <p>This team's affiliation is <strong>{{ team.affiliation }}</strong></p>
<h3>Email</h3> <h3>Email</h3>
<p>This team's email is <strong>{{ team.email }} ({{ "confirmed" if team.email_confirmed else "unconfirmed" }})</strong>.</p> <p>This team's email is <strong>{{ team.email }} ({{ "confirmed" if team.email_confirmed else "unconfirmed" }})</strong>.</p>
{% if not team.email_confirmed or 1 %} {% if not team.email_confirmed %}
<p>This team's confirmation key is <code>{{ team.email_confirmation_key }}</code>. <p>This team's confirmation key is <code>{{ team.email_confirmation_key }}</code>.
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -75,7 +75,7 @@
<form method="POST"> <form method="POST">
<div class="input-field"> <div class="input-field">
<label for="team-name">Team Name</label> <label for="team-name">Team Name</label>
<input required id="team-name" name="team_name" type="text" value="{{ team.name }}" /> <input required maxlength="50" id="team-name" name="team_name" type="text" value="{{ team.name }}" />
</div> </div>
<div class="input-field"> <div class="input-field">
<label for="team-email">Team Email</label> <label for="team-email">Team Email</label>

View File

@ -11,7 +11,7 @@ contain a "team key", which is used to log in.</p>
team members.</strong></p> team members.</strong></p>
<form method="POST"> <form method="POST">
<div class="input-field"> <div class="input-field">
<input required id="team-name" name="team_name" type="text" /> <input required maxlength="50" id="team-name" name="team_name" type="text" />
<label for="team-name">Team Name</label> <label for="team-name">Team Name</label>
</div> </div>
<div class="input-field"> <div class="input-field">
@ -19,7 +19,7 @@ team members.</strong></p>
<label for="team-email">Team Email</label> <label for="team-email">Team Email</label>
</div> </div>
<div class="input-field"> <div class="input-field">
<input required id="affiliation" name="affiliation" type="text" /> <input id="affiliation" name="affiliation" type="text" />
<label for="affiliation">Affiliation</label> <label for="affiliation">Affiliation</label>
</div> </div>
<p>{{ config.eligibility }}</p> <p>{{ config.eligibility }}</p>

View File

@ -1,5 +1,5 @@
import config import config
from flask import session, redirect, url_for, flash, g from flask import session, redirect, url_for, flash, g, abort
from functools import wraps from functools import wraps
def login_required(f): def login_required(f):
@ -40,3 +40,19 @@ def admin_required(f):
return redirect(url_for("admin.admin_login")) return redirect(url_for("admin.admin_login"))
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated return decorated
def csrf_check(f):
@wraps(f)
def decorated(*args, **kwargs):
if "csrf" not in kwargs:
abort(403)
return
if kwargs["csrf"] != session["_csrf_token"]:
abort(403)
return
del kwargs["csrf"]
return f(*args, **kwargs)
return decorated