first release
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}DynDNS Manager{% endblock %}</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<style>
|
||||
:root { --sidebar-bg: #1e2a38; --sidebar-hover: #2d3f52; }
|
||||
body { background: #f4f6f9; min-height: 100vh; }
|
||||
#sidebar {
|
||||
width: 220px; min-width: 220px; min-height: 100vh;
|
||||
background: var(--sidebar-bg); color: #cdd6e0;
|
||||
}
|
||||
#sidebar .brand { color: #4fc3f7; font-weight: 700; font-size: 1.1rem; }
|
||||
#sidebar .nav-link {
|
||||
color: #b0bec5; border-radius: 6px; padding: .5rem .75rem;
|
||||
margin-bottom: 2px; transition: background .15s;
|
||||
}
|
||||
#sidebar .nav-link:hover, #sidebar .nav-link.active {
|
||||
background: var(--sidebar-hover); color: #fff;
|
||||
}
|
||||
#sidebar .nav-link i { width: 1.3em; }
|
||||
.main-content { flex: 1; padding: 2rem; min-width: 0; }
|
||||
.card { border: none; box-shadow: 0 1px 4px rgba(0,0,0,.08); }
|
||||
.badge-ip { font-family: monospace; font-size: .85em; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="d-flex">
|
||||
|
||||
<nav id="sidebar" class="d-flex flex-column p-3">
|
||||
<a href="{{ url_for('dashboard') }}" class="brand text-decoration-none mb-4 d-flex align-items-center gap-2">
|
||||
<i class="bi bi-globe2 fs-5"></i> DynDNS
|
||||
</a>
|
||||
<div class="nav flex-column">
|
||||
<a href="{{ url_for('dashboard') }}"
|
||||
class="nav-link {% if request.endpoint == 'dashboard' %}active{% endif %}">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
<a href="{{ url_for('users') }}"
|
||||
class="nav-link {% if request.endpoint in ['users'] %}active{% endif %}">
|
||||
<i class="bi bi-people-fill"></i> Benutzer
|
||||
</a>
|
||||
<a href="{{ url_for('settings') }}"
|
||||
class="nav-link {% if request.endpoint == 'settings' %}active{% endif %}">
|
||||
<i class="bi bi-gear-fill"></i> Einstellungen
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-auto">
|
||||
<hr style="border-color:#2d3f52">
|
||||
<small class="text-secondary d-block mb-2 px-2">{{ session.admin_username }}</small>
|
||||
<a href="{{ url_for('logout') }}" class="nav-link text-danger">
|
||||
<i class="bi bi-box-arrow-left"></i> Abmelden
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="main-content">
|
||||
{% with msgs = get_flashed_messages(with_categories=true) %}
|
||||
{% for cat, msg in msgs %}
|
||||
<div class="alert alert-{{ cat }} alert-dismissible fade show" role="alert">
|
||||
{{ msg }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,117 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Dashboard — DynDNS Manager{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="mb-0"><i class="bi bi-speedometer2 text-primary"></i> Dashboard</h4>
|
||||
</div>
|
||||
|
||||
<!-- Stats row -->
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-sm-4">
|
||||
<div class="card text-center p-3">
|
||||
<div class="fs-2 fw-bold text-primary">{{ users|length }}</div>
|
||||
<div class="text-muted small">Benutzer gesamt</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="card text-center p-3">
|
||||
<div class="fs-2 fw-bold text-success">{{ users|selectattr('active', 'equalto', 1)|list|length }}</div>
|
||||
<div class="text-muted small">Aktiv</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="card text-center p-3">
|
||||
<div class="fs-2 fw-bold text-info">{{ users|sum(attribute='update_count') }}</div>
|
||||
<div class="text-muted small">Updates gesamt</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User table -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span class="fw-semibold">Benutzer & aktuelle IPs</span>
|
||||
<a href="{{ url_for('users') }}" class="btn btn-sm btn-outline-primary">Verwalten</a>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Subdomain</th>
|
||||
<th>Hostname</th>
|
||||
<th>Aktuelle IP</th>
|
||||
<th>Letztes Update</th>
|
||||
<th>Updates</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in users %}
|
||||
<tr>
|
||||
<td class="fw-semibold">{{ u.subdomain }}</td>
|
||||
<td class="text-muted small">
|
||||
{% if base_domain %}{{ u.subdomain }}.{{ base_domain }}{% else %}—{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if u.current_ip %}
|
||||
<span class="badge bg-secondary badge-ip">{{ u.current_ip }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">noch kein Update</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-muted small">{{ u.last_updated or '—' }}</td>
|
||||
<td>{{ u.update_count }}</td>
|
||||
<td>
|
||||
{% if u.active %}
|
||||
<span class="badge bg-success">Aktiv</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">Inaktiv</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="text-center text-muted py-4">Noch keine Benutzer angelegt.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Update log -->
|
||||
<div class="card">
|
||||
<div class="card-header fw-semibold">Letzte Updates</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Zeit</th>
|
||||
<th>Benutzer</th>
|
||||
<th>Alte IP</th>
|
||||
<th>Neue IP</th>
|
||||
<th>Ergebnis</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for l in logs %}
|
||||
<tr>
|
||||
<td class="text-muted small">{{ l.timestamp }}</td>
|
||||
<td>{{ l.subdomain }} <span class="text-muted small">({{ l.dyndns_username }})</span></td>
|
||||
<td class="badge-ip text-muted small">{{ l.old_ip or '—' }}</td>
|
||||
<td><span class="badge bg-secondary badge-ip">{{ l.new_ip }}</span></td>
|
||||
<td>
|
||||
{% if l.result == 'good' %}
|
||||
<span class="badge bg-success">good</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger" title="{{ l.result }}">error</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="5" class="text-center text-muted py-3">Keine Einträge.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login — DynDNS Manager</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
|
||||
<style>
|
||||
body { background: #1e2a38; min-height: 100vh; display: flex; align-items: center; }
|
||||
.login-card { width: 100%; max-width: 380px; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="justify-content-center">
|
||||
<div class="login-card">
|
||||
<div class="text-center mb-4">
|
||||
<span class="text-info fs-2"><i class="bi bi-globe2"></i></span>
|
||||
<h4 class="text-white mt-2 mb-0">DynDNS Manager</h4>
|
||||
</div>
|
||||
<div class="card shadow">
|
||||
<div class="card-body p-4">
|
||||
{% with msgs = get_flashed_messages(with_categories=true) %}
|
||||
{% for cat, msg in msgs %}
|
||||
<div class="alert alert-{{ cat }} py-2">{{ msg }}</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Benutzername</label>
|
||||
<input name="username" type="text" class="form-control" autofocus required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label fw-semibold">Passwort</label>
|
||||
<input name="password" type="password" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Anmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Einstellungen — DynDNS Manager{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h4 class="mb-4"><i class="bi bi-gear-fill text-primary"></i> Einstellungen</h4>
|
||||
|
||||
<div class="row g-4">
|
||||
|
||||
<!-- Plesk config -->
|
||||
<div class="col-lg-7">
|
||||
<div class="card">
|
||||
<div class="card-header fw-semibold">Plesk-Server</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('settings_plesk') }}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Plesk URL</label>
|
||||
<input name="plesk_url" type="url" class="form-control font-monospace"
|
||||
placeholder="https://plesk.example.com:8443"
|
||||
value="{{ plesk_url }}" required>
|
||||
<div class="form-text">Inkl. Port, ohne abschließenden Slash.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">API-Schlüssel</label>
|
||||
<input name="plesk_api_key" type="password" class="form-control font-monospace"
|
||||
placeholder="Plesk API Key" value="{{ plesk_api_key }}">
|
||||
<div class="form-text">In Plesk: <em>Erweiterungen → API-Schlüssel</em> oder
|
||||
<em>Admin → API-Schlüssel verwalten</em>.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Basis-Domain</label>
|
||||
<input name="plesk_base_domain" type="text" class="form-control font-monospace"
|
||||
placeholder="example.com" value="{{ plesk_base_domain }}" required>
|
||||
<div class="form-text">Domain die in Plesk verwaltet wird. Subdomains werden darunter angelegt.</div>
|
||||
</div>
|
||||
<div class="mb-4 form-check">
|
||||
<input name="plesk_verify_ssl" type="checkbox" class="form-check-input" id="sslCheck"
|
||||
{% if plesk_verify_ssl == '1' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="sslCheck">SSL-Zertifikat prüfen</label>
|
||||
<div class="form-text">Deaktivieren bei selbstsignierten Zertifikaten.</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save"></i> Speichern
|
||||
</button>
|
||||
<button type="submit" name="test_connection" value="1" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-plug"></i> Verbindung testen
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Admin password -->
|
||||
<div class="col-lg-5">
|
||||
<div class="card">
|
||||
<div class="card-header fw-semibold">Admin-Passwort ändern</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('settings_password') }}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Aktuelles Passwort</label>
|
||||
<input name="current_password" type="password" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Neues Passwort</label>
|
||||
<input name="new_password" type="password" class="form-control" minlength="6" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Neues Passwort (Wiederholung)</label>
|
||||
<input name="new_password2" type="password" class="form-control" minlength="6" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-warning">
|
||||
<i class="bi bi-key"></i> Passwort ändern
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Speedport hint -->
|
||||
<div class="card mt-3 border-info">
|
||||
<div class="card-header fw-semibold text-info">
|
||||
<i class="bi bi-router"></i> Speedport-Konfiguration
|
||||
</div>
|
||||
<div class="card-body small">
|
||||
<p class="mb-2"><strong>Anbieter:</strong> Anderer Anbieter</p>
|
||||
<p class="mb-2"><strong>Hostname:</strong> <code><subdomain>.{{ plesk_base_domain or 'domain.com' }}</code></p>
|
||||
<p class="mb-2"><strong>Username:</strong> DynDNS-Benutzername</p>
|
||||
<p class="mb-2"><strong>Passwort:</strong> DynDNS-Passwort</p>
|
||||
<p class="mb-2"><strong>Updateserver:</strong> <code><deine-subdomain></code> (diese App)</p>
|
||||
<p class="mb-2"><strong>Protokoll:</strong> HTTP (oder HTTPS)</p>
|
||||
<p class="mb-0"><strong>Update-Pfad:</strong> <code>/nic/update</code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,184 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Benutzer — DynDNS Manager{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="mb-0"><i class="bi bi-people-fill text-primary"></i> Benutzer</h4>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addModal">
|
||||
<i class="bi bi-plus-lg"></i> Benutzer anlegen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Subdomain</th>
|
||||
<th>Hostname</th>
|
||||
<th>DynDNS-User</th>
|
||||
<th>Aktuelle IP</th>
|
||||
<th>Letztes Update</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in users %}
|
||||
<tr>
|
||||
<td class="fw-semibold">{{ u.subdomain }}</td>
|
||||
<td class="text-muted small font-monospace">
|
||||
{% if base_domain %}{{ u.subdomain }}.{{ base_domain }}{% else %}—{% endif %}
|
||||
</td>
|
||||
<td>{{ u.username }}</td>
|
||||
<td>
|
||||
{% if u.current_ip %}
|
||||
<span class="badge bg-secondary font-monospace">{{ u.current_ip }}</span>
|
||||
{% else %}<span class="text-muted">—</span>{% endif %}
|
||||
</td>
|
||||
<td class="text-muted small">{{ u.last_updated or '—' }}</td>
|
||||
<td>
|
||||
{% if u.active %}
|
||||
<span class="badge bg-success">Aktiv</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">Inaktiv</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-secondary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#editModal{{ u.id }}"
|
||||
title="Bearbeiten">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<form method="post" action="{{ url_for('user_toggle', user_id=u.id) }}" class="d-inline">
|
||||
<button type="submit" class="btn btn-outline-warning" title="Aktivieren/Deaktivieren">
|
||||
<i class="bi bi-{% if u.active %}pause{% else %}play{% endif %}-fill"></i>
|
||||
</button>
|
||||
</form>
|
||||
<button class="btn btn-outline-danger"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#delModal{{ u.id }}"
|
||||
title="Löschen">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Edit modal -->
|
||||
<div class="modal fade" id="editModal{{ u.id }}" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Benutzer bearbeiten</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="post" action="{{ url_for('user_edit', user_id=u.id) }}">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">DynDNS-Benutzername</label>
|
||||
<input name="username" type="text" class="form-control"
|
||||
value="{{ u.username }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Neues Passwort <span class="text-muted">(leer = unverändert)</span></label>
|
||||
<input name="password" type="password" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Subdomain</label>
|
||||
<div class="input-group">
|
||||
<input name="subdomain" type="text" class="form-control font-monospace"
|
||||
value="{{ u.subdomain }}" required>
|
||||
{% if base_domain %}
|
||||
<span class="input-group-text text-muted">.{{ base_domain }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete modal -->
|
||||
<div class="modal fade" id="delModal{{ u.id }}" tabindex="-1">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Benutzer löschen?</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<strong>{{ u.username }}</strong> ({{ u.subdomain }}) wirklich löschen?
|
||||
Alle Update-Logs werden ebenfalls entfernt.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<form method="post" action="{{ url_for('user_delete', user_id=u.id) }}" class="d-inline">
|
||||
<button type="submit" class="btn btn-danger">Löschen</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<tr><td colspan="7" class="text-center text-muted py-4">
|
||||
Noch keine Benutzer. <a href="#" data-bs-toggle="modal" data-bs-target="#addModal">Jetzt anlegen.</a>
|
||||
</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add modal -->
|
||||
<div class="modal fade" id="addModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Neuen Benutzer anlegen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="post" action="{{ url_for('user_add') }}">
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">DynDNS-Benutzername</label>
|
||||
<input name="username" type="text" class="form-control"
|
||||
placeholder="z.B. stefan" required>
|
||||
<div class="form-text">Wird im Speedport als „Username" eingetragen.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Passwort</label>
|
||||
<input name="password" type="password" class="form-control" required>
|
||||
<div class="form-text">Wird im Speedport als „Passwort" eingetragen.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Subdomain</label>
|
||||
<div class="input-group">
|
||||
<input name="subdomain" type="text" class="form-control font-monospace"
|
||||
placeholder="mypc" required
|
||||
pattern="[a-z0-9]([a-z0-9\-]*[a-z0-9])?"
|
||||
title="Kleinbuchstaben, Ziffern und Bindestriche">
|
||||
{% if base_domain %}
|
||||
<span class="input-group-text text-muted">.{{ base_domain }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-text">Nur Kleinbuchstaben, Ziffern und Bindestriche.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary">Anlegen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user