aboutsummaryrefslogtreecommitdiff
path: root/webmentions_ssg/templates/received.html
diff options
context:
space:
mode:
authorDennis Fink2026-08-10 23:28:03 +0200
committerDennis Fink2026-08-10 23:28:03 +0200
commitb3e12b975064f0873bdb4d2834cae75925387d6b (patch)
tree92a7ce50f9a3e2b0a49aa32addd9c7e35062d91e /webmentions_ssg/templates/received.html
parent5b39f70aa14cac635b6084170e9d0bd3f548b911 (diff)
downloadwebmentions-ssg-b3e12b975064f0873bdb4d2834cae75925387d6b.tar.gz
webmentions-ssg-b3e12b975064f0873bdb4d2834cae75925387d6b.zip
feat(core): add received webmention admin actions
Add authenticated delete and reverify actions to the received webmentions admin view and protect them with CSRF validation. Enable CSRF protection globally while exempting the public Webmention endpoint.
Diffstat (limited to '')
-rw-r--r--webmentions_ssg/templates/received.html97
1 files changed, 88 insertions, 9 deletions
diff --git a/webmentions_ssg/templates/received.html b/webmentions_ssg/templates/received.html
index ea74557..64f225e 100644
--- a/webmentions_ssg/templates/received.html
+++ b/webmentions_ssg/templates/received.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+{% from "bootstrap5/form.html" import render_form %}
{% from "bootstrap5/pagination.html" import render_pagination %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
@@ -16,16 +17,20 @@
<th scope="col">Received</th>
<th scope="col">Updated</th>
<th scope="col">Reason</th>
+ <th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{% for webmention in webmentions %}
- {% if webmention.status == "verified" %}
+ {% if webmention.status == "received" %}
+ {% set row_class = "table-info" %}
+ {% set display_status = "Pending" %}
+ {% elif webmention.status == "verifying" %}
+ {% set row_class = "table-warning" %}
+ {% set display_status = "Verifying" %}
+ {% elif webmention.status == "verified" %}
{% set row_class = "table-success" %}
{% set display_status = "Verified" %}
- {% elif webmention.status in ("received", "verifying") %}
- {% set row_class = "table-warning" %}
- {% set display_status = "Pending" %}
{% else %}
{% set row_class = "table-danger" %}
{% set display_status = "Declined" %}
@@ -51,19 +56,93 @@
</time>
</td>
<td>{{ webmention.failure_reason or "—" }}</td>
+ <td class="text-nowrap">
+ <button type="button"
+ class="btn btn-sm btn-primary"
+ data-bs-toggle="modal"
+ data-bs-target="#confirmation-modal"
+ data-action="{{ url_for('root.reverify_received_webmention', identifier=webmention.uuid, page=webmentions.page) }}"
+ data-title="Reverify webmention?"
+ data-message="The webmention will be fetched and verified again."
+ data-confirm-label="Reverify"
+ data-confirm-class="btn-primary">Reverify</button>
+ <button type="button"
+ class="btn btn-sm btn-danger"
+ data-bs-toggle="modal"
+ data-bs-target="#confirmation-modal"
+ data-action="{{ url_for('root.delete_received_webmention', identifier=webmention.uuid, page=webmentions.page) }}"
+ data-title="Delete webmention?"
+ data-message="This permanently deletes the webmention and cannot be undone."
+ data-confirm-label="Delete"
+ data-confirm-class="btn-danger">Delete</button>
+ </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if webmentions.pages > 1 %}
- <div class="mt-3">
- {{ render_pagination(webmentions,
- align="center",
- size="sm") }}
- </div>
+ <div class="mt-3">{{ render_pagination(webmentions) }}</div>
{% endif %}
+ <div class="modal fade"
+ id="confirmation-modal"
+ tabindex="-1"
+ aria-labelledby="confirmation-modal-title"
+ aria-hidden="true">
+ <div class="modal-dialog modal-dialog-centered">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h1 class="modal-title fs-5" id="confirmation-modal-title"></h1>
+ <button type="button"
+ class="btn-close"
+ data-bs-dismiss="modal"
+ aria-label="Close"></button>
+ </div>
+ <div class="modal-body">
+ <p id="confirmation-modal-message" class="mb-0"></p>
+ </div>
+ <div class="modal-footer">
+ {{ render_form(action_form,
+ id="confirmation-modal-form",
+ button_style="primary",
+ form_group_classes="mb-0") }}
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
+ </div>
+ </div>
+ </div>
+ </div>
{% else %}
<p class="text-body-secondary">No Webmentions have been received yet.</p>
{% endif %}
{% endblock %}
+{% block scripts %}
+ {{ super() }}
+ <script>
+ const confirmationModal = document.getElementById(
+ "confirmation-modal"
+ );
+
+ confirmationModal.addEventListener("show.bs.modal", (event) => {
+ const button = event.relatedTarget;
+
+ const form = confirmationModal.querySelector(
+ "#confirmation-modal-form"
+ );
+ const title = confirmationModal.querySelector(
+ "#confirmation-modal-title"
+ );
+ const message = confirmationModal.querySelector(
+ "#confirmation-modal-message"
+ );
+ const submit = form.querySelector("#submit");
+
+ form.action = button.dataset.action;
+
+ title.textContent = button.dataset.title;
+ message.textContent = button.dataset.message;
+
+ submit.value = button.dataset.confirmLabel;
+ submit.className = `btn ${button.dataset.confirmClass}`;
+ });
+ </script>
+{% endblock %}