348 lines
25 KiB
HTML
348 lines
25 KiB
HTML
{% extends "layout.html" %}
|
|
{% block content %}
|
|
<section class="administrator-section">
|
|
{% if setup_required %}
|
|
<div class="content-card">
|
|
<h2 class="section-title"><i data-lucide="settings"></i> Administrator Einrichtung</h2>
|
|
<form action="{{ url_for('handle_administrator') }}" method="POST" class="input-form">
|
|
<div class="form-group">
|
|
<label for="password_string" class="input-label">Neues Administrator-Passwort</label>
|
|
<input type="password" id="password_string" name="password_string" class="text-input" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="password_string_confirmation" class="input-label">Passwort wiederholen</label>
|
|
<input type="password" id="password_string_confirmation" name="password_string_confirmation" class="text-input" required>
|
|
</div>
|
|
<button type="submit" class="action-button primary-button"><i data-lucide="check"></i> Einrichtung abschließen</button>
|
|
</form>
|
|
</div>
|
|
{% elif login_required %}
|
|
<div class="content-card">
|
|
<h2 class="section-title"><i data-lucide="shield"></i> Administrator Anmeldung</h2>
|
|
<form action="{{ url_for('handle_administrator') }}" method="POST" class="input-form">
|
|
<div class="form-group">
|
|
<label for="password_string" class="input-label">Passwort</label>
|
|
<input type="password" id="password_string" name="password_string" class="text-input" required>
|
|
</div>
|
|
{% if two_factor_enabled %}
|
|
<div class="form-group">
|
|
<label for="two_factor_code" class="input-label">Zwei-Faktor Code</label>
|
|
<input type="text" id="two_factor_code" name="two_factor_code" class="text-input" required>
|
|
</div>
|
|
{% endif %}
|
|
<button type="submit" class="action-button primary-button"><i data-lucide="log-in"></i> Anmelden</button>
|
|
</form>
|
|
</div>
|
|
{% elif dashboard_active %}
|
|
<div class="tab-container">
|
|
<button class="tab-button active-tab" data-target="control-panel"><i data-lucide="sliders"></i> Steuerung</button>
|
|
<button class="tab-button" data-target="player-panel"><i data-lucide="users"></i> Spieler</button>
|
|
<button class="tab-button" data-target="kill-panel"><i data-lucide="message-square"></i> Meldungen</button>
|
|
</div>
|
|
|
|
<div id="control-panel" class="tab-content active-content">
|
|
<div class="content-card status-card">
|
|
<h3 class="card-title" style="display: flex; align-items: center; gap: var(--spacing-small);">
|
|
<i data-lucide="activity"></i> Spielstatus:
|
|
{% if game_status == 'pending' %}
|
|
<span class="status-pill warning-pill"><i data-lucide="clock"></i> Ausstehend</span>
|
|
{% elif game_status == 'running' %}
|
|
<span class="status-pill success-pill"><i data-lucide="play"></i> Läuft</span>
|
|
{% elif game_status == 'paused' %}
|
|
<span class="status-pill warning-pill"><i data-lucide="pause"></i> Pausiert</span>
|
|
{% elif game_status == 'finished' %}
|
|
<span class="status-pill danger-pill"><i data-lucide="square"></i> Beendet</span>
|
|
{% endif %}
|
|
</h3>
|
|
|
|
{% if game_status == 'pending' %}
|
|
{% if can_start %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="start_game">
|
|
<button type="submit" class="action-button success-button large-button"><i data-lucide="play"></i> Spiel starten</button>
|
|
</form>
|
|
{% else %}
|
|
<div class="content-card notice-card warning-card">
|
|
<p class="notice-text">Es werden mindestens zwei freigegebene Spieler benötigt, um das Spiel zu starten.</p>
|
|
</div>
|
|
{% endif %}
|
|
{% elif game_status == 'running' %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form" style="margin-bottom: var(--spacing-medium);">
|
|
<input type="hidden" name="action_type" value="pause_game">
|
|
<button type="submit" class="action-button warning-button large-button"><i data-lucide="pause"></i> Spiel pausieren</button>
|
|
</form>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="stop_game">
|
|
<button type="submit" class="action-button danger-button large-button"><i data-lucide="square"></i> Spiel beenden</button>
|
|
</form>
|
|
{% elif game_status == 'paused' %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form" style="margin-bottom: var(--spacing-medium);">
|
|
<input type="hidden" name="action_type" value="resume_game">
|
|
<button type="submit" class="action-button success-button large-button"><i data-lucide="play"></i> Spiel fortsetzen</button>
|
|
</form>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="stop_game">
|
|
<button type="submit" class="action-button danger-button large-button"><i data-lucide="square"></i> Spiel beenden</button>
|
|
</form>
|
|
{% elif game_status == 'finished' %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="reset_game">
|
|
<button type="submit" class="action-button danger-button large-button"><i data-lucide="rotate-ccw"></i> Spiel zurücksetzen</button>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="content-card settings-card">
|
|
<h3 class="card-title"><i data-lucide="shield-check"></i> Sicherheit</h3>
|
|
|
|
{% if two_factor_enabled %}
|
|
<div class="content-card notice-card success-card">
|
|
<p class="notice-text">Zwei-Faktor-Authentifizierung ist aktiv.</p>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="inline-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="disable_two_factor">
|
|
<button type="submit" class="action-button danger-button"><i data-lucide="shield-off"></i> Deaktivieren</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<div class="content-card notice-card warning-card">
|
|
<p class="notice-text">Zwei-Faktor-Authentifizierung ist inaktiv. Bitte scanne den QR-Code und bestätige zur Aktivierung.</p>
|
|
<p>Manuelle Eingabe: <strong>{{ two_factor_secret }}</strong></p>
|
|
<div class="qr-code-container">
|
|
{{ qr_code_svg | safe }}
|
|
</div>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="enable_two_factor">
|
|
<div class="form-group">
|
|
<label for="enable_two_factor_code" class="input-label">Bestätigungscode</label>
|
|
<input type="text" id="enable_two_factor_code" name="two_factor_code" class="text-input" required>
|
|
</div>
|
|
<button type="submit" class="action-button success-button"><i data-lucide="shield-alert"></i> Aktivieren</button>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form" style="margin-top: var(--spacing-large);">
|
|
<input type="hidden" name="action_type" value="update_credentials">
|
|
<div class="form-group">
|
|
<label for="new_password_string" class="input-label">Passwort ändern</label>
|
|
<input type="password" id="new_password_string" name="password_string" class="text-input" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="update_password_confirmation" class="input-label">Passwort wiederholen</label>
|
|
<input type="password" id="update_password_confirmation" name="password_string_confirmation" class="text-input" required>
|
|
</div>
|
|
<button type="submit" class="action-button primary-button"><i data-lucide="save"></i> Aktualisieren</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="player-panel" class="tab-content">
|
|
<div class="content-card">
|
|
<h3 class="card-title"><i data-lucide="user-plus"></i> Spieler manuell erstellen</h3>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="input-form admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="create_player">
|
|
<div class="form-group">
|
|
<label for="display_name" class="input-label">Anzeigename</label>
|
|
<input type="text" id="display_name" name="display_name" class="text-input" required>
|
|
</div>
|
|
<button type="submit" class="action-button primary-button"><i data-lucide="plus"></i> Spieler erstellen</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="content-card" style="overflow-x: auto;">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Kennung</th>
|
|
<th>Name & Änderung</th>
|
|
<th>Status</th>
|
|
<th>Ziel</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for current_player in all_players %}
|
|
<tr class="{% if not current_player.is_approved %}unregistered-row{% endif %}">
|
|
<td class="monospace-identifier">
|
|
{{ current_player.player_identifier }}
|
|
{% if not current_player.is_approved %}
|
|
<br><span class="status-pill warning-pill" style="margin-left: 0; margin-top: var(--spacing-small);">Wartet</span>
|
|
{% elif current_player.late_joiner %}
|
|
<br><span class="status-pill warning-pill" style="margin-left: 0; margin-top: var(--spacing-small);">Späteinstieg</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="edit_name">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<input type="text" name="new_display_name" value="{{ current_player.display_name }}" class="text-input small-input" required>
|
|
<button type="submit" class="action-button primary-button small-button"><i data-lucide="save"></i></button>
|
|
</form>
|
|
{% if current_player.pending_display_name %}
|
|
<div class="content-card notice-card warning-card" style="margin-top: var(--spacing-small); padding: var(--spacing-small); margin-bottom: 0;">
|
|
<p style="margin: 0 0 var(--spacing-small) 0; font-size: calc(0.875rem * var(--dimension-multiplier));">
|
|
Wünscht: <strong>{{ current_player.pending_display_name }}</strong>
|
|
</p>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-bottom: var(--spacing-small);">
|
|
<input type="hidden" name="action_type" value="approve_name_change">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button success-button small-button"><i data-lucide="check"></i></button>
|
|
</form>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="reject_name_change">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button danger-button small-button"><i data-lucide="x"></i></button>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if not current_player.is_approved %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="approve_player">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button success-button small-button"><i data-lucide="user-check"></i> Freigeben</button>
|
|
</form>
|
|
{% else %}
|
|
{% if current_player.is_alive %}
|
|
<span class="status-pill success-pill" style="margin-left: 0;"><i data-lucide="heart"></i> Lebend</span>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
|
|
<input type="hidden" name="action_type" value="eliminate_player">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button danger-button small-button"><i data-lucide="skull"></i> Töten</button>
|
|
</form>
|
|
{% else %}
|
|
<span class="status-pill danger-pill" style="margin-left: 0;"><i data-lucide="skull"></i> Tot</span>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
|
|
<input type="hidden" name="action_type" value="revive_player">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button success-button small-button"><i data-lucide="heart-pulse"></i> Beleben</button>
|
|
</form>
|
|
{% endif %}
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if current_player.target_identifier %}
|
|
{{ current_player.target_identifier }}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
|
|
<input type="hidden" name="action_type" value="change_target">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<select name="new_target_identifier" class="text-input small-input">
|
|
{% for possible_target in all_players %}
|
|
{% if possible_target.is_alive and possible_target.player_identifier != current_player.player_identifier %}
|
|
<option value="{{ possible_target.player_identifier }}" {% if current_player.target_identifier == possible_target.player_identifier %}selected{% endif %}>{{ possible_target.display_name }}</option>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</select>
|
|
<button type="submit" class="action-button secondary-button small-button"><i data-lucide="refresh-cw"></i></button>
|
|
</form>
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="generate_reset">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button secondary-button small-button"><i data-lucide="link"></i> Reset Link</button>
|
|
</form>
|
|
{% if current_player.reset_token %}
|
|
<input type="text" readonly value="{{ url_for('handle_password_reset', token=current_player.reset_token, _external=True) }}" class="text-input small-input" style="margin: var(--spacing-small) 0;">
|
|
{% endif %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
|
|
<input type="hidden" name="action_type" value="delete_player">
|
|
<input type="hidden" name="player_identifier" value="{{ current_player.player_identifier }}">
|
|
<button type="submit" class="action-button danger-button small-button"><i data-lucide="trash-2"></i></button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="kill-panel" class="tab-content">
|
|
<div class="content-card" style="overflow-x: auto;">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Zeitpunkt</th>
|
|
<th>Killer</th>
|
|
<th>Opfer</th>
|
|
<th>Status</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for report in kill_logs %}
|
|
<tr>
|
|
<td>{{ report.kill_timestamp[:16].replace('T', ' ') if report.kill_timestamp else '-' }}</td>
|
|
<td>{{ report.killer_name or 'Unbekannt' }} ({{ report.killer_identifier }})</td>
|
|
<td>{{ report.victim_name or 'Unbekannt' }} ({{ report.victim_identifier }})</td>
|
|
<td>
|
|
{% if report.report_status == 'confirmed' %}
|
|
<span class="status-pill success-pill" style="margin-left: 0;">Bestätigt</span>
|
|
{% elif report.report_status == 'pending' %}
|
|
<span class="status-pill warning-pill" style="margin-left: 0;">Ausstehend</span>
|
|
{% elif report.report_status == 'rejected' %}
|
|
<span class="status-pill danger-pill" style="margin-left: 0;">Abgelehnt</span>
|
|
{% elif report.report_status == 'revoked' %}
|
|
<span class="status-pill danger-pill" style="margin-left: 0;">Widerrufen</span>
|
|
{% else %}
|
|
{{ report.report_status }}
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if report.report_status == 'confirmed' %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="revoke_kill">
|
|
<input type="hidden" name="kill_identifier" value="{{ report.kill_identifier }}">
|
|
<button type="submit" class="action-button danger-button small-button"><i data-lucide="rotate-ccw"></i> Rückgängig</button>
|
|
</form>
|
|
{% endif %}
|
|
|
|
{% if report.report_status == 'pending' %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form">
|
|
<input type="hidden" name="action_type" value="force_confirm_report">
|
|
<input type="hidden" name="kill_identifier" value="{{ report.kill_identifier }}">
|
|
<button type="submit" class="action-button success-button small-button"><i data-lucide="check"></i> Bestätigen</button>
|
|
</form>
|
|
{% endif %}
|
|
|
|
{% if report.report_status in ['pending', 'rejected', 'revoked'] %}
|
|
<form action="{{ url_for('handle_administrator_action') }}" method="POST" class="flexible_form_container admin-asynchronous-form" style="margin-top: var(--spacing-small);">
|
|
<input type="hidden" name="action_type" value="delete_report">
|
|
<input type="hidden" name="kill_identifier" value="{{ report.kill_identifier }}">
|
|
<button type="submit" class="action-button secondary-button small-button"><i data-lucide="trash-2"></i> Löschen</button>
|
|
</form>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="5" style="text-align: center; opacity: 0.6;">Bisher keine Meldungen im System.</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="admin-confirmation-modal" class="modal-overlay">
|
|
<div class="modal-dialog">
|
|
<h2 class="modal-title"><i data-lucide="calendar-clock"></i> Aktion planen</h2>
|
|
<p class="modal-description">Führe die Aktion sofort aus oder plane sie für die Zukunft.</p>
|
|
<div class="form-group" style="margin-bottom: var(--spacing-large); text-align: left;">
|
|
<label for="modal_execution_time" class="input-label">Zeitpunkt (Optional)</label>
|
|
<input type="datetime-local" id="modal_execution_time" class="text-input time-input" style="width: 100%; box-sizing: border-box;">
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" id="confirm-admin-action" class="action-button success-button"><i data-lucide="check"></i> Bestätigen</button>
|
|
<button type="button" id="cancel-admin-action" class="action-button secondary-button"><i data-lucide="x"></i> Abbrechen</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</section>
|
|
{% endblock %} |