a3546b4c01
- Move all credentials from hardcoded to .env with python-dotenv (add .env.example template and .gitignore) - Add CSRF token generation and validation on all state-changing requests - Replace random.choices with secrets.choice for all secure code generation - Add session cookie security headers (HttpOnly, Secure, SameSite) - Add presenter management: assign/remove presenters to breakout sessions, presenter QR scanning - Add email communications system: templates per event, custom email sending, sent email tracking - Add staff/organizer profile pages with staff code display - New DB tables: event_email_templates, sent_emails, user_communications - New DB columns: staff.reminder_count/reminder_dates, breakout_session_organizers.presenter_code - Expand English translation strings across all new features Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
103 lines
5.9 KiB
HTML
103 lines
5.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="{{ session.locale if session.locale else 'en' }}">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="description" content="NetEvents - Professional networking event platform for organizers, attendees, and staff. Manage events, breakout sessions, QR check-ins, and attendee connections.">
|
|
<meta name="csrf-token" content="{{ session.csrf_token if session.csrf_token else '' }}">
|
|
<title>{% block title %}NetEvents{% endblock %}</title>
|
|
<link rel="icon" href="{{ url_for('static', filename='favicon.svg') }}">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
|
</head>
|
|
<body>
|
|
<nav class="navbar sticky-navbar">
|
|
<div class="container navbar-container">
|
|
<a href="{{ url_for('index') }}" class="logo">
|
|
<img src="{{ url_for('static', filename='img/logo.svg') }}" alt="NetEvents" width="150" height="40" class="logo-icon">
|
|
</a>
|
|
<button class="hamburger" aria-label="Toggle navigation" aria-expanded="false">
|
|
<i data-lucide="menu" class="hamburger-icon"></i>
|
|
<i data-lucide="x" class="hamburger-close-icon d-none"></i>
|
|
</button>
|
|
<ul class="nav-links">
|
|
{% if session.user_id %}
|
|
{% if session.user_type == 'organizer' %}
|
|
<li><a href="{{ url_for('organizer_dashboard') }}"><i data-lucide="layout-dashboard"></i><span>{{ 'dashboard'|t }}</span></a></li>
|
|
<li><a href="{{ url_for('create_event') }}"><i data-lucide="plus-circle"></i><span>{{ 'create_event'|t }}</span></a></li>
|
|
{% elif session.user_type == 'staff' %}
|
|
<li><a href="{{ url_for('staff_dashboard') }}"><i data-lucide="layout-dashboard"></i><span>{{ 'dashboard'|t }}</span></a></li>
|
|
{% elif session.user_type == 'breakout_organizer' %}
|
|
<li><a href="{{ url_for('presenter_dashboard') }}"><i data-lucide="layout-dashboard"></i><span>{{ 'dashboard'|t }}</span></a></li>
|
|
{% else %}
|
|
<li><a href="{{ url_for('attendee_dashboard') }}"><i data-lucide="layout-dashboard"></i><span>{{ 'dashboard'|t }}</span></a></li>
|
|
<li><a href="{{ url_for('list_attendees') }}"><i data-lucide="search"></i><span>{{ 'attendees'|t }}</span></a></li>
|
|
<li><a href="{{ url_for('attendee_profile') }}"><i data-lucide="user"></i><span>{{ 'profile'|t }}</span></a></li>
|
|
{% endif %}
|
|
<li><a href="{{ url_for('logout') }}"><i data-lucide="log-out"></i><span>{{ 'logout'|t }}</span></a></li>
|
|
{% else %}
|
|
<li><a href="{{ url_for('index') }}"><i data-lucide="home"></i><span>{{ 'home'|t }}</span></a></li>
|
|
<li><a href="{{ url_for('login') }}"><i data-lucide="log-in"></i><span>{{ 'login'|t }}</span></a></li>
|
|
{% endif %}
|
|
</ul>
|
|
{% if session.user_id and session.user_name %}
|
|
<a href="{% if session.user_type == 'attendee' %}{{ url_for('attendee_profile') }}{% elif session.user_type == 'organizer' or session.user_type == 'breakout_organizer' %}{{ url_for('organizer_profile') }}{% elif session.user_type == 'staff' %}{{ url_for('staff_profile') }}{% else %}#{% endif %}" class="nav-user">
|
|
<i data-lucide="circle-user" class="nav-user-icon"></i>
|
|
<span class="nav-user-name">{{ session.user_name }}</span>
|
|
<span class="nav-user-type">{{ session.user_type }}</span>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Toast Notification Container -->
|
|
<div id="toast-container" class="toast-container"></div>
|
|
|
|
<!-- Confirmation Modal -->
|
|
<div id="confirm-modal" class="modal-overlay" style="display:none">
|
|
<div class="modal-content modal-sm">
|
|
<h3 id="confirm-title">Confirm</h3>
|
|
<p id="confirm-message"></p>
|
|
<div class="modal-actions">
|
|
<button id="confirm-cancel" class="btn btn-secondary">{{ 'cancel'|t }}</button>
|
|
<button id="confirm-ok" class="btn btn-danger">{{ 'confirm'|t }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<main>
|
|
<div class="container">
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="footer">
|
|
<div class="container">
|
|
<p>© 2026 NetEvents - Networking Event Platform</p>
|
|
<p class="footer-love">
|
|
Made and hosted with
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="cheese-heart" aria-label="love">
|
|
<!-- Cheese heart -->
|
|
<path d="M12 21C12 21 3 14 3 8.5C3 5.5 5.5 3 8.5 3C10.5 3 12 4.5 12 6C12 4.5 13.5 3 15.5 3C18.5 3 21 5.5 21 8.5C21 14 12 21 12 21Z" fill="#f0c040"/>
|
|
<!-- Cheese holes -->
|
|
<circle cx="9" cy="8" r="1.5" fill="#d4a020"/>
|
|
<circle cx="14" cy="7" r="1" fill="#d4a020"/>
|
|
<circle cx="11" cy="12" r="1.2" fill="#d4a020"/>
|
|
<circle cx="15" cy="11" r="0.8" fill="#d4a020"/>
|
|
</svg>
|
|
in the heart of The Netherlands
|
|
</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
// Initialize Lucide icons
|
|
lucide.createIcons();
|
|
</script>
|
|
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
|
{% block extra_styles %}{% endblock %}
|
|
</body>
|
|
</html> |