- Extract comment templates into reusable partials (_comment.html, _comment_form.html, _comment_list.html, _reply_form.html, etc.) - Add HTMX progressive enhancement: inline form submission with partial responses, delta polling for live updates, form reset on success, success/moderation toast feedback - Integrate Cloudflare Turnstile for invisible bot protection: server-side token validation with hostname check, fail-closed on errors/timeouts, feature-flagged via TURNSTILE_SECRET_KEY env var - Auto-approve comments that pass Turnstile; keep manual approval as fallback when Turnstile is disabled (model default stays False) - Add CommentReaction model with UniqueConstraint for session-based anonymous reactions (heart/thumbs-up), toggle support, separate rate-limit bucket (20/min) - Add comment poll endpoint (GET /comments/poll/<id>/?after_id=N) for HTMX delta polling without duplicates - Update CSP middleware to allow challenges.cloudflare.com in script-src, connect-src, and frame-src - Self-host htmx.min.js (v2.0.4) to minimize CSP surface area - Add django-htmx middleware and requests to dependencies - Add Unapprove bulk action to Wagtail admin for moderation - Extend PII purge command to anonymize reaction session_key - Design refresh: neon glow avatars, solid hover shadows, gradient section header, cyan reply borders, grid-pattern empty state, neon-pink focus glow on form inputs - Add turnstile_site_key to template context via context processor - 18 new tests covering HTMX contracts, Turnstile success/failure/ timeout/hostname-mismatch, polling deltas, reaction toggle/dedup/ rate-limit, CSP headers, and PII purge extension Closes #43 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
54 lines
2.2 KiB
HTML
54 lines
2.2 KiB
HTML
{% extends 'wagtailadmin/bulk_actions/confirmation/base.html' %}
|
|
{% load i18n wagtailusers_tags wagtailadmin_tags %}
|
|
|
|
{% block titletag %}
|
|
{% if items|length == 1 %}
|
|
{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}Unapprove {{ snippet_type_name }}{% endblocktrans %} - {{ items.0.item }}
|
|
{% else %}
|
|
{% blocktrans trimmed with count=items|length|intcomma %}Unapprove {{ count }} comments{% endblocktrans %}
|
|
{% endif %}
|
|
{% endblock %}
|
|
|
|
{% block header %}
|
|
{% trans "Unapprove" as unapprove_str %}
|
|
{% if items|length == 1 %}
|
|
{% include "wagtailadmin/shared/header.html" with title=unapprove_str subtitle=items.0.item icon=header_icon only %}
|
|
{% else %}
|
|
{% include "wagtailadmin/shared/header.html" with title=unapprove_str subtitle=model_opts.verbose_name_plural|capfirst icon=header_icon only %}
|
|
{% endif %}
|
|
{% endblock header %}
|
|
|
|
{% block items_with_access %}
|
|
{% if items %}
|
|
{% if items|length == 1 %}
|
|
<p>{% blocktrans trimmed with snippet_type_name=model_opts.verbose_name %}Unapprove this {{ snippet_type_name }}?{% endblocktrans %}</p>
|
|
{% else %}
|
|
<p>{% blocktrans trimmed with count=items|length|intcomma %}Unapprove {{ count }} selected comments?{% endblocktrans %}</p>
|
|
<ul>
|
|
{% for snippet in items %}
|
|
<li><a href="{{ snippet.edit_url }}" target="_blank" rel="noreferrer">{{ snippet.item }}</a></li>
|
|
{% endfor %}
|
|
</ul>
|
|
{% endif %}
|
|
{% endif %}
|
|
{% endblock items_with_access %}
|
|
|
|
{% block items_with_no_access %}
|
|
{% if items_with_no_access|length == 1 %}
|
|
{% trans "You don't have permission to unapprove this comment" as no_access_msg %}
|
|
{% else %}
|
|
{% trans "You don't have permission to unapprove these comments" as no_access_msg %}
|
|
{% endif %}
|
|
{% include 'wagtailsnippets/bulk_actions/list_items_with_no_access.html' with items=items_with_no_access no_access_msg=no_access_msg %}
|
|
{% endblock items_with_no_access %}
|
|
|
|
{% block form_section %}
|
|
{% if items %}
|
|
{% trans "Yes, unapprove" as action_button_text %}
|
|
{% trans "No, go back" as no_action_button_text %}
|
|
{% include 'wagtailadmin/bulk_actions/confirmation/form.html' %}
|
|
{% else %}
|
|
{% include 'wagtailadmin/bulk_actions/confirmation/go_back.html' %}
|
|
{% endif %}
|
|
{% endblock form_section %}
|