Userverwaltung hinzugefügt
This commit is contained in:
@@ -42,10 +42,22 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Logout -->
|
||||
<div class="ms-2">
|
||||
<a href="/logout" class="btn btn-outline-secondary"><i class="ti ti-logout me-1"></i>Abmelden</a>
|
||||
<!-- User-Dropdown (Passwort ändern, Userverwaltung, Abmelden) -->
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="dropdown ms-2">
|
||||
<a class="btn btn-outline-secondary text-nowrap" href="#" data-bs-toggle="dropdown">
|
||||
<i class="ti ti-user me-1"></i>{{ current_user.email }}{% if current_user.is_admin %}<span class="badge bg-red text-red-fg ms-2" style="font-size:0.6rem;">Admin</span>{% elif current_user.is_superuser %}<span class="badge bg-purple text-purple-fg ms-2" style="font-size:0.6rem;">Superuser</span>{% else %}<span class="badge bg-blue text-blue-fg ms-2" style="font-size:0.6rem;">User</span>{% endif %} <i class="ti ti-chevron-down"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="/change-password"><i class="ti ti-key me-1"></i>Passwort ändern</a>
|
||||
{% if current_user.is_admin %}
|
||||
<a class="dropdown-item" href="/admin/users"><i class="ti ti-users me-1"></i>Userverwaltung</a>
|
||||
{% endif %}
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/logout"><i class="ti ti-logout me-1"></i>Abmelden</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
75
templates/change_password.html
Normal file
75
templates/change_password.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CANCOM Simple Signage – Passwort ändern</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<script>
|
||||
(() => {
|
||||
const stored = window.localStorage.getItem("signage-theme");
|
||||
const theme = stored === "dark" || stored === "light" ? stored : "light";
|
||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
||||
<script defer
|
||||
src="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/js/tabler.min.js"></script>
|
||||
{% include "_styles.html" %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
|
||||
{% set brand_subtitle = "Passwort ändern" %}
|
||||
{% set site_dropdown_url_prefix = "/admin/" %}
|
||||
{% include "_header.html" %}
|
||||
|
||||
<div class="navbar-expand-md">
|
||||
<div class="collapse navbar-collapse show">
|
||||
<div class="navbar navbar-dark nav-surface">
|
||||
<div class="container-xl">
|
||||
<div class="d-flex flex-wrap gap-2 py-2">
|
||||
<a class="btn btn-white" href="/admin"><i class="ti ti-arrow-left me-1"></i>Zurück</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="container-xl mt-4" style="max-width:480px;">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-3">Passwort ändern</h2>
|
||||
|
||||
{% if error %}
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
{% endif %}
|
||||
{% if success %}
|
||||
<div class="alert alert-success" role="alert">{{ success }}</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Neues Passwort</label>
|
||||
<input type="password" class="form-control" name="new_password" minlength="6" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Passwort wiederholen</label>
|
||||
<input type="password" class="form-control" name="confirm_password" minlength="6" required>
|
||||
</div>
|
||||
<button class="btn btn-primary w-100">Passwort speichern</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "_footer.html" %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -36,8 +36,8 @@
|
||||
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Benutzername</label>
|
||||
<input class="form-control" name="username" required>
|
||||
<label class="form-label">E-Mail / Benutzername</label>
|
||||
<input class="form-control" name="username" placeholder="admin" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Passwort</label>
|
||||
|
||||
124
templates/user_create.html
Normal file
124
templates/user_create.html
Normal file
@@ -0,0 +1,124 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CANCOM Simple Signage – User anlegen</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<script>
|
||||
(() => {
|
||||
const stored = window.localStorage.getItem("signage-theme");
|
||||
const theme = stored === "dark" || stored === "light" ? stored : "light";
|
||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
||||
<script defer
|
||||
src="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/js/tabler.min.js"></script>
|
||||
{% include "_styles.html" %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
|
||||
{% set brand_subtitle = "User anlegen" %}
|
||||
{% set site_dropdown_url_prefix = "/admin/" %}
|
||||
{% include "_header.html" %}
|
||||
|
||||
<div class="navbar-expand-md">
|
||||
<div class="collapse navbar-collapse show">
|
||||
<div class="navbar navbar-dark nav-surface">
|
||||
<div class="container-xl">
|
||||
<div class="d-flex flex-wrap gap-2 py-2">
|
||||
<a class="btn btn-white" href="/admin/{{ current_site }}"><i class="ti ti-arrow-left me-1"></i>Zurück</a>
|
||||
<a class="btn btn-white" href="/admin/users"><i class="ti ti-users me-1"></i>Userliste</a>
|
||||
<a class="btn btn-white active" href="/admin/users/create"><i class="ti ti-user-plus me-1"></i>Neu anlegen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="container-xl mt-4" style="max-width:600px;">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><i class="ti ti-user-plus me-1"></i>Neuen User anlegen</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/admin/users/create" method="post">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">E-Mail (Username)</label>
|
||||
<input type="email" name="email" class="form-control" placeholder="user@example.com" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Passwort</label>
|
||||
<input type="password" name="password" class="form-control" placeholder="Passwort" minlength="6" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Rolle</label>
|
||||
<select name="role" class="form-select" id="role-select">
|
||||
<option value="user" selected>User</option>
|
||||
<option value="superuser">Superuser</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3" id="sites-select-wrapper">
|
||||
<label class="form-label">Standort-Berechtigungen</label>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary w-100 text-start" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span id="sites-btn-text">Standorte auswählen</span>
|
||||
<i class="ti ti-chevron-down float-end"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu p-2" style="min-width:220px;" id="sites-dropdown-menu">
|
||||
{% for s in all_sites %}
|
||||
<label class="dropdown-item d-flex align-items-center gap-2 px-2 py-1">
|
||||
<input class="form-check-input m-0" type="checkbox" name="sites" value="{{ s }}">
|
||||
<span>{{ s | capitalize }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">User anlegen</button>
|
||||
<a href="/admin/users" class="btn btn-outline-secondary ms-2">Abbrechen</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "_footer.html" %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const roleSelect = document.getElementById("role-select");
|
||||
const sitesWrapper = document.getElementById("sites-select-wrapper");
|
||||
roleSelect.addEventListener("change", function () {
|
||||
sitesWrapper.style.display = (this.value === "admin" || this.value === "superuser") ? "none" : "block";
|
||||
});
|
||||
if (roleSelect.value === "admin" || roleSelect.value === "superuser") sitesWrapper.style.display = "none";
|
||||
|
||||
const dropdownMenu = document.getElementById("sites-dropdown-menu");
|
||||
const btnText = document.getElementById("sites-btn-text");
|
||||
if (dropdownMenu) {
|
||||
dropdownMenu.addEventListener("change", function () {
|
||||
const checked = dropdownMenu.querySelectorAll("input:checked");
|
||||
const total = dropdownMenu.querySelectorAll("input").length;
|
||||
btnText.textContent = checked.length === 0
|
||||
? "Standorte auswählen"
|
||||
: checked.length === total
|
||||
? "Alle Standorte"
|
||||
: checked.length + " von " + total + " ausgewählt";
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
131
templates/user_edit.html
Normal file
131
templates/user_edit.html
Normal file
@@ -0,0 +1,131 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CANCOM Simple Signage – User bearbeiten</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<script>
|
||||
(() => {
|
||||
const stored = window.localStorage.getItem("signage-theme");
|
||||
const theme = stored === "dark" || stored === "light" ? stored : "light";
|
||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
||||
<script defer
|
||||
src="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/js/tabler.min.js"></script>
|
||||
{% include "_styles.html" %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
|
||||
{% set brand_subtitle = "User bearbeiten" %}
|
||||
{% set site_dropdown_url_prefix = "/admin/" %}
|
||||
{% include "_header.html" %}
|
||||
|
||||
<div class="navbar-expand-md">
|
||||
<div class="collapse navbar-collapse show">
|
||||
<div class="navbar navbar-dark nav-surface">
|
||||
<div class="container-xl">
|
||||
<div class="d-flex flex-wrap gap-2 py-2">
|
||||
<a class="btn btn-white" href="/admin"><i class="ti ti-arrow-left me-1"></i>Zurück</a>
|
||||
<a class="btn btn-white" href="/admin/users"><i class="ti ti-users me-1"></i>Userliste</a>
|
||||
<a class="btn btn-white active" href="#"><i class="ti ti-edit me-1"></i>Bearbeiten</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="container-xl mt-4" style="max-width:600px;">
|
||||
|
||||
{% if error %}
|
||||
<div class="alert alert-danger" role="alert">{{ error }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><i class="ti ti-edit me-1"></i>User bearbeiten</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/admin/users/edit/{{ user.email }}" method="post">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">E-Mail (Username)</label>
|
||||
<input type="email" name="email" class="form-control" value="{{ user.email }}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Rolle</label>
|
||||
<select name="role" class="form-select" id="role-select">
|
||||
<option value="user" {% if user.role == "user" %}selected{% endif %}>User</option>
|
||||
<option value="superuser" {% if user.role == "superuser" %}selected{% endif %}>Superuser</option>
|
||||
<option value="admin" {% if user.role == "admin" %}selected{% endif %}>Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3" id="sites-select-wrapper" {% if user.role == "admin" or user.role == "superuser" %}style="display:none"{% endif %}>
|
||||
<label class="form-label">Standort-Berechtigungen</label>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary w-100 text-start" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span id="sites-btn-text">
|
||||
{%- set checked_sites = user.sites -%}
|
||||
{%- if checked_sites -%}
|
||||
{{ checked_sites|length }} von {{ all_sites|length }} ausgewählt
|
||||
{%- else -%}
|
||||
Standorte auswählen
|
||||
{%- endif -%}
|
||||
</span>
|
||||
<i class="ti ti-chevron-down float-end"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu p-2" style="min-width:220px;" id="sites-dropdown-menu">
|
||||
{% for s in all_sites %}
|
||||
<label class="dropdown-item d-flex align-items-center gap-2 px-2 py-1">
|
||||
<input class="form-check-input m-0" type="checkbox" name="sites" value="{{ s }}"
|
||||
{% if s in user.sites %}checked{% endif %}>
|
||||
<span>{{ s | capitalize }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||
<a href="/admin/users" class="btn btn-outline-secondary ms-2">Abbrechen</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "_footer.html" %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const roleSelect = document.getElementById("role-select");
|
||||
const sitesWrapper = document.getElementById("sites-select-wrapper");
|
||||
roleSelect.addEventListener("change", function () {
|
||||
sitesWrapper.style.display = (this.value === "admin" || this.value === "superuser") ? "none" : "block";
|
||||
});
|
||||
|
||||
const dropdownMenu = document.getElementById("sites-dropdown-menu");
|
||||
const btnText = document.getElementById("sites-btn-text");
|
||||
if (dropdownMenu) {
|
||||
dropdownMenu.addEventListener("change", function () {
|
||||
const checked = dropdownMenu.querySelectorAll("input:checked");
|
||||
const total = dropdownMenu.querySelectorAll("input").length;
|
||||
btnText.textContent = checked.length === 0
|
||||
? "Standorte auswählen"
|
||||
: checked.length === total
|
||||
? "Alle Standorte"
|
||||
: checked.length + " von " + total + " ausgewählt";
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
141
templates/user_list.html
Normal file
141
templates/user_list.html
Normal file
@@ -0,0 +1,141 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CANCOM Simple Signage – Userverwaltung</title>
|
||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
<script>
|
||||
(() => {
|
||||
const stored = window.localStorage.getItem("signage-theme");
|
||||
const theme = stored === "dark" || stored === "light" ? stored : "light";
|
||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet"
|
||||
href="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/css/tabler.min.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css">
|
||||
<script defer
|
||||
src="https://unpkg.com/@tabler/core@1.0.0-beta20/dist/js/tabler.min.js"></script>
|
||||
{% include "_styles.html" %}
|
||||
<style>
|
||||
.badge-site { background: #e9ecef; color: #212121; margin: 0 0.15rem; }
|
||||
[data-bs-theme="dark"] .badge-site { background: #3a3f45; color: #e9ecef; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
|
||||
{% set brand_subtitle = "Userverwaltung" %}
|
||||
{% set site_dropdown_url_prefix = "/admin/" %}
|
||||
{% include "_header.html" %}
|
||||
|
||||
<div class="navbar-expand-md">
|
||||
<div class="collapse navbar-collapse show">
|
||||
<div class="navbar navbar-dark nav-surface">
|
||||
<div class="container-xl">
|
||||
<div class="d-flex flex-wrap gap-2 py-2">
|
||||
<a class="btn btn-white" href="/admin/{{ current_site }}"><i class="ti ti-arrow-left me-1"></i>Zurück</a>
|
||||
<a class="btn btn-white active" href="/admin/users"><i class="ti ti-users me-1"></i>Userliste</a>
|
||||
<a class="btn btn-white" href="/admin/users/create"><i class="ti ti-user-plus me-1"></i>Neu anlegen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="container-xl mt-4">
|
||||
|
||||
{% if request.args.get('reset') and request.args.get('temp') %}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<strong>Passwort zurückgesetzt für {{ request.args.get('reset') }}</strong><br>
|
||||
Temporäres Passwort: <code>{{ request.args.get('temp') }}</code><br>
|
||||
<small class="text-muted">Der User muss sich beim nächsten Login mit diesem Passwort anmelden und wird dann zur Passwort-Änderung aufgefordert.</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.args.get('updated') %}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<strong>User {{ request.args.get('updated') }} erfolgreich aktualisiert.</strong>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title"><i class="ti ti-users me-1"></i>User</h3>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-vcenter card-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>E-Mail</th>
|
||||
<th>Rolle</th>
|
||||
<th>Standorte</th>
|
||||
<th>Status</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in users %}
|
||||
<tr>
|
||||
<td class="text-nowrap">{{ u.email }}</td>
|
||||
<td>
|
||||
{% if u.role == "admin" %}
|
||||
<span class="badge bg-red text-red-fg">Admin</span>
|
||||
{% elif u.role == "superuser" %}
|
||||
<span class="badge bg-purple text-purple-fg">Superuser</span>
|
||||
{% else %}
|
||||
<span class="badge bg-blue text-blue-fg">User</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if u.role == "admin" or u.role == "superuser" %}
|
||||
<span class="text-muted">Alle</span>
|
||||
{% else %}
|
||||
{% for s in u.sites %}
|
||||
<span class="badge badge-site">{{ s }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">–</span>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if u.must_change_password %}
|
||||
<span class="badge bg-warning text-white">Passwort-Änderung erforderlich</span>
|
||||
{% else %}
|
||||
<span class="badge bg-green text-green-fg">Aktiv</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex gap-1">
|
||||
{% if u.email != current_user.email %}
|
||||
<form action="/admin/users/delete/{{ u.email }}" method="post"
|
||||
onsubmit="return confirm('User »{{ u.email }}« wirklich löschen?')">
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm">Löschen</button>
|
||||
</form>
|
||||
<a href="/admin/users/edit/{{ u.email }}" class="btn btn-outline-secondary btn-sm">Bearbeiten</a>
|
||||
<form action="/admin/users/reset-password/{{ u.email }}" method="post" style="display:inline">
|
||||
<button type="submit" class="btn btn-outline-warning btn-sm">Reset</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<span class="text-muted small">(aktueller User)</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include "_footer.html" %}
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user