Allow to delete webmentions

This commit is contained in:
Thomas Sileo 2022-11-20 11:56:58 +01:00
parent d692ec060f
commit a435cd33c9
5 changed files with 77 additions and 1 deletions

View file

@ -11,6 +11,7 @@ from fastapi.exceptions import HTTPException
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from loguru import logger from loguru import logger
from sqlalchemy import and_ from sqlalchemy import and_
from sqlalchemy import delete
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy import or_ from sqlalchemy import or_
from sqlalchemy import select from sqlalchemy import select
@ -883,6 +884,42 @@ async def admin_actions_force_delete(
return RedirectResponse(redirect_url, status_code=302) return RedirectResponse(redirect_url, status_code=302)
@router.post("/actions/force_delete_webmention")
async def admin_actions_force_delete_webmention(
request: Request,
webmention_id: int = Form(),
redirect_url: str = Form(),
csrf_check: None = Depends(verify_csrf_token),
db_session: AsyncSession = Depends(get_db_session),
) -> RedirectResponse:
webmention = await boxes.get_webmention_by_id(db_session, webmention_id)
if not webmention:
raise ValueError(f"Cannot find {webmention_id}")
if not webmention.outbox_object:
raise ValueError(f"Missing related outbox object for {webmention_id}")
# TODO: move this
logger.info(f"Deleting {webmention_id}")
webmention.is_deleted = True
await db_session.flush()
from app.webmentions import _handle_webmention_side_effects
await _handle_webmention_side_effects(
db_session, webmention, webmention.outbox_object
)
# Delete related notifications
notif_deletion_result = await db_session.execute(
delete(models.Notification)
.where(models.Notification.webmention_id == webmention.id)
.execution_options(synchronize_session=False)
)
logger.info(
f"Deleted {notif_deletion_result.rowcount} notifications" # type: ignore
)
await db_session.commit()
return RedirectResponse(redirect_url, status_code=302)
@router.post("/actions/follow") @router.post("/actions/follow")
async def admin_actions_follow( async def admin_actions_follow(
request: Request, request: Request,

View file

@ -1088,6 +1088,20 @@ async def get_anybox_object_by_ap_id(
return await get_inbox_object_by_ap_id(db_session, ap_id) return await get_inbox_object_by_ap_id(db_session, ap_id)
async def get_webmention_by_id(
db_session: AsyncSession, webmention_id: int
) -> models.Webmention | None:
return (
await db_session.execute(
select(models.Webmention)
.where(models.Webmention.id == webmention_id)
.options(
joinedload(models.Webmention.outbox_object),
)
)
).scalar_one_or_none() # type: ignore
async def _handle_delete_activity( async def _handle_delete_activity(
db_session: AsyncSession, db_session: AsyncSession,
from_actor: models.Actor, from_actor: models.Actor,

View file

@ -142,6 +142,17 @@
{% endblock %} {% endblock %}
{% endmacro %} {% endmacro %}
{% macro admin_force_delete_webmention_button(webmention_id, permalink_id=None) %}
{% block admin_force_delete_webmention_button scoped %}
<form action="{{ request.url_for("admin_actions_force_delete_webmention") }}" class="object-delete-form" method="POST">
{{ embed_csrf_token() }}
{{ embed_redirect_url(permalink_id) }}
<input type="hidden" name="webmention_id" value="{{ webmention_id }}">
<input type="submit" value="local delete">
</form>
{% endblock %}
{% endmacro %}
{% macro admin_announce_button(ap_object_id, permalink_id=None) %} {% macro admin_announce_button(ap_object_id, permalink_id=None) %}
{% block admin_announce_button scoped %} {% block admin_announce_button scoped %}
<form action="{{ request.url_for("admin_actions_announce") }}" method="POST"> <form action="{{ request.url_for("admin_actions_announce") }}" method="POST">
@ -473,6 +484,11 @@
<li> <li>
<time class="dt-published" datetime="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}" title="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}">{{ wm_reply.published_at | timeago }}</time> <time class="dt-published" datetime="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}" title="{{ wm_reply.published_at.replace(microsecond=0).isoformat() }}">{{ wm_reply.published_at | timeago }}</time>
</li> </li>
{% if is_admin %}
<li>
{{ admin_force_delete_webmention_button(wm_reply.webmention_id) }}
</li>
{% endif %}
</ul> </ul>
</nav> </nav>
</div> </div>

View file

@ -125,6 +125,7 @@ class WebmentionReply:
url: str url: str
published_at: datetime.datetime published_at: datetime.datetime
in_reply_to: str in_reply_to: str
webmention_id: int
@classmethod @classmethod
def from_webmention(cls, webmention: Webmention) -> Optional["WebmentionReply"]: def from_webmention(cls, webmention: Webmention) -> Optional["WebmentionReply"]:
@ -147,6 +148,7 @@ class WebmentionReply:
item["properties"]["published"][0] item["properties"]["published"][0]
).replace(tzinfo=None), ).replace(tzinfo=None),
in_reply_to=webmention.target, # type: ignore in_reply_to=webmention.target, # type: ignore
webmention_id=webmention.id, # type: ignore
) )
except Exception: except Exception:
logger.exception( logger.exception(

View file

@ -8,6 +8,7 @@ from fastapi import HTTPException
from fastapi import Request from fastapi import Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from loguru import logger from loguru import logger
from sqlalchemy import func
from sqlalchemy import select from sqlalchemy import select
from app import models from app import models
@ -204,7 +205,13 @@ async def _handle_webmention_side_effects(
) -> None: ) -> None:
if webmention.webmention_type == models.WebmentionType.UNKNOWN: if webmention.webmention_type == models.WebmentionType.UNKNOWN:
# TODO: recount everything # TODO: recount everything
mentioned_object.webmentions_count = mentioned_object.webmentions_count + 1 mentioned_object.webmentions_count = await db_session.scalar(
select(func.count(models.Webmention.id)).where(
models.Webmention.is_deleted.is_(False),
models.Webmention.outbox_object_id == mentioned_object.id,
models.Webmention.webmention_type == models.WebmentionType.UNKNOWN,
)
)
elif webmention.webmention_type == models.WebmentionType.LIKE: elif webmention.webmention_type == models.WebmentionType.LIKE:
mentioned_object.likes_count = await _get_outbox_likes_count( mentioned_object.likes_count = await _get_outbox_likes_count(
db_session, mentioned_object db_session, mentioned_object