From 462f8a688bcccec7e610b00ca348d761df455d48 Mon Sep 17 00:00:00 2001 From: cato447 Date: Mon, 12 Jan 2026 14:01:18 +0100 Subject: [PATCH] finished dev version --- app/models.py | 2 + app/routes.py | 61 +++++++++++++++++++++---------- app/static/style.css | 4 ++ app/templates/email.html | 2 +- app/templates/index.html | 41 +++++++++++---------- app/templates/rules.html | 1 + app/templates/waitlist_email.html | 39 ++++++++++++++++++++ run.py | 2 +- 8 files changed, 111 insertions(+), 41 deletions(-) create mode 100644 app/templates/waitlist_email.html diff --git a/app/models.py b/app/models.py index 0f5db21..82d5869 100644 --- a/app/models.py +++ b/app/models.py @@ -5,8 +5,10 @@ class Participant(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) + num_emails_sent = db.Column(db.Integer, default=0) looking_for_team = db.Column(db.Boolean, default=False) confirmed = db.Column(db.Boolean, default=False) + on_waitlist = db.Column(db.Boolean, default=False) discord_token = db.Column(db.String(16), unique=True) discord_user_id = db.Column(db.String(50)) diff --git a/app/routes.py b/app/routes.py index b8184dc..acb6f17 100644 --- a/app/routes.py +++ b/app/routes.py @@ -9,14 +9,31 @@ bp = Blueprint('main', __name__) def get_confirmed_count(): return Participant.query.filter_by(confirmed=True).count() -def send_verification_email(user_email): +def add_user(name, email, looking_for_team, on_waitlist = False): + new_user = Participant(name=name, email=email, looking_for_team=looking_for_team) + if on_waitlist: + new_user.on_waitlist = on_waitlist + db.session.add(new_user) + db.session.commit() + return new_user + +def send_verification_email(user): s = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) - token = s.dumps(user_email, salt='email-confirm-h4tum-ctf-2025') + token = s.dumps(user.email, salt='email-confirm-h4tum-ctf-2025') link = url_for('main.verify_email', token=token, _external=True) logo = url_for('static', filename='h4tum_white.png', _external=True) - msg = Message('Verify your CTF Registration', recipients=[user_email]) - msg.html = render_template("email.html", user_email=user_email, link=link, logo_url=logo) + msg = Message('Verify your CTF Registration', recipients=[user.email]) + msg.html = render_template("email.html", user_name=user.name, link=link, logo_url=logo) + mail.send(msg) + user.num_emails_sent += 1 + db.session.commit() + return True + +def send_waitlist_email(user): + msg = Message('h4tum CTF 2026 Registration', recipients=[user.email]) + logo = url_for('static', filename='h4tum_white.png', _external=True) + msg.html = render_template("waitlist_email.html", logo_url=logo, user_name=user.name) mail.send(msg) @bp.route('/', methods=['GET', 'POST']) @@ -34,29 +51,35 @@ def index(): if not email.endswith(f"@{tum_domain}"): flash(f"Error: You must use a @{tum_domain} email address.", "error") return redirect(url_for('main.index')) - - if confirmed_count >= max_spots: - flash("Sorry, the event is full!", "error") - return redirect(url_for('main.index')) existing_user = Participant.query.filter_by(email=email).first() + if existing_user: if existing_user.confirmed: flash("You are already registered and confirmed!", "info") + elif existing_user.on_waitlist: + flash("You are already on the waitlist", "info") else: - flash("Confirmation email resent. Please check your inbox.", "info") - send_verification_email(email) + if existing_user.num_emails_sent < 5: + flash("Confirmation email resent. Please check your inbox.", "info") + send_verification_email(existing_user) + else: + flash("Email limit reached", "error") + return redirect(url_for('main.index')) + else: + new_user = add_user(name, email, looking_for_team) + + if confirmed_count < max_spots: + send_verification_email(new_user) + flash("Registration started! Check your email to confirm your spot.", "success") + else: + new_user.on_waitlist = True + db.session.commit() + send_waitlist_email(new_user) + flash("The event is already full!\nYou have been placed on the waitlist", "info") return redirect(url_for('main.index')) - new_user = Participant(name=name, email=email, looking_for_team=looking_for_team) - db.session.add(new_user) - db.session.commit() - - send_verification_email(email) - flash("Registration started! Check your email to confirm your spot.", "success") - return redirect(url_for('main.index')) - - return render_template('index.html', spots_left=spots_left) + return render_template('index.html', spots_left=spots_left, max_spots=max_spots) @bp.route('/verify/') def verify_email(token): diff --git a/app/static/style.css b/app/static/style.css index 725d935..0cdc4cb 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -45,6 +45,10 @@ footer { margin: 0; } +.status { + text-align: center; +} + h1 { font-size: 1.5rem; word-wrap: break-word; } diff --git a/app/templates/email.html b/app/templates/email.html index bce7d06..546cdcd 100644 --- a/app/templates/email.html +++ b/app/templates/email.html @@ -20,7 +20,7 @@ Thanks for registering
- {{ user_email }}

+ {{ user_name }}

To secure your spot at the event, please confirm your attendance by clicking the button below. diff --git a/app/templates/index.html b/app/templates/index.html index a9c16a3..1e6fbf8 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -13,9 +13,9 @@

> Prizes


> Format

@@ -76,26 +76,27 @@ {% endwith %}
-

Spots Remaining: {{ spots_left }} / 84

+ {% if spots_left > 0 %} +

Spots Remaining: {{ spots_left }} / {{max_spots}}

+ {% else %} +

Register for Waitlist

+

This event is currently full. Join the queue to be notified of openings.

+ {%endif %}
- {% if spots_left > 0 %} -
- - + + + - - + + - + - -
- {% else %} -

EVENT FULL

- {% endif %} - + + + {% endblock %} diff --git a/app/templates/rules.html b/app/templates/rules.html index 35aced5..dd4fdea 100644 --- a/app/templates/rules.html +++ b/app/templates/rules.html @@ -15,6 +15,7 @@
  • If something feels unintentionally easy, please report it.
  • Do not share flags or solutions with other teams. We will not tolerate flag sharing.
  • Each team may register only once, and each person may belong to only one team.
  • +
  • A team has at maximum four members
  • Only TUM Students are permitted to participate in the CTF.
  • Attacking personnel, including participants and non-participants, or the competition system itself is forbidden.
  • Every participant has to follow the Code of Conduct.
  • diff --git a/app/templates/waitlist_email.html b/app/templates/waitlist_email.html new file mode 100644 index 0000000..2f2b665 --- /dev/null +++ b/app/templates/waitlist_email.html @@ -0,0 +1,39 @@ + + + + + + +
    + + + + + + + + + + + + + + + + + + +
    + Club Logo +
    +

    Registration Received

    +
    + Thanks for registering
    + {{ user_name }}

    + At this time, the event has reached maximum capacity. Your name has been placed on a waiting list; we will contact you in the event of any cancellations. +
    + If you didn't request this, you can safely ignore this email. +
    +
    + + diff --git a/run.py b/run.py index bce0a8c..3dc5f39 100644 --- a/run.py +++ b/run.py @@ -3,4 +3,4 @@ from app import create_app app = create_app() if __name__ == '__main__': - app.run(debug=True, host='0.0.0.0') + app.run()