nordabiz/templates/admin/forum_deleted.html
Maciej Pienczyn f22342ea37 feat: Add forum modernization with reactions, subscriptions, and moderation
- Add edit tracking (24h limit), soft delete, and JSONB reactions to ForumTopic/ForumReply
- Create ForumTopicSubscription, ForumReport, ForumEditHistory models
- Add 15 new API endpoints for user actions and admin moderation
- Implement reactions (👍❤️🎉), topic subscriptions, content reporting
- Add solution marking, restore deleted content, edit history for admins
- Create forum_reports.html and forum_deleted.html admin templates
- Integrate notifications for replies, reactions, solutions, and reports
- Add SQL migration 024_forum_modernization.sql

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 18:55:40 +01:00

231 lines
6.5 KiB
HTML

{% extends "base.html" %}
{% block title %}Usunięte Treści Forum - Norda Biznes Partner{% endblock %}
{% block extra_css %}
<style>
.admin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-xl);
}
.admin-header h1 {
font-size: var(--font-size-3xl);
color: var(--text-primary);
}
.section {
background: var(--surface);
padding: var(--spacing-xl);
border-radius: var(--radius-lg);
box-shadow: var(--shadow);
margin-bottom: var(--spacing-xl);
}
.section h2 {
font-size: var(--font-size-xl);
margin-bottom: var(--spacing-lg);
color: var(--text-primary);
border-bottom: 2px solid var(--border);
padding-bottom: var(--spacing-sm);
}
.deleted-item {
padding: var(--spacing-lg);
border: 1px dashed #fecaca;
border-radius: var(--radius);
background: #fef2f2;
margin-bottom: var(--spacing-md);
}
.deleted-item:last-child {
margin-bottom: 0;
}
.deleted-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: var(--spacing-md);
}
.deleted-meta {
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
.deleted-content {
color: var(--text-primary);
margin-bottom: var(--spacing-md);
}
.deleted-info {
font-size: var(--font-size-sm);
color: #dc2626;
font-style: italic;
}
.btn-restore {
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius);
font-size: var(--font-size-sm);
cursor: pointer;
border: 1px solid #86efac;
background: #dcfce7;
color: #166534;
transition: all 0.2s;
}
.btn-restore:hover {
background: #bbf7d0;
}
.empty-state {
text-align: center;
padding: var(--spacing-xl);
color: var(--text-secondary);
}
.back-link {
margin-bottom: var(--spacing-lg);
}
.back-link a {
color: var(--text-secondary);
text-decoration: none;
}
.back-link a:hover {
color: var(--primary);
}
</style>
{% endblock %}
{% block content %}
<div class="back-link">
<a href="{{ url_for('admin_forum') }}">&larr; Powrót do moderacji forum</a>
</div>
<div class="admin-header">
<h1>Usunięte Treści Forum</h1>
</div>
<div class="section">
<h2>Usunięte Tematy ({{ deleted_topics|length }})</h2>
{% if deleted_topics %}
{% for topic in deleted_topics %}
<div class="deleted-item" id="topic-{{ topic.id }}">
<div class="deleted-header">
<div>
<strong>{{ topic.title }}</strong>
<div class="deleted-meta">
Autor: {{ topic.author.name or topic.author.email.split('@')[0] }}
&bull; Utworzono: {{ topic.created_at.strftime('%d.%m.%Y %H:%M') }}
</div>
</div>
<button class="btn-restore" onclick="restoreTopic({{ topic.id }})">
↩ Przywróć
</button>
</div>
<div class="deleted-content">
{{ topic.content[:300] }}{% if topic.content|length > 300 %}...{% endif %}
</div>
<div class="deleted-info">
Usunięto: {{ topic.deleted_at.strftime('%d.%m.%Y %H:%M') if topic.deleted_at else 'brak daty' }}
{% if topic.deleter %}przez {{ topic.deleter.name or topic.deleter.email.split('@')[0] }}{% endif %}
</div>
</div>
{% endfor %}
{% else %}
<div class="empty-state">
Brak usuniętych tematów.
</div>
{% endif %}
</div>
<div class="section">
<h2>Usunięte Odpowiedzi ({{ deleted_replies|length }})</h2>
{% if deleted_replies %}
{% for reply in deleted_replies %}
<div class="deleted-item" id="reply-{{ reply.id }}">
<div class="deleted-header">
<div>
<div class="deleted-meta">
W temacie: <a href="{{ url_for('forum_topic', topic_id=reply.topic_id) }}" target="_blank">{{ reply.topic.title }}</a>
<br>Autor: {{ reply.author.name or reply.author.email.split('@')[0] }}
&bull; Utworzono: {{ reply.created_at.strftime('%d.%m.%Y %H:%M') }}
</div>
</div>
<button class="btn-restore" onclick="restoreReply({{ reply.id }})">
↩ Przywróć
</button>
</div>
<div class="deleted-content">
{{ reply.content[:300] }}{% if reply.content|length > 300 %}...{% endif %}
</div>
<div class="deleted-info">
Usunięto: {{ reply.deleted_at.strftime('%d.%m.%Y %H:%M') if reply.deleted_at else 'brak daty' }}
{% if reply.deleter %}przez {{ reply.deleter.name or reply.deleter.email.split('@')[0] }}{% endif %}
</div>
</div>
{% endfor %}
{% else %}
<div class="empty-state">
Brak usuniętych odpowiedzi.
</div>
{% endif %}
</div>
{% endblock %}
{% block extra_js %}
function restoreTopic(topicId) {
if (!confirm('Przywrócić ten temat?')) return;
fetch(`/admin/forum/topic/${topicId}/restore`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token() }}'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('topic-' + topicId).remove();
} else {
alert(data.error || 'Błąd');
}
})
.catch(err => {
alert('Błąd połączenia');
});
}
function restoreReply(replyId) {
if (!confirm('Przywrócić tę odpowiedź?')) return;
fetch(`/admin/forum/reply/${replyId}/restore`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token() }}'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('reply-' + replyId).remove();
} else {
alert(data.error || 'Błąd');
}
})
.catch(err => {
alert('Błąd połączenia');
});
}
{% endblock %}