123 lines
6.6 KiB
HTML
123 lines
6.6 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Settings{% endblock %}
|
|
{% macro csrf() %}<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">{% endmacro %}
|
|
{% block content %}
|
|
<h1>Settings</h1>
|
|
|
|
<section class="card" id="account">
|
|
<h2>My account</h2>
|
|
<form method="post" action="{{ url_for('views.settings_account') }}" class="form-grid">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#account">
|
|
<label>Email <input name="email" type="email" value="{{ user.email }}" required></label>
|
|
<label>Current password <input name="current" type="password" autocomplete="current-password" required></label>
|
|
<label>New password <input name="new" type="password" autocomplete="new-password" minlength="10" placeholder="leave empty to keep"></label>
|
|
<label>Confirm new password <input name="confirm" type="password" autocomplete="new-password"></label>
|
|
<div class="actions"><button class="btn primary">Save</button></div>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="card" id="clients">
|
|
<h2>Clients</h2>
|
|
<p class="muted">A machine can only connect once its public key is listed here. On the client, run <code>patchbayd --pubkey</code> and paste the output below.</p>
|
|
{% if clients %}
|
|
<table class="grid">
|
|
<thead><tr><th>Name</th><th>Host</th><th>Key</th><th>Last seen</th><th>Added by</th><th></th></tr></thead>
|
|
<tbody>
|
|
{% for c in clients %}
|
|
<tr>
|
|
<td>{{ c.name }}</td>
|
|
<td>{{ c.hostname or '-' }}{% if c.last_addr %} <span class="muted mono">{{ c.last_addr }}</span>{% endif %}</td>
|
|
<td class="mono key" title="{{ c.pubkey }}">{{ c.pubkey.split(' ')[0] }} ...{{ c.pubkey[-12:] }}</td>
|
|
<td data-ts="{{ c.last_seen }}"><span class="ts"></span></td>
|
|
<td>{{ c.added_by }}</td>
|
|
<td class="right">
|
|
<form method="post" action="{{ url_for('views.clients_delete', cid=c.id) }}" data-confirm="Remove client {{ c.name }}? It will be disconnected and its nodes lose their client.">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#clients">
|
|
<button class="btn small danger">Remove</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% endif %}
|
|
<form method="post" action="{{ url_for('views.clients_add') }}" class="form-grid">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#clients">
|
|
<label>Name <input name="name" required pattern="[A-Za-z0-9._\-]{1,64}" placeholder="e.g. homeserver"></label>
|
|
<label class="wide">Public key <textarea name="pubkey" rows="2" required placeholder="ssh-ed25519 AAAA... root@host"></textarea></label>
|
|
<div class="actions"><button class="btn primary">Add client</button></div>
|
|
</form>
|
|
</section>
|
|
|
|
{% if user.sysop %}
|
|
<section class="card" id="users">
|
|
<h2>Users</h2>
|
|
<p class="muted">All users can edit the patch and manage clients. Only the sysop ({{ conf.get('sysopuser') }}, defined in patchbay.conf) manages users and server settings.</p>
|
|
{% for u in users %}
|
|
<div class="user-row">
|
|
<form method="post" action="{{ url_for('views.users_edit', uid=u.id) }}" class="inline-form">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#users">
|
|
<strong>{{ u.username }}</strong>
|
|
<input name="email" type="email" value="{{ u.email }}" required aria-label="Email">
|
|
<input name="password" type="password" minlength="10" placeholder="new password" aria-label="New password" autocomplete="new-password">
|
|
<button class="btn small">Save</button>
|
|
</form>
|
|
<form method="post" action="{{ url_for('views.users_delete', uid=u.id) }}" data-confirm="Delete user {{ u.username }}?">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#users">
|
|
<button class="btn small danger">Delete</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<p class="muted">No other users yet.</p>
|
|
{% endfor %}
|
|
<h3>New user</h3>
|
|
<form method="post" action="{{ url_for('views.users_add') }}" class="form-grid">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#users">
|
|
<label>Username <input name="username" required pattern="[A-Za-z0-9._\-]{1,64}"></label>
|
|
<label>Email <input name="email" type="email" required></label>
|
|
<label>Password <input name="password" type="password" minlength="10" required autocomplete="new-password"></label>
|
|
<div class="actions"><button class="btn primary">Create user</button></div>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="card" id="mail">
|
|
<h2>Mail</h2>
|
|
<p class="muted">Used to send login codes. Saved to patchbay.conf.</p>
|
|
<form method="post" action="{{ url_for('views.settings_mail') }}" class="form-grid">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#mail">
|
|
<label>SMTP server <input name="host" value="{{ conf.get('mailhost') }}" placeholder="smtp.example.org"></label>
|
|
<label>Port <input name="port" type="number" min="1" max="65535" value="{{ conf.get('mailport') }}"></label>
|
|
<label>Security
|
|
<select name="security">
|
|
{% for v, l in [('ssl', 'SSL/TLS'), ('starttls', 'STARTTLS'), ('none', 'None')] %}
|
|
<option value="{{ v }}" {{ 'selected' if conf.get('mailsecurity') == v }}>{{ l }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
<label>Username <input name="user" value="{{ conf.get('mailuser') }}" autocomplete="off"></label>
|
|
<label>Password <input name="password" type="password" placeholder="{{ 'unchanged' if conf.get('mailpassword') else '' }}" autocomplete="new-password"></label>
|
|
<label>From address <input name="from" value="{{ conf.get('mailfrom') }}"></label>
|
|
<div class="actions"><button class="btn primary">Save</button></div>
|
|
</form>
|
|
<form method="post" action="{{ url_for('views.settings_mail_test') }}">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#mail">
|
|
<button class="btn">Send test mail to {{ user.email }}</button>
|
|
</form>
|
|
</section>
|
|
|
|
<section class="card" id="retention">
|
|
<h2>Statistics retention</h2>
|
|
<form method="post" action="{{ url_for('views.settings_retention') }}" class="form-grid">
|
|
{{ csrf() }}<input type="hidden" name="anchor" value="#retention">
|
|
<label>Per-minute data (hours) <input name="stats_minute_hours" type="number" min="1" value="{{ retention.stats_minute_hours }}"></label>
|
|
<label>Hourly data (days) <input name="stats_hour_days" type="number" min="1" value="{{ retention.stats_hour_days }}"></label>
|
|
<label>Daily data (days, 0 = forever) <input name="stats_day_days" type="number" min="0" value="{{ retention.stats_day_days }}"></label>
|
|
<div class="actions"><button class="btn primary">Save</button></div>
|
|
</form>
|
|
</section>
|
|
{% endif %}
|
|
{% endblock %}
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='common.js') }}"></script>
|
|
{% endblock %}
|