Files
conference/templates/attendee/connection_requests.html
T
paul a3546b4c01 Security hardening: env-based config, CSRF protection, secure code generation, plus presenter management and email communications system
- 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>
2026-05-26 20:34:48 +00:00

81 lines
3.3 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ 'connection_requests'|t }} - NetEvents{% endblock %}
{% block content %}
<div class="connection-requests">
<h1>{{ 'connection_requests'|t }}</h1>
<p>{{ 'people_scanned_qr'|t }}</p>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-info">
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% if requests %}
<div class="requests-list">
{% for req in requests %}
<div class="request-card">
<div class="request-profile">
{% if req.profile_picture %}
<img src="{{ url_for('uploaded_file', filename=req.profile_picture) }}" alt="{{ req.first_name }}" class="profile-photo">
{% else %}
<div class="profile-photo-placeholder"><span class="first-name">{{ req.first_name[0] }}</span><span class="last-name">{{ req.last_name[0] }}</span></div>
{% endif %}
</div>
<div class="request-info">
<h3><span class="first-name">{{ req.first_name }}</span> <span class="last-name">{{ req.last_name }}</span></h3>
<p class="request-email">{{ req.email }}</p>
<p class="request-org">{{ req.organisation if req.organisation else '' }}{% if req.role %} - {{ req.role }}{% endif %}</p>
{% if req.introduction %}
<p class="request-intro">"{{ req.introduction }}"</p>
{% endif %}
<p class="request-time">{{ 'requested'|t }} {{ req.created_at|localized_date if req.created_at else 'recently' }}</p>
</div>
<div class="request-actions">
<button class="btn btn-success btn-sm respond-btn" data-connection-id="{{ req.id }}" data-action="approve">{{ 'approve'|t }}</button>
<button class="btn btn-danger btn-sm respond-btn" data-connection-id="{{ req.id }}" data-action="reject">{{ 'reject'|t }}</button>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="no-requests">{{ 'no_pending_requests'|t }}</p>
{% endif %}
<div class="back-link">
<a href="{{ url_for('attendee_dashboard') }}" class="btn btn-outline">{{ 'back_to_dashboard'|t }}</a>
</div>
</div>
<script>
document.querySelectorAll('.respond-btn').forEach(btn => {
btn.addEventListener('click', async function() {
const connectionId = this.dataset.connectionId;
const action = this.dataset.action;
try {
const response = await fetch(`/attendee/connection-request/${connectionId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: action })
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
showToast(data.error || 'Error processing request', 'error');
}
} catch (error) {
showToast('Error processing request', 'error');
}
});
});
</script>
{% endblock %}