Files
team-tryouts/app/templates/pages/admin.html
T

277 lines
12 KiB
HTML

{% extends "layouts/base.html" %}
{% block title %}Admin Panel{% endblock %}
{% block page_title %}Admin Panel{% endblock %}
{% block content %}
<!-- Stats Bar -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon bg-primary">
<i class="fas fa-users"></i>
</div>
<div class="stat-info">
<h3>{{ stats.total_users }}</h3>
<p>Total Users</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon bg-success">
<i class="fas fa-user"></i>
</div>
<div class="stat-info">
<h3>{{ stats.total_players }}</h3>
<p>Players</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon bg-warning">
<i class="fas fa-shield-alt"></i>
</div>
<div class="stat-info">
<h3>{{ stats.total_org_teams }}</h3>
<p>Org Teams</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon bg-info">
<i class="fas fa-calendar-alt"></i>
</div>
<div class="stat-info">
<h3>{{ stats.active_tryouts }}</h3>
<p>Active Tryouts</p>
</div>
</div>
<div class="stat-card">
<div class="stat-icon bg-secondary">
<i class="fas fa-clock"></i>
</div>
<div class="stat-info">
<h3>{{ stats.upcoming_tryouts }}</h3>
<p>Upcoming</p>
</div>
</div>
</div>
<div class="dashboard-grid">
<!-- Left column -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-toggle-{% if settings.tryouts_open %}on{% else %}off{% endif %}"></i> Tryouts Access</h3>
</div>
<div class="card-body">
<p>
Status:
<span class="badge badge-{% if settings.tryouts_open %}success{% else %}danger{% endif %}">
{% if settings.tryouts_open %}OPEN{% else %}CLOSED{% endif %}
</span>
</p>
<p class="text-muted" style="font-size: 0.85rem; margin: 8px 0;">
{% if settings.tryouts_open %}
Coaches and managers can create and modify tryouts.
{% else %}
Only admins can create or modify tryouts. Coaches and managers are locked out.
{% endif %}
</p>
<form method="POST" action="{{ url_for('admin.toggle_tryouts') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<button type="submit" class="btn btn-{% if settings.tryouts_open %}warning{% else %}success{% endif %}">
{% if settings.tryouts_open %}Close Tryouts{% else %}Open Tryouts{% endif %}
</button>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
<h3><i class="fas fa-calendar-check"></i> Season Management</h3>
</div>
<div class="card-body">
<p>
Season:
<span class="badge badge-{% if settings.season_active %}success{% else %}info{% endif %}">
{% if settings.season_active %}ACTIVE{% else %}INACTIVE{% endif %}
</span>
</p>
<p><strong>Name:</strong> {{ settings.season_name }}</p>
<p><strong>Start:</strong> {{ settings.season_start }}</p>
<p><strong>End:</strong> {{ settings.season_end }}</p>
{% if not settings.season_active %}
<hr style="margin: 12px 0;">
<form method="POST" action="{{ url_for('admin.start_season') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-group">
<label>Season Name</label>
<input type="text" name="season_name" class="form-input" placeholder="e.g. Fall 2026" required>
</div>
<div class="form-group">
<label>Start Date</label>
<input type="date" name="season_start" class="form-input" required>
</div>
<button type="submit" class="btn btn-success">Begin Season</button>
</form>
{% else %}
<hr style="margin: 12px 0;">
<form method="POST" action="{{ url_for('admin.end_season') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-group">
<label>End Date</label>
<input type="date" name="season_end" class="form-input" required>
</div>
<button type="submit" class="btn btn-warning">End Season</button>
</form>
{% endif %}
</div>
</div>
<!-- Wipe Teams -->
<div class="card" style="border-left: 4px solid var(--danger);">
<div class="card-header">
<h3><i class="fas fa-trash-alt" style="color: var(--danger);"></i> Wipe Teams for New Season</h3>
</div>
<div class="card-body">
<p class="text-muted" style="font-size: 0.85rem; margin-bottom: 12px;">
This removes all players from organization teams and deletes all regular-season matches.
Team structures, coaches, and managers are preserved. A safety backup is created automatically.
</p>
<form method="POST" action="{{ url_for('admin.wipe_teams') }}" onsubmit="return confirmWipe()">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-group">
<label>Type <strong>WIPE</strong> to confirm:</label>
<input type="text" name="confirm" class="form-input" placeholder="WIPE" autocomplete="off" required>
</div>
<button type="submit" class="btn btn-danger">Wipe Team Rosters</button>
</form>
</div>
</div>
<!-- Manual Backup -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-database"></i> Manual Backup</h3>
</div>
<div class="card-body">
<p class="text-muted" style="font-size: 0.85rem; margin-bottom: 12px;">
Creates a full PostgreSQL database dump (.sql file). Stored on the server.
</p>
<form method="POST" action="{{ url_for('admin.create_backup') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<div class="form-group">
<label>Notes (optional)</label>
<input type="text" name="notes" class="form-input" placeholder="What's this backup for?">
</div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Create Backup Now
</button>
</form>
</div>
</div>
<!-- Backup History -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-history"></i> Backup History & Restore</h3>
</div>
<div class="card-body">
{% if backups %}
<div class="table-container">
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Filename</th>
<th>Size</th>
<th>Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for b in backups %}
<tr>
<td>{{ b.created_at.strftime('%Y-%m-%d %H:%M') if b.created_at else '—' }}</td>
<td style="max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="{{ b.filename }}">{{ b.filename }}</td>
<td>{{ (b.size_bytes / 1024)|round(1) }} KB</td>
<td><span class="badge badge-info">{{ b.backup_type }}</span></td>
<td style="white-space: nowrap;">
<a href="{{ url_for('admin.download_backup', backup_id=b.id) }}" class="btn btn-sm btn-primary" title="Download">
<i class="fas fa-download"></i>
</a>
<form method="POST" action="{{ url_for('admin.restore_backup', backup_id=b.id) }}" class="inline-form"
onsubmit="return confirm('Restore backup {{ b.filename }}? This will overwrite all current data. A safety backup will be made first.');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<button type="submit" class="btn btn-sm btn-warning" title="Restore">
<i class="fas fa-undo"></i>
</button>
</form>
<form method="POST" action="{{ url_for('admin.delete_backup', backup_id=b.id) }}" class="inline-form"
onsubmit="return confirm('Delete backup {{ b.filename }}?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<button type="submit" class="btn btn-sm btn-danger" title="Delete">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-muted" style="font-size: 0.85rem;">No backups yet. Create your first backup above.</p>
{% endif %}
</div>
</div>
</div>
<!-- Audit Log -->
<div class="card mt-4">
<div class="card-header">
<h3><i class="fas fa-clipboard-list"></i> Audit Log (Recent)</h3>
</div>
<div class="card-body">
{% if audit_logs %}
<div class="table-container">
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>User</th>
<th>Action</th>
<th>Details</th>
<th>IP</th>
</tr>
</thead>
<tbody>
{% for entry in audit_logs %}
<tr>
<td>{{ entry.created_at.strftime('%Y-%m-%d %H:%M') if entry.created_at else '—' }}</td>
<td>{{ entry.user.username if entry.user else 'System' }}</td>
<td><span class="badge badge-info">{{ entry.action }}</span></td>
<td style="max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ entry.details or '—' }}</td>
<td>{{ entry.ip_address or '—' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="text-muted" style="font-size: 0.85rem;">No audit log entries yet.</p>
{% endif %}
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
function confirmWipe() {
var input = document.querySelector('input[name="confirm"]');
if (input.value.trim() !== 'WIPE') {
alert('You must type WIPE to confirm.');
return false;
}
return confirm('This will remove ALL players from organization teams and delete ALL regular-season matches. A safety backup will be created automatically. Are you ABSOLUTELY sure?');
}
</script>
{% endblock %}