Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Production moved from on-prem VM 249 (10.22.68.249) to OVH VPS (57.128.200.27, inpi-vps-waw01). Updated ALL documentation, slash commands, memory files, architecture docs, and deploy procedures. Added |local_time Jinja filter (UTC→Europe/Warsaw) and converted 155 .strftime() calls across 71 templates so timestamps display in Polish timezone regardless of server timezone. Also includes: created_by_id tracking, abort import fix, ICS calendar fix for missing end times, Pros Poland data cleanup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
231 lines
6.5 KiB
HTML
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('forum.admin_forum') }}">← 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] }}
|
|
• Utworzono: {{ topic.created_at|local_time('%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|local_time('%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] }}
|
|
• Utworzono: {{ reply.created_at|local_time('%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|local_time('%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 %}
|