diff --git a/app/admin.py b/app/admin.py index f23c53e..f8d8fa3 100644 --- a/app/admin.py +++ b/app/admin.py @@ -427,6 +427,18 @@ async def admin_actions_follow( return RedirectResponse(redirect_url, status_code=302) +@router.post("/actions/delete") +async def admin_actions_delete( + request: Request, + ap_object_id: str = Form(), + redirect_url: str = Form(), + csrf_check: None = Depends(verify_csrf_token), + db_session: AsyncSession = Depends(get_db_session), +) -> RedirectResponse: + await boxes.send_delete(db_session, ap_object_id) + return RedirectResponse(redirect_url, status_code=302) + + @router.post("/actions/like") async def admin_actions_like( request: Request, diff --git a/app/boxes.py b/app/boxes.py index 37cdb0f..f00d04a 100644 --- a/app/boxes.py +++ b/app/boxes.py @@ -76,6 +76,39 @@ async def save_outbox_object( return outbox_object +async def send_delete(db_session: AsyncSession, ap_object_id: str) -> None: + outbox_object_to_delete = await get_outbox_object_by_ap_id(db_session, ap_object_id) + if not outbox_object_to_delete: + raise ValueError(f"{ap_object_id} not found in the outbox") + + delete_id = allocate_outbox_id() + delete = { + "@context": ap.AS_CTX, + "id": outbox_object_id(delete_id), + "type": "Delete", + "actor": ID, + "object": ap_object_id, + } + outbox_object = await save_outbox_object( + db_session, + delete_id, + delete, + relates_to_outbox_object_id=outbox_object_to_delete.id, + ) + if not outbox_object.id: + raise ValueError("Should never happen") + + outbox_object_to_delete.is_deleted = True + await db_session.commit() + + # Compute the original recipients + recipients = await _compute_recipients( + db_session, outbox_object_to_delete.ap_object + ) + for rcp in recipients: + await new_outgoing_activity(db_session, rcp, outbox_object.id) + + async def send_like(db_session: AsyncSession, ap_object_id: str) -> None: inbox_object = await get_inbox_object_by_ap_id(db_session, ap_object_id) if not inbox_object: diff --git a/app/outgoing_activities.py b/app/outgoing_activities.py index ed180de..3903132 100644 --- a/app/outgoing_activities.py +++ b/app/outgoing_activities.py @@ -99,8 +99,11 @@ def process_next_outgoing_activity(db: Session) -> bool: next_activity.last_try = now() payload = ap.wrap_object_if_needed(next_activity.outbox_object.ap_object) - if payload["type"] == "Create": + + # Use LD sig if the activity may need to be forwarded by recipients + if payload["type"] in ["Create", "Delete"]: ldsig.generate_signature(payload, k) + logger.info(f"{payload=}") try: resp = ap.post(next_activity.recipient, payload) diff --git a/app/templates/admin_outbox.html b/app/templates/admin_outbox.html index 51f1078..fcdbc20 100644 --- a/app/templates/admin_outbox.html +++ b/app/templates/admin_outbox.html @@ -16,6 +16,7 @@
You followed
{{ utils.display_actor(outbox_object.relates_to_actor, actors_metadata) }} {% elif outbox_object.ap_type in ["Article", "Note", "Video"] %} + {% if outbox_object.is_deleted %}Deleted{% endif %} {{ utils.display_object(outbox_object) }} {% else %} Implement {{ outbox_object.ap_type }} diff --git a/app/templates/utils.html b/app/templates/utils.html index 393fc0c..6e15c8c 100644 --- a/app/templates/utils.html +++ b/app/templates/utils.html @@ -60,6 +60,15 @@ {% endmacro %} +{% macro admin_delete_button(ap_object_id) %} +
+ {{ embed_csrf_token() }} + {{ embed_redirect_url() }} + + +
+{% endmacro %} + {% macro admin_announce_button(ap_object_id, disabled=False) %}
{{ embed_csrf_token() }} @@ -320,6 +329,9 @@ {% if is_admin %} +
+ {{ admin_delete_button(object.ap_id) }} +
{{ admin_reply_button(object.ap_id) }}