added html email and made site deployment ready | security fixes still needed

This commit is contained in:
2026-01-09 03:33:15 +01:00
parent 8a3857a093
commit 10fd6e63bf
6 changed files with 183 additions and 10 deletions

View File

@@ -8,14 +8,13 @@ class Config:
'sqlite:///' + os.path.join(basedir, '../instance/registration.db') 'sqlite:///' + os.path.join(basedir, '../instance/registration.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
# Email Settings (Update these!) MAIL_SERVER = 'mail.your-server.de'
MAIL_SERVER = MAIL_PORT = 587
MAIL_PORT =
MAIL_USE_TLS = True MAIL_USE_TLS = True
MAIL_USERNAME = os.environ.get('EMAIL_USER') MAIL_USERNAME = os.environ.get('EMAIL_USER')
MAIL_PASSWORD = os.environ.get('EMAIL_PASS') MAIL_PASSWORD = os.environ.get('EMAIL_PASS')
MAIL_DEFAULT_SENDER = os.environ.get('EMAIL_USER') MAIL_DEFAULT_SENDER = os.environ.get('EMAIL_USER')
MAX_SPOTS = MAX_SPOTS = 84
TUM_DOMAIN = "tum.de" TUM_DOMAIN = "tum.de"
DISCORD_LINK = DISCORD_LINK = os.environ.get('DISCORD_LINK')

View File

@@ -13,10 +13,11 @@ def send_verification_email(user_email):
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)
#msg = Message('Verify your CTF Registration', recipients=["fdohq9ipugtc@mockmail.io"]) msg = Message('Verify your CTF Registration', recipients=[user_email])
#msg.body = f'Click here to confirm your spot: {link}\nThanks for registering {user_email}' msg.html = render_template("email.html", user_email=user_email, link=link, logo_url=logo)
print(link) mail.send(msg)
@bp.route('/', methods=['GET', 'POST']) @bp.route('/', methods=['GET', 'POST'])
def index(): def index():

BIN
app/static/h4tum_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

81
app/static/timeline.css Normal file
View File

@@ -0,0 +1,81 @@
.timeline-container {
position: relative;
padding: 0 20px;
}
/* The actual horizontal line */
.line {
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 4px;
background: #dfe6e9;
transform: translateY(-50%);
z-index: 1;
}
.items-wrapper {
display: flex;
justify-content: space-between;
position: relative;
z-index: 2;
}
.item {
width: 120px;
text-align: center;
position: relative;
/* This height ensures the time is above and label is below the line */
height: 120px;
}
/* The Dot - centered perfectly on the line */
.dot {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* Centers the dot exactly */
width: 16px;
height: 16px;
background: #00ff00;
border: 2px solid #1a1a1a;
border-radius: 50%;
box-shadow: 0 0 8px #00ff00;
}
/* Time - positioned above the dot */
.time {
position: absolute;
bottom: 65%; /* Push above the center line */
left: 0;
right: 0;
font-weight: bold;
color: #ffffff;
}
/* Label - positioned below the dot */
.label {
position: absolute;
top: 65%; /* Push below the center line */
left: 0;
right: 0;
font-size: 0.9rem;
color: #ffffff;
}
.label span {
display: block;
font-size: 0.75rem;
color: #dddddd;
margin-top: 4px;
}
/* Mobile: Stack vertically */
@media (max-width: 700px) {
.line { display: none; }
.items-wrapper { flex-direction: column; gap: 10px; align-items: flex-start; }
.item { height: auto; text-align: center; width: 100%; }
.dot { display: none;}
.time, .label { position: static; }
}

53
app/templates/email.html Normal file
View File

@@ -0,0 +1,53 @@
<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_email }}</strong><br><br>
To secure your spot at the event, please confirm your attendance by clicking the button below.
</td>
</tr>
<tr>
<td align="center" style="padding-bottom: 30px;">
<table border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td align="center" bgcolor="#00ff00" style="padding: 15px 25px;">
<a href="{{ link }}" target="_blank" style="font-size: 18px; font-weight: bold; color: #000000; text-decoration: none; display: inline-block;">
CONFIRM MY SPOT
</a>
</td>
</tr>
</table>
</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>

View File

@@ -1,7 +1,9 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<div class="container">
<link rel="stylesheet" href="{{ url_for('static', filename='timeline.css') }}">
<div class="container">
<h1>> Info</h1> <h1>> Info</h1>
<ul> <ul>
<li>Date: 23.01.2026</li> <li>Date: 23.01.2026</li>
@@ -23,7 +25,44 @@
<li>Teams will be finalized on site at the competition</li> <li>Teams will be finalized on site at the competition</li>
</ul> </ul>
<hr style="border-color: #333; margin: 30px 0;"></hr> <hr style="border-color: #333; margin: 30px 0;"></hr>
<a href="{{ url_for('main.rules') }}">Rules and further information</a> <h1>> Timeline</h1>
<div class="timeline-container">
<div class="line"></div>
<div class="items-wrapper">
<div class="item">
<div class="time">12:00</div>
<div class="dot"></div>
<div class="label">Entry<span>Setup & find team</span></div>
</div>
<div class="item">
<div class="time">13:00</div>
<div class="dot"></div>
<div class="label">Start of Event</div>
</div>
<div class="item">
<div class="time">~18:30</div>
<div class="dot"></div>
<div class="label">Pizza Time<span>Bring cash. <a href="https://lapergola.igetnow.com/menu" target="_blank">Menu</a></span></div>
</div>
<div class="item">
<div class="time">21:00</div>
<div class="dot"></div>
<div class="label">End of Event</div>
</div>
<div class="item">
<div class="time">21:15</div>
<div class="dot"></div>
<div class="label">Awards</div>
</div>
</div>
</div>
<hr style="border-color: #333; margin: 30px 0;"></hr>
<a href="{{ url_for('main.rules') }}" style="text-align: center;"><h3>Rules and Code of Conduct</h3></a>
</div> </div>
<div class="container"> <div class="container">