206 lines
7.9 KiB
HTML
206 lines
7.9 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<h1 class="page-title">Admin settings</h1>
|
|
<a class="btn btn-outline-ink" href="{{ url_for('admin.dashboard') }}">Back</a>
|
|
</div>
|
|
|
|
<div class="row mt-4 g-3">
|
|
<div class="col-lg-6">
|
|
<div class="card card-elevated">
|
|
<div class="card-header">
|
|
<h2 class="h5 mb-0">SMTP settings</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" action="{{ url_for('admin.update_smtp_settings') }}" class="vstack gap-3">
|
|
<div>
|
|
<label class="form-label">Host</label>
|
|
<input class="form-control" name="smtp_host" value="{{ settings.smtp_host or '' }}" placeholder="smtp.example.com" />
|
|
</div>
|
|
|
|
<div class="row g-2">
|
|
<div class="col-md-4">
|
|
<label class="form-label">Port</label>
|
|
<input class="form-control" name="smtp_port" value="{{ settings.smtp_port or '' }}" placeholder="587" />
|
|
</div>
|
|
<div class="col-md-8">
|
|
<label class="form-label">From address (optional)</label>
|
|
<input class="form-control" name="smtp_from" value="{{ settings.smtp_from or '' }}" placeholder="no-reply@example.com" />
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="form-label">Username</label>
|
|
<input class="form-control" name="smtp_username" value="{{ settings.smtp_username or '' }}" placeholder="user@example.com" />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="form-label">Password</label>
|
|
<input
|
|
class="form-control"
|
|
name="smtp_password"
|
|
type="password"
|
|
value=""
|
|
placeholder="Leave empty to keep current password"
|
|
autocomplete="new-password"
|
|
/>
|
|
<div class="form-text">
|
|
For security, the current password is never shown. Leave empty to keep it unchanged.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-2">
|
|
<div class="col-md-6">
|
|
<label class="form-label">Timeout (seconds)</label>
|
|
<input
|
|
class="form-control"
|
|
name="smtp_timeout_seconds"
|
|
value="{{ settings.smtp_timeout_seconds }}"
|
|
placeholder="10"
|
|
/>
|
|
</div>
|
|
<div class="col-md-6 d-flex align-items-end">
|
|
<div class="form-check">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
name="smtp_starttls"
|
|
value="1"
|
|
id="smtp_starttls"
|
|
{% if settings.smtp_starttls %}checked{% endif %}
|
|
/>
|
|
<label class="form-check-label" for="smtp_starttls">Use STARTTLS</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-check">
|
|
<input
|
|
class="form-check-input"
|
|
type="checkbox"
|
|
name="smtp_debug"
|
|
value="1"
|
|
id="smtp_debug"
|
|
{% if settings.smtp_debug %}checked{% endif %}
|
|
/>
|
|
<label class="form-check-label" for="smtp_debug">Enable SMTP debug logging</label>
|
|
<div class="form-text">Prints SMTP conversation to the Flask console (useful for troubleshooting).</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end">
|
|
<button class="btn btn-brand" type="submit">Save SMTP settings</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card card-elevated mt-3">
|
|
<div class="card-header">
|
|
<h2 class="h5 mb-0">Send test email</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" action="{{ url_for('admin.send_test_email') }}" class="vstack gap-2">
|
|
<div>
|
|
<label class="form-label">Recipient email</label>
|
|
<input class="form-control" name="to_email" placeholder="you@example.com" required />
|
|
<div class="form-text">Sends a short test email using the current SMTP configuration.</div>
|
|
</div>
|
|
<div class="d-flex justify-content-end">
|
|
<button class="btn btn-outline-ink" type="submit">Send test email</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card card-elevated mt-3">
|
|
<div class="card-header">
|
|
<h2 class="h5 mb-0">Public domain</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" action="{{ url_for('admin.update_public_domain') }}" class="vstack gap-2">
|
|
<div>
|
|
<label class="form-label">Domain used in emails</label>
|
|
<input
|
|
class="form-control"
|
|
name="public_domain"
|
|
value="{{ settings.public_domain or '' }}"
|
|
placeholder="signage.example.com"
|
|
/>
|
|
<div class="form-text">
|
|
Used to generate absolute links (like password reset). Do not include <code>http(s)://</code>.
|
|
Leave empty to use the current request host.
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-end">
|
|
<button class="btn btn-brand" type="submit">Save domain</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
<div class="card card-elevated">
|
|
<div class="card-header">
|
|
<h2 class="h5 mb-0">Admin users</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" action="{{ url_for('admin.create_admin_user') }}" class="vstack gap-2 mb-3">
|
|
<div class="row g-2">
|
|
<div class="col-md-6">
|
|
<input class="form-control" name="email" placeholder="Email" required />
|
|
</div>
|
|
<div class="col-md-6">
|
|
<input class="form-control" name="password" type="password" placeholder="Password (min 8 chars)" required />
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-end">
|
|
<button class="btn btn-brand" type="submit">Add admin</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>Email</th>
|
|
<th class="text-end">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for u in admins %}
|
|
<tr>
|
|
<td>
|
|
<strong>{{ u.email }}</strong>
|
|
{% if u.id == current_user.id %}
|
|
<span class="badge text-bg-secondary ms-2">You</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="text-end">
|
|
{% if u.id != current_user.id %}
|
|
<form method="post" action="{{ url_for('admin.demote_admin_user', user_id=u.id) }}" class="d-inline">
|
|
<button class="btn btn-outline-danger btn-sm" type="submit">Demote</button>
|
|
</form>
|
|
{% else %}
|
|
<span class="text-muted small">(cannot demote yourself)</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="2" class="text-muted">No admin users found.</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="form-text mt-2">
|
|
Safety: the last remaining admin cannot be demoted.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|