finished dev version
This commit is contained in:
@@ -5,8 +5,10 @@ class Participant(db.Model):
|
|||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String(100), nullable=False)
|
name = db.Column(db.String(100), nullable=False)
|
||||||
email = db.Column(db.String(120), unique=True, 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)
|
looking_for_team = db.Column(db.Boolean, default=False)
|
||||||
confirmed = 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_token = db.Column(db.String(16), unique=True)
|
||||||
discord_user_id = db.Column(db.String(50))
|
discord_user_id = db.Column(db.String(50))
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,31 @@ bp = Blueprint('main', __name__)
|
|||||||
def get_confirmed_count():
|
def get_confirmed_count():
|
||||||
return Participant.query.filter_by(confirmed=True).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'])
|
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)
|
link = url_for('main.verify_email', token=token, _external=True)
|
||||||
logo = url_for('static', filename='h4tum_white.png', _external=True)
|
logo = url_for('static', filename='h4tum_white.png', _external=True)
|
||||||
|
|
||||||
msg = Message('Verify your CTF Registration', recipients=[user_email])
|
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.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)
|
mail.send(msg)
|
||||||
|
|
||||||
@bp.route('/', methods=['GET', 'POST'])
|
@bp.route('/', methods=['GET', 'POST'])
|
||||||
@@ -35,28 +52,34 @@ def index():
|
|||||||
flash(f"Error: You must use a @{tum_domain} email address.", "error")
|
flash(f"Error: You must use a @{tum_domain} email address.", "error")
|
||||||
return redirect(url_for('main.index'))
|
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()
|
existing_user = Participant.query.filter_by(email=email).first()
|
||||||
|
|
||||||
if existing_user:
|
if existing_user:
|
||||||
if existing_user.confirmed:
|
if existing_user.confirmed:
|
||||||
flash("You are already registered and confirmed!", "info")
|
flash("You are already registered and confirmed!", "info")
|
||||||
|
elif existing_user.on_waitlist:
|
||||||
|
flash("You are already on the waitlist", "info")
|
||||||
else:
|
else:
|
||||||
flash("Confirmation email resent. Please check your inbox.", "info")
|
if existing_user.num_emails_sent < 5:
|
||||||
send_verification_email(email)
|
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'))
|
return redirect(url_for('main.index'))
|
||||||
|
|
||||||
new_user = Participant(name=name, email=email, looking_for_team=looking_for_team)
|
return render_template('index.html', spots_left=spots_left, max_spots=max_spots)
|
||||||
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)
|
|
||||||
|
|
||||||
@bp.route('/verify/<token>')
|
@bp.route('/verify/<token>')
|
||||||
def verify_email(token):
|
def verify_email(token):
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ footer {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
h1 { font-size: 1.5rem; word-wrap: break-word; }
|
h1 { font-size: 1.5rem; word-wrap: break-word; }
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td align="center" style="padding-bottom: 30px; font-size: 16px; line-height: 1.5; text-align: center;">
|
<td align="center" style="padding-bottom: 30px; font-size: 16px; line-height: 1.5; text-align: center;">
|
||||||
Thanks for registering <br>
|
Thanks for registering <br>
|
||||||
<strong style="color: #00ff00;">{{ user_email }}</strong><br><br>
|
<strong style="color: #00ff00;">{{ user_name }}</strong><br><br>
|
||||||
To secure your spot at the event, please confirm your attendance by clicking the button below.
|
To secure your spot at the event, please confirm your attendance by clicking the button below.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -13,9 +13,9 @@
|
|||||||
<hr style="border-color: #333; margin: 30px 0;"></hr>
|
<hr style="border-color: #333; margin: 30px 0;"></hr>
|
||||||
<h1>> Prizes</h1>
|
<h1>> Prizes</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<li>1st Place: 100€</li>
|
<li>1st Place: 150€</li>
|
||||||
<li>2nd Place: 75€</li>
|
<li>2nd Place: 110€</li>
|
||||||
<li>3rd Place: 50€</li>
|
<li>3rd Place: 75€</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr style="border-color: #333; margin: 30px 0;"></hr>
|
<hr style="border-color: #333; margin: 30px 0;"></hr>
|
||||||
<h1>> Format</h1>
|
<h1>> Format</h1>
|
||||||
@@ -76,26 +76,27 @@
|
|||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<h2>Spots Remaining: {{ spots_left }} / 84</h2>
|
{% if spots_left > 0 %}
|
||||||
|
<h2>Spots Remaining: {{ spots_left }} / {{max_spots}}</h2>
|
||||||
|
{% else %}
|
||||||
|
<h2>Register for Waitlist</h2>
|
||||||
|
<p>This event is currently full. Join the queue to be notified of openings.</p>
|
||||||
|
{%endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if spots_left > 0 %}
|
<form method="POST">
|
||||||
<form method="POST">
|
<label>Name</label>
|
||||||
<label>Name</label>
|
<input type="text" name="name" required>
|
||||||
<input type="text" name="name" required>
|
|
||||||
|
|
||||||
<label>TUM Email</label>
|
<label>TUM Email</label>
|
||||||
<input type="email" name="email" placeholder="@tum.de" required>
|
<input type="email" name="email" placeholder="@tum.de" required>
|
||||||
|
|
||||||
<label style="display:block; margin: 20px 0; line-height: 1.4;">
|
<label style="display:block; margin: 20px 0; line-height: 1.4;">
|
||||||
<input type="checkbox" name="looking_for_team" style="transform: scale(1.2); margin-right: 10px;">
|
<input type="checkbox" name="looking_for_team" style="transform: scale(1.2); margin-right: 10px;">
|
||||||
I need a team / looking for group
|
I need a team / looking for group
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button type="submit">INITIALIZE_REGISTRATION</button>
|
<button type="submit">INITIALIZE_REGISTRATION</button>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
</div>
|
||||||
<h2 style="color:red">EVENT FULL</h2>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<li>If something feels unintentionally easy, please report it.</li>
|
<li>If something feels unintentionally easy, please report it.</li>
|
||||||
<li>Do not share flags or solutions with other teams. We will not tolerate flag sharing.</li>
|
<li>Do not share flags or solutions with other teams. We will not tolerate flag sharing.</li>
|
||||||
<li>Each team may register only once, and each person may belong to only one team.</li>
|
<li>Each team may register only once, and each person may belong to only one team.</li>
|
||||||
|
<li>A team has at maximum four members</li>
|
||||||
<li>Only TUM Students are permitted to participate in the CTF.</li>
|
<li>Only TUM Students are permitted to participate in the CTF.</li>
|
||||||
<li>Attacking personnel, including participants and non-participants, or the competition system itself is forbidden.</li>
|
<li>Attacking personnel, including participants and non-participants, or the competition system itself is forbidden.</li>
|
||||||
<li>Every participant has to follow the Code of Conduct.</li>
|
<li>Every participant has to follow the Code of Conduct.</li>
|
||||||
|
|||||||
39
app/templates/waitlist_email.html
Normal file
39
app/templates/waitlist_email.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<html>
|
||||||
|
<body style="margin: 0; padding: 0; background-color: #1a1a1a; font-family: 'Courier New', Courier, monospace; color: #ffffff;">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="background-color: #1a1a1a; padding: 20px;">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table width="100%" border="0" cellspacing="0" cellpadding="0" style="max-width: 600px; background-color: #222222; border: 1px solid #00ff00; padding: 30px;">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding-bottom: 20px;">
|
||||||
|
<img src="{{ logo_url }}" alt="Club Logo" width="150" style="display: block; border: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding-bottom: 20px;">
|
||||||
|
<h1 style="color: #00ff00; font-size: 24px; margin: 0; text-transform: uppercase; text-align: center;">Registration Received</h1>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding-bottom: 30px; font-size: 16px; line-height: 1.5; text-align: center;">
|
||||||
|
Thanks for registering <br>
|
||||||
|
<strong style="color: #00ff00;">{{ user_name }}</strong><br><br>
|
||||||
|
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.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding-top: 20px; border-top: 1px solid #333333; font-size: 12px; color: #888888; text-align: center;">
|
||||||
|
If you didn't request this, you can safely ignore this email.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user