125 lines
7.9 KiB
HTML
125 lines
7.9 KiB
HTML
{% extends 'layout/base.html' %}
|
||
{% block title %}Админка сервера{% endblock %}
|
||
{% block body %}
|
||
<div class="content">
|
||
{% include 'admin/_flash.html' %}
|
||
<div class="metrics">
|
||
<div class="metric"><div class="metric-label">Домены</div><div class="metric-val">{{ n_domains }}</div><div class="metric-sub">настроено</div></div>
|
||
<div class="metric"><div class="metric-label">Ящики</div><div class="metric-val">{{ n_mailboxes }}</div><div class="metric-sub">активные</div></div>
|
||
<div class="metric"><div class="metric-label">Алиасы</div><div class="metric-val">{{ n_aliases }}</div><div class="metric-sub">переадресации</div></div>
|
||
<div class="metric"><div class="metric-label">DMS</div><div class="metric-val">v14</div><div class="metric-sub">docker-mailserver</div></div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-head"><div class="card-title">Быстрые действия</div></div>
|
||
<div class="card-body" style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<a class="btn" href="{{ url_for('admin.mailboxes') }}">Ящики</a>
|
||
<a class="btn" href="{{ url_for('admin.aliases') }}">Алиасы</a>
|
||
<a class="btn" href="{{ url_for('admin.domains') }}">Домены / DNS / DKIM</a>
|
||
<span style="flex:1"></span>
|
||
<form method="post" action="{{ url_for('admin.trash_cleanup_now') }}" style="display:inline">
|
||
<button type="submit" class="btn" title="Очистить корзину старше {{ settings.trash_retention_days }} дней у всех активных юзеров">Очистить Корзину</button>
|
||
</form>
|
||
<form method="post" action="{{ url_for('admin.reindex') }}" style="display:inline">
|
||
<button type="submit" class="btn" title="Перечитать письма из IMAP и положить в Meilisearch">Реиндексировать поиск</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-head"><div class="card-title">Администраторы ({{ admins|length }})</div></div>
|
||
<div class="card-body">
|
||
<p style="color:var(--color-text-secondary);font-size:12px;margin-bottom:12px">
|
||
Администраторы видят раздел «Сервер» и пункты «Ящики», «Группы», «Общие ящики» в настройках, могут заходить на /admin/*.
|
||
</p>
|
||
<div style="display:flex;flex-direction:column;gap:6px;margin-bottom:14px">
|
||
{% for a in admins %}
|
||
<div style="display:flex;align-items:center;gap:10px;padding:6px 0;border-bottom:0.5px solid var(--color-border-tertiary)">
|
||
<span style="flex:1">{{ a }}</span>
|
||
<form method="post" action="{{ url_for('admin.admins_change') }}" onsubmit="return confirm('Снять {{ a }} с администратора?')">
|
||
<input type="hidden" name="action" value="remove">
|
||
<input type="hidden" name="email" value="{{ a }}">
|
||
<button class="btn" type="submit" style="font-size:12px;color:var(--color-text-danger)">Убрать</button>
|
||
</form>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
<form method="post" action="{{ url_for('admin.admins_change') }}" style="display:flex;gap:8px;align-items:center">
|
||
<input type="hidden" name="action" value="add">
|
||
<input class="compose-input" name="email" placeholder="email@domain" required type="email"
|
||
style="flex:1;border:0.5px solid var(--color-border-tertiary);border-radius:6px;padding:6px 10px">
|
||
<button class="btn btn-primary" type="submit">+ Назначить администратором</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-head"><div class="card-title">ELK · отправка логов</div></div>
|
||
<div class="card-body">
|
||
<p style="color:var(--color-text-secondary);font-size:12px;margin-bottom:10px">
|
||
Логи Flask, Dramatiq, Postfix/Dovecot и cron-бэкапов отправляются на удалённый syslog-приёмник
|
||
(Logstash / rsyslog-collector). Настрой и нажми «Применить» — конфиг
|
||
<code>/etc/rsyslog.d/49-mail-stack.conf</code> перегенерируется и rsyslog перезагрузится.
|
||
Пустой ELK_HOST выключает отправку.
|
||
</p>
|
||
<table class="tbl" style="margin-bottom:14px">
|
||
<tr><td style="width:40%;color:var(--color-text-secondary)">Текущий target</td>
|
||
<td><code>{{ settings.elk_host or '— не настроен —' }}{% if settings.elk_host %}:{{ settings.elk_port }} ({{ settings.elk_proto }}){% endif %}</code></td></tr>
|
||
</table>
|
||
<form method="post" action="{{ url_for('admin.elk_apply') }}">
|
||
<button class="btn btn-primary" type="submit">Применить настройки rsyslog</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-head"><div class="card-title">Настройки приложения</div></div>
|
||
<div class="card-body">
|
||
<p style="color:var(--color-text-secondary);margin-bottom:14px;font-size:12px">
|
||
Значения сохраняются в <code>.env</code>. IMAP/SMTP-параметры применятся после авто-перезагрузки Flask
|
||
(debug-mode сам подхватит правки .env), остальное — мгновенно.
|
||
</p>
|
||
<form method="post" action="{{ url_for('admin.settings_update') }}" class="settings-form">
|
||
{% for form_name, env_name, kind, label in editable_settings %}
|
||
<div class="settings-row">
|
||
<label for="set-{{ form_name }}">
|
||
<span class="settings-label">{{ label }}</span>
|
||
<span class="settings-key">{{ env_name }}</span>
|
||
</label>
|
||
<input id="set-{{ form_name }}" name="{{ form_name }}"
|
||
type="{{ 'number' if kind == 'int' else 'text' }}"
|
||
value="{{ settings.get(form_name) if settings.get(form_name) is not none else '' }}">
|
||
</div>
|
||
{% endfor %}
|
||
<div class="settings-readonly">
|
||
<strong>Только для чтения:</strong>
|
||
use_mock_mail = {{ settings.use_mock_mail }}
|
||
</div>
|
||
<div style="display:flex;gap:8px;margin-top:14px">
|
||
<button class="btn btn-primary" type="submit">Сохранить</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
.settings-form{display:flex;flex-direction:column;gap:10px}
|
||
.settings-row{display:grid;grid-template-columns:minmax(280px,2fr) minmax(160px,1fr);gap:14px;align-items:center}
|
||
.settings-row label{display:flex;flex-direction:column;gap:2px}
|
||
.settings-label{font-size:13px;color:var(--color-text-primary)}
|
||
.settings-key{font-size:11px;color:var(--color-text-tertiary);font-family:monospace}
|
||
.settings-row input{width:100%;padding:6px 10px;font-size:13px;font-family:inherit;color:var(--color-text-primary);background:var(--color-background-primary);border:0.5px solid var(--color-border-tertiary);border-radius:6px}
|
||
.settings-row input:focus{outline:none;border-color:var(--color-text-primary)}
|
||
.settings-readonly{margin-top:6px;padding:8px 12px;background:var(--color-background-secondary);border-radius:6px;font-size:12px;color:var(--color-text-secondary);font-family:monospace}
|
||
</style>
|
||
|
||
<div class="card" style="margin-top:14px">
|
||
<div class="card-head"><div class="card-title">Отложенная отправка</div></div>
|
||
<div class="card-body" style="color:var(--color-text-secondary)">
|
||
Все исходящие письма уходят через <strong>{{ settings.send_defer_seconds }} сек</strong>
|
||
после нажатия «Отправить». В это окно вы можете отменить отправку.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|