Enhance UI and functionality for admin dashboard and user management
- Update `_base_context` to include `active_nav` for dynamic navigation highlighting. - Revamp `base.html` to improve header layout and navigation links for better user experience. - Redesign `dashboard.html` to include statistics for new and edited articles, enhancing visibility of content changes. - Improve `users.html` layout for user management, adding detailed user roles and status indicators. - Update CSS styles for a cohesive design across the application, introducing new color variables and layout adjustments.
This commit is contained in:
@@ -3,22 +3,43 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ title if title else "TK Wiki Newsletter Admin" }}</title>
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<title>{% block title %}{{ title if title else "Wiki Newsletter Admin" }}{% endblock %} · Thomas-Krenn.AG</title>
|
||||
<link rel="stylesheet" href="/static/css/main.css?v=3">
|
||||
</head>
|
||||
<body>
|
||||
<body class="{% block body_class %}{% endblock %}">
|
||||
<header class="topbar">
|
||||
<h1>TK Wiki Newsletter Admin</h1>
|
||||
<div class="topbar-brand">
|
||||
<div class="topbar-logo" aria-hidden="true">TK</div>
|
||||
<div>
|
||||
<h1>Wiki Newsletter Admin</h1>
|
||||
<p class="topbar-sub">Thomas-Krenn.AG · Intern</p>
|
||||
</div>
|
||||
</div>
|
||||
{% if user %}
|
||||
<form method="post" action="/logout">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
<div class="topbar-actions">
|
||||
<nav class="topbar-nav" aria-label="Hauptnavigation">
|
||||
<a href="/dashboard" class="{% if active_nav == 'dashboard' %}active{% endif %}">Dashboard</a>
|
||||
{% if user.role == "admin" %}
|
||||
<a href="/admin/users" class="{% if active_nav == 'users' %}active{% endif %}">Benutzer</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
<div class="user-chip">
|
||||
<span>{{ user.full_name }}</span>
|
||||
<span class="badge badge-{{ user.role }}">{{ user.role }}</span>
|
||||
</div>
|
||||
<form method="post" action="/logout">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<button type="submit" class="btn-logout">Abmelden</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</header>
|
||||
<main class="container">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
<footer class="site-footer">
|
||||
Thomas-Krenn.AG · Interner Wiki-Newsletter · Nur für den internen Gebrauch
|
||||
</footer>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,204 +1,301 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
{% block content %}
|
||||
<section class="card">
|
||||
<h2>Newsletter erstellen</h2>
|
||||
<form method="post" action="/dashboard" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<label>Zeitraum (Tage)
|
||||
<input type="number" name="days" min="1" max="90" value="{{ filters.days }}">
|
||||
</label>
|
||||
<label>Kategorie (optional)
|
||||
<input type="text" name="category" value="{{ filters.category }}">
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="only_edited" value="true" {% if filters.only_edited %}checked{% endif %}>
|
||||
Nur bearbeitete Artikel (keine neu erstellten)
|
||||
</label>
|
||||
<fieldset class="display-options">
|
||||
<legend>Anzeige im Output</legend>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="show_date" value="true" {% if filters.display.show_date %}checked{% endif %}>
|
||||
Datum anzeigen
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="show_user" value="true" {% if filters.display.show_user %}checked{% endif %}>
|
||||
Benutzer anzeigen
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="show_category" value="true" {% if filters.display.show_category %}checked{% endif %}>
|
||||
Kategorie anzeigen
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Wiki Newsletter</h2>
|
||||
<p class="page-lead">Wiki-Änderungen filtern, Newsletter generieren und für Outlook aufbereiten.</p>
|
||||
</div>
|
||||
|
||||
<div class="stats-row">
|
||||
<div class="stat-card accent-new">
|
||||
<div class="stat-value">{{ articles_new|length }}</div>
|
||||
<div class="stat-label">Neue Artikel</div>
|
||||
</div>
|
||||
<div class="stat-card accent-edit">
|
||||
<div class="stat-value">{{ articles_edited|length }}</div>
|
||||
<div class="stat-label">Bearbeitete Artikel</div>
|
||||
</div>
|
||||
<div class="stat-card accent-total">
|
||||
<div class="stat-value">{{ articles_new|length + articles_edited|length }}</div>
|
||||
<div class="stat-label">Gesamt</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layout-2col">
|
||||
<div class="main-col">
|
||||
|
||||
<section class="card card-accent-orange">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<h3>Newsletter erstellen</h3>
|
||||
<p class="card-desc">Zeitraum und Filter wählen, dann generieren.</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" action="/dashboard" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="form-row">
|
||||
<label>Zeitraum (Tage)
|
||||
<input type="number" name="days" min="1" max="90" value="{{ filters.days }}">
|
||||
</label>
|
||||
<label>Kategorie (optional)
|
||||
<input type="text" name="category" value="{{ filters.category }}" placeholder="z. B. Linux">
|
||||
</label>
|
||||
</div>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="only_edited" value="true" {% if filters.only_edited %}checked{% endif %}>
|
||||
Nur bearbeitete Artikel (keine neu erstellten)
|
||||
</label>
|
||||
<fieldset class="display-options">
|
||||
<legend>Anzeige im Newsletter</legend>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="show_date" value="true" {% if filters.display.show_date %}checked{% endif %}>
|
||||
Datum anzeigen
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="show_user" value="true" {% if filters.display.show_user %}checked{% endif %}>
|
||||
Benutzer anzeigen
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="show_category" value="true" {% if filters.display.show_category %}checked{% endif %}>
|
||||
Kategorie anzeigen
|
||||
</label>
|
||||
</fieldset>
|
||||
{% if wiki_error %}
|
||||
<p class="error">{{ wiki_error }}</p>
|
||||
{% endif %}
|
||||
{% if user.role in ["admin", "editor"] %}
|
||||
<button type="submit" class="btn-primary">Newsletter generieren</button>
|
||||
{% else %}
|
||||
<p class="hint">Sie haben Leserechte. Bitte einen Editor oder Admin bitten, den Newsletter zu generieren.</p>
|
||||
{% endif %}
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="card card-accent-orange">
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<h3>Vorschau & Export</h3>
|
||||
<p class="card-desc">Formatierten Newsletter ansehen und für Outlook kopieren.</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint"><strong>Empfohlen:</strong> „Im Browser öffnen“ → <strong>Strg+A</strong>, <strong>Strg+C</strong> → in Outlook <strong>Strg+V</strong>.</p>
|
||||
<div class="copy-actions">
|
||||
<button type="button" id="open-outlook-btn" class="btn-primary">Im Browser öffnen</button>
|
||||
<button type="button" id="copy-outlook-btn" class="btn-secondary">Für Outlook kopieren</button>
|
||||
<button type="button" id="download-html-btn" class="btn-secondary">HTML herunterladen</button>
|
||||
<button type="button" id="copy-html-source-btn" class="btn-outline">HTML-Quelltext</button>
|
||||
<span id="copy-status" class="copy-status" aria-live="polite"></span>
|
||||
</div>
|
||||
<iframe id="newsletter-preview-frame" class="newsletter-preview-frame" title="Newsletter Vorschau"></iframe>
|
||||
<textarea id="newsletter-html-source" class="hidden-source" hidden readonly>{{ raw_html }}</textarea>
|
||||
<textarea id="newsletter-outlook-source" class="hidden-source" hidden readonly>{{ outlook_html }}</textarea>
|
||||
<textarea id="newsletter-plain-source" class="hidden-source" hidden readonly>{{ plain_text }}</textarea>
|
||||
</section>
|
||||
|
||||
<section class="card card-accent-gray">
|
||||
<div class="card-header">
|
||||
<h3>Neue Artikel <span class="count-badge orange">{{ articles_new|length }}</span></h3>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titel</th>
|
||||
{% if filters.display.show_date %}<th>Zeit</th>{% endif %}
|
||||
{% if filters.display.show_user %}<th>Benutzer</th>{% endif %}
|
||||
{% if filters.display.show_category %}<th>Kategorien</th>{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in articles_new %}
|
||||
<tr>
|
||||
<td><a href="{{ wiki_article_url(item.title) }}" target="_blank" rel="noopener">{{ item.title }}</a></td>
|
||||
{% if filters.display.show_date %}<td>{{ item.timestamp }}</td>{% endif %}
|
||||
{% if filters.display.show_user %}<td>{{ item.user }}</td>{% endif %}
|
||||
{% if filters.display.show_category %}<td>{{ item.categories|join(", ") }}</td>{% endif %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="empty-row"><td colspan="4">Keine neuen Artikel im gewählten Zeitraum.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card card-accent-gray">
|
||||
<div class="card-header">
|
||||
<h3>Bearbeitete Artikel <span class="count-badge">{{ articles_edited|length }}</span></h3>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titel</th>
|
||||
{% if filters.display.show_date %}<th>Zeit</th>{% endif %}
|
||||
{% if filters.display.show_user %}<th>Benutzer</th>{% endif %}
|
||||
{% if filters.display.show_category %}<th>Kategorien</th>{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in articles_edited %}
|
||||
<tr>
|
||||
<td><a href="{{ wiki_article_url(item.title) }}" target="_blank" rel="noopener">{{ item.title }}</a></td>
|
||||
{% if filters.display.show_date %}<td>{{ item.timestamp }}</td>{% endif %}
|
||||
{% if filters.display.show_user %}<td>{{ item.user }}</td>{% endif %}
|
||||
{% if filters.display.show_category %}<td>{{ item.categories|join(", ") }}</td>{% endif %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="empty-row"><td colspan="4">Keine bearbeiteten Artikel im gewählten Zeitraum.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<details class="card-details">
|
||||
<summary>Weitere Ausgabeformate</summary>
|
||||
<div class="details-body">
|
||||
<h4 style="margin:1rem 0 0.5rem;font-size:0.95rem;">Nur-Text (Fallback)</h4>
|
||||
<p class="hint">URLs als Klartext – für klickbare Links die Vorschau nutzen.</p>
|
||||
<textarea class="readonly-output" rows="10" readonly>{{ plain_text }}</textarea>
|
||||
|
||||
<h4 style="margin:1.25rem 0 0.5rem;font-size:0.95rem;">HTML-Quelltext</h4>
|
||||
<p class="hint">Öffnet ein Fenster mit markiertem Text – dort <strong>Strg+C</strong> drücken.</p>
|
||||
<div class="textarea-actions">
|
||||
<button type="button" id="copy-html-source-btn-2" class="btn-secondary">HTML-Quelltext kopieren</button>
|
||||
<button type="button" id="download-html-source-btn" class="btn-outline">Herunterladen</button>
|
||||
</div>
|
||||
<textarea id="newsletter-html-display" class="readonly-output" rows="8" readonly>{{ raw_html }}</textarea>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{% if user.role in ["admin", "editor"] %}
|
||||
<button type="submit">Newsletter generieren</button>
|
||||
<details class="card-details">
|
||||
<summary>SMTP-Versand</summary>
|
||||
<div class="details-body">
|
||||
<p class="hint">Newsletter direkt per E-Mail versenden (aktuell gewählte Filter).</p>
|
||||
<form method="post" action="/newsletter/send-now">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="days" value="{{ filters.days }}">
|
||||
<input type="hidden" name="category" value="{{ filters.category }}">
|
||||
<input type="hidden" name="only_edited" value="{{ 'true' if filters.only_edited else 'false' }}">
|
||||
<input type="hidden" name="show_date" value="{{ 'true' if filters.display.show_date else 'false' }}">
|
||||
<input type="hidden" name="show_user" value="{{ 'true' if filters.display.show_user else 'false' }}">
|
||||
<input type="hidden" name="show_category" value="{{ 'true' if filters.display.show_category else 'false' }}">
|
||||
<button type="submit" class="btn-secondary">Newsletter jetzt senden</button>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if user.role == "admin" %}
|
||||
<p><a href="/admin/users">Zur Benutzerverwaltung</a></p>
|
||||
{% endif %}
|
||||
{% if wiki_error %}
|
||||
<p class="error">{{ wiki_error }}</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
{% if user.role in ["admin", "editor"] %}
|
||||
<section class="card">
|
||||
<h3>Optionaler SMTP-Versand</h3>
|
||||
<form method="post" action="/newsletter/send-now" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="days" value="{{ filters.days }}">
|
||||
<input type="hidden" name="category" value="{{ filters.category }}">
|
||||
<input type="hidden" name="only_edited" value="{{ 'true' if filters.only_edited else 'false' }}">
|
||||
<input type="hidden" name="show_date" value="{{ 'true' if filters.display.show_date else 'false' }}">
|
||||
<input type="hidden" name="show_user" value="{{ 'true' if filters.display.show_user else 'false' }}">
|
||||
<input type="hidden" name="show_category" value="{{ 'true' if filters.display.show_category else 'false' }}">
|
||||
<button type="submit">Newsletter jetzt senden</button>
|
||||
</form>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% if user.role == "admin" %}
|
||||
<details class="card-details">
|
||||
<summary>SMTP-Konfiguration</summary>
|
||||
<div class="details-body">
|
||||
<form method="post" action="/admin/smtp" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="enabled" value="true" {% if smtp.enabled == "true" %}checked{% endif %}>
|
||||
SMTP-Versand aktivieren
|
||||
</label>
|
||||
<div class="form-row">
|
||||
<label>SMTP-Host
|
||||
<input type="text" name="host" value="{{ smtp.host }}" placeholder="mail.example.com">
|
||||
</label>
|
||||
<label>SMTP-Port
|
||||
<input type="number" name="port" value="{{ smtp.port }}">
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Benutzername
|
||||
<input type="text" name="username" value="{{ smtp.username }}">
|
||||
</label>
|
||||
<label>Passwort
|
||||
<input type="password" name="password" value="{{ smtp.password }}">
|
||||
</label>
|
||||
</div>
|
||||
<label>Absender E-Mail
|
||||
<input type="email" name="from_email" value="{{ smtp.from_email }}">
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="use_tls" value="true" {% if smtp.use_tls == "true" %}checked{% endif %}>
|
||||
STARTTLS verwenden
|
||||
</label>
|
||||
<label>Verteilerliste (kommagetrennt)
|
||||
<textarea rows="3" name="recipients" placeholder="kollege@firma.de, team@firma.de">{{ smtp.recipients }}</textarea>
|
||||
</label>
|
||||
<label>Geplanter täglicher Versand (HH:MM)
|
||||
<input type="time" name="schedule_time" value="{{ smtp.schedule_time }}">
|
||||
</label>
|
||||
<button type="submit">Einstellungen speichern</button>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
||||
{% if user.role == "admin" %}
|
||||
<section class="card">
|
||||
<h3>SMTP-Konfiguration (optional)</h3>
|
||||
<form method="post" action="/admin/smtp" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="enabled" value="true" {% if smtp.enabled == "true" %}checked{% endif %}>
|
||||
SMTP Versand aktivieren
|
||||
</label>
|
||||
<label>SMTP Host
|
||||
<input type="text" name="host" value="{{ smtp.host }}">
|
||||
</label>
|
||||
<label>SMTP Port
|
||||
<input type="number" name="port" value="{{ smtp.port }}">
|
||||
</label>
|
||||
<label>Benutzername
|
||||
<input type="text" name="username" value="{{ smtp.username }}">
|
||||
</label>
|
||||
<label>Passwort
|
||||
<input type="password" name="password" value="{{ smtp.password }}">
|
||||
</label>
|
||||
<label>Absender E-Mail
|
||||
<input type="email" name="from_email" value="{{ smtp.from_email }}">
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="use_tls" value="true" {% if smtp.use_tls == "true" %}checked{% endif %}>
|
||||
STARTTLS verwenden
|
||||
</label>
|
||||
<label>Verteilerliste (Komma-separiert)
|
||||
<textarea rows="3" name="recipients">{{ smtp.recipients }}</textarea>
|
||||
</label>
|
||||
<label>Geplanter täglicher Versand (HH:MM)
|
||||
<input type="time" name="schedule_time" value="{{ smtp.schedule_time }}">
|
||||
</label>
|
||||
<button type="submit">SMTP Einstellungen speichern</button>
|
||||
</form>
|
||||
</section>
|
||||
{% endif %}
|
||||
<section class="card">
|
||||
<div class="card-header">
|
||||
<h3>Versandprotokoll</h3>
|
||||
<span class="hint" style="margin:0;">Letzte 20 Einträge</span>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Zeit</th><th>Status</th><th>Betreff</th><th>Empfänger</th><th>Details</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in send_logs %}
|
||||
<tr>
|
||||
<td>{{ log.created_at }}</td>
|
||||
<td><span class="badge badge-{{ log.status }}">{{ log.status }}</span></td>
|
||||
<td>{{ log.subject }}</td>
|
||||
<td>{{ log.recipients }}</td>
|
||||
<td>{{ log.detail }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="empty-row"><td colspan="5">Noch keine Versände protokolliert.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h3>Newsletter-Vorschau (mit Hyperlinks)</h3>
|
||||
<p class="hint"><strong>Empfohlen für Outlook:</strong> „Im Browser öffnen“ → dort <strong>Strg+A</strong>, <strong>Strg+C</strong> → in Outlook <strong>Strg+V</strong>. Alternativ „Für Outlook kopieren“ und mit Rechtsklick → „Format beibehalten“ einfügen.</p>
|
||||
<div class="copy-actions">
|
||||
<button type="button" id="open-outlook-btn" class="btn-secondary">Im Browser öffnen</button>
|
||||
<button type="button" id="copy-outlook-btn" class="btn-secondary">Für Outlook kopieren</button>
|
||||
<button type="button" id="copy-html-source-btn" class="btn-secondary">HTML-Quelltext kopieren</button>
|
||||
<button type="button" id="download-html-btn" class="btn-secondary">HTML herunterladen</button>
|
||||
<span id="copy-status" class="copy-status" aria-live="polite"></span>
|
||||
</div>
|
||||
<iframe id="newsletter-preview-frame" class="newsletter-preview-frame" title="Newsletter Vorschau"></iframe>
|
||||
<textarea id="newsletter-html-source" class="hidden-source" hidden readonly>{{ raw_html }}</textarea>
|
||||
<textarea id="newsletter-outlook-source" class="hidden-source" hidden readonly>{{ outlook_html }}</textarea>
|
||||
<textarea id="newsletter-plain-source" class="hidden-source" hidden readonly>{{ plain_text }}</textarea>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h3>Output: Nur-Text (Fallback)</h3>
|
||||
<p class="hint">Enthält URLs als Text. Für klickbare Links bitte die Vorschau bzw. „Für Outlook kopieren“ verwenden.</p>
|
||||
<textarea rows="16" readonly>{{ plain_text }}</textarea>
|
||||
</section>
|
||||
<aside class="sidebar-col">
|
||||
<div class="sidebar-card">
|
||||
<h4>Workflow</h4>
|
||||
<ol style="margin:0;padding-left:1.1rem;color:var(--tk-gray);">
|
||||
<li>Filter setzen</li>
|
||||
<li>Newsletter generieren</li>
|
||||
<li>Vorschau prüfen</li>
|
||||
<li>Für Outlook exportieren</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="sidebar-card">
|
||||
<h4>Outlook-Tipp</h4>
|
||||
<ul>
|
||||
<li>„Im Browser öffnen“ nutzen</li>
|
||||
<li>Alles markieren (Strg+A)</li>
|
||||
<li>Kopieren (Strg+C)</li>
|
||||
<li>In Outlook einfügen</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% if user.role == "admin" %}
|
||||
<div class="sidebar-card">
|
||||
<h4>Administration</h4>
|
||||
<ul>
|
||||
<li><a href="/admin/users">Benutzerverwaltung</a></li>
|
||||
<li>SMTP unter „SMTP-Konfiguration“</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<section class="card">
|
||||
<h3>Output: HTML-Quelltext</h3>
|
||||
<p class="hint">Öffnet ein Fenster mit markiertem Text – dort <strong>Strg+C</strong> drücken. Funktioniert auch ohne HTTPS.</p>
|
||||
<div class="textarea-actions">
|
||||
<button type="button" id="copy-html-source-btn-2" class="btn-secondary">HTML-Quelltext kopieren</button>
|
||||
<button type="button" id="download-html-source-btn" class="btn-secondary">HTML-Quelltext herunterladen</button>
|
||||
</div>
|
||||
<textarea id="newsletter-html-display" rows="12" readonly>{{ raw_html }}</textarea>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h3>Neue Artikel ({{ articles_new|length }})</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titel</th>
|
||||
{% if filters.display.show_date %}<th>Zeit</th>{% endif %}
|
||||
{% if filters.display.show_user %}<th>Benutzer</th>{% endif %}
|
||||
{% if filters.display.show_category %}<th>Kategorien</th>{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in articles_new %}
|
||||
<tr>
|
||||
<td><a href="{{ wiki_article_url(item.title) }}" target="_blank" rel="noopener">{{ item.title }}</a></td>
|
||||
{% if filters.display.show_date %}<td>{{ item.timestamp }}</td>{% endif %}
|
||||
{% if filters.display.show_user %}<td>{{ item.user }}</td>{% endif %}
|
||||
{% if filters.display.show_category %}<td>{{ item.categories|join(", ") }}</td>{% endif %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="4">Keine neuen Artikel im gewählten Zeitraum.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h3>Bearbeitete Artikel ({{ articles_edited|length }})</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titel</th>
|
||||
{% if filters.display.show_date %}<th>Zeit</th>{% endif %}
|
||||
{% if filters.display.show_user %}<th>Benutzer</th>{% endif %}
|
||||
{% if filters.display.show_category %}<th>Kategorien</th>{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in articles_edited %}
|
||||
<tr>
|
||||
<td><a href="{{ wiki_article_url(item.title) }}" target="_blank" rel="noopener">{{ item.title }}</a></td>
|
||||
{% if filters.display.show_date %}<td>{{ item.timestamp }}</td>{% endif %}
|
||||
{% if filters.display.show_user %}<td>{{ item.user }}</td>{% endif %}
|
||||
{% if filters.display.show_category %}<td>{{ item.categories|join(", ") }}</td>{% endif %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="4">Keine bearbeiteten Artikel im gewählten Zeitraum.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h3>Versandprotokoll (letzte 20)</h3>
|
||||
<table>
|
||||
<thead><tr><th>Zeit</th><th>Status</th><th>Betreff</th><th>Empfänger</th><th>Details</th></tr></thead>
|
||||
<tbody>
|
||||
{% for log in send_logs %}
|
||||
<tr>
|
||||
<td>{{ log.created_at }}</td>
|
||||
<td>{{ log.status }}</td>
|
||||
<td>{{ log.subject }}</td>
|
||||
<td>{{ log.recipients }}</td>
|
||||
<td>{{ log.detail }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/static/js/newsletter.js?v=5"></script>
|
||||
<script src="/static/js/newsletter.js?v=6"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Anmelden{% endblock %}
|
||||
{% block body_class %}login-page{% endblock %}
|
||||
{% block content %}
|
||||
<section class="card narrow">
|
||||
<h2>Login</h2>
|
||||
<section class="card login-card">
|
||||
<h2>Anmelden</h2>
|
||||
<p class="login-subtitle">Thomas-Krenn Wiki Newsletter Admin</p>
|
||||
{% if error_message %}
|
||||
<p class="error">{{ error_message }}</p>
|
||||
{% endif %}
|
||||
<form method="post" action="/login" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<label>E-Mail
|
||||
<input type="email" name="email" required>
|
||||
<input type="email" name="email" required autocomplete="username" placeholder="name@firma.de">
|
||||
</label>
|
||||
<label>Passwort
|
||||
<input type="password" name="password" required>
|
||||
<input type="password" name="password" required autocomplete="current-password">
|
||||
</label>
|
||||
<button type="submit">Anmelden</button>
|
||||
<button type="submit" class="btn-primary btn-block">Anmelden</button>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,43 +1,78 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Benutzerverwaltung{% endblock %}
|
||||
{% block content %}
|
||||
<section class="card">
|
||||
<h2>Benutzerverwaltung</h2>
|
||||
<form method="post" action="/admin/users" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<label>E-Mail
|
||||
<input type="email" name="email" required>
|
||||
</label>
|
||||
<label>Vollständiger Name
|
||||
<input type="text" name="full_name" required>
|
||||
</label>
|
||||
<label>Passwort
|
||||
<input type="password" name="password" required minlength="10">
|
||||
</label>
|
||||
<label>Rolle
|
||||
<select name="role">
|
||||
<option value="reader">Reader</option>
|
||||
<option value="editor">Editor</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</label>
|
||||
<button type="submit">Benutzer erstellen</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h3>Bestehende Benutzer</h3>
|
||||
<table>
|
||||
<thead><tr><th>E-Mail</th><th>Name</th><th>Rolle</th><th>Aktiv</th></tr></thead>
|
||||
<tbody>
|
||||
{% for u in users %}
|
||||
<tr>
|
||||
<td>{{ u.email }}</td>
|
||||
<td>{{ u.full_name }}</td>
|
||||
<td>{{ u.role }}</td>
|
||||
<td>{{ "Ja" if u.is_active else "Nein" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<div class="page-header">
|
||||
<h2>Benutzerverwaltung</h2>
|
||||
<p class="page-lead"><a href="/dashboard">← Zurück zum Dashboard</a></p>
|
||||
</div>
|
||||
|
||||
<div class="layout-2col">
|
||||
<div class="main-col">
|
||||
<section class="card card-accent-orange">
|
||||
<div class="card-header">
|
||||
<h3>Neuen Benutzer anlegen</h3>
|
||||
</div>
|
||||
<form method="post" action="/admin/users" class="form-grid">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<div class="form-row">
|
||||
<label>E-Mail
|
||||
<input type="email" name="email" required placeholder="name@firma.de">
|
||||
</label>
|
||||
<label>Vollständiger Name
|
||||
<input type="text" name="full_name" required>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label>Passwort
|
||||
<input type="password" name="password" required minlength="10">
|
||||
</label>
|
||||
<label>Rolle
|
||||
<select name="role">
|
||||
<option value="reader">Leser (nur ansehen)</option>
|
||||
<option value="editor">Editor (generieren & senden)</option>
|
||||
<option value="admin">Admin (voller Zugriff)</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<button type="submit" class="btn-primary">Benutzer erstellen</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<div class="card-header">
|
||||
<h3>Bestehende Benutzer <span class="count-badge">{{ users|length }}</span></h3>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>E-Mail</th><th>Name</th><th>Rolle</th><th>Status</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u in users %}
|
||||
<tr>
|
||||
<td>{{ u.email }}</td>
|
||||
<td>{{ u.full_name }}</td>
|
||||
<td><span class="badge badge-{{ u.role }}">{{ u.role }}</span></td>
|
||||
<td>{{ "Aktiv" if u.is_active else "Inaktiv" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<aside class="sidebar-col">
|
||||
<div class="sidebar-card">
|
||||
<h4>Rollen</h4>
|
||||
<ul>
|
||||
<li><strong>Leser</strong> – Newsletter ansehen</li>
|
||||
<li><strong>Editor</strong> – Generieren & senden</li>
|
||||
<li><strong>Admin</strong> – Benutzer & SMTP</li>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user