Allow to delete webmentions
parent
d692ec060f
commit
a435cd33c9
37
app/admin.py
37
app/admin.py
|
@ -11,6 +11,7 @@ from fastapi.exceptions import HTTPException
|
|||
from fastapi.responses import RedirectResponse
|
||||
from loguru import logger
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import delete
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import or_
|
||||
from sqlalchemy import select
|
||||
|
@ -883,6 +884,42 @@ async def admin_actions_force_delete(
|
|||
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")
|
||||
async def admin_actions_follow(
|
||||
request: Request,
|
||||
|
|
14
app/boxes.py
14
app/boxes.py
|
@ -1088,6 +1088,20 @@ async def get_anybox_object_by_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(
|
||||
db_session: AsyncSession,
|
||||
from_actor: models.Actor,
|
||||
|
|
|
@ -142,6 +142,17 @@
|
|||
{% endblock %}
|
||||
{% 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) %}
|
||||
{% block admin_announce_button scoped %}
|
||||
<form action="{{ request.url_for("admin_actions_announce") }}" method="POST">
|
||||
|
@ -473,6 +484,11 @@
|
|||
<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>
|
||||
</li>
|
||||
{% if is_admin %}
|
||||
<li>
|
||||
{{ admin_force_delete_webmention_button(wm_reply.webmention_id) }}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
@ -125,6 +125,7 @@ class WebmentionReply:
|
|||
url: str
|
||||
published_at: datetime.datetime
|
||||
in_reply_to: str
|
||||
webmention_id: int
|
||||
|
||||
@classmethod
|
||||
def from_webmention(cls, webmention: Webmention) -> Optional["WebmentionReply"]:
|
||||
|
@ -147,6 +148,7 @@ class WebmentionReply:
|
|||
item["properties"]["published"][0]
|
||||
).replace(tzinfo=None),
|
||||
in_reply_to=webmention.target, # type: ignore
|
||||
webmention_id=webmention.id, # type: ignore
|
||||
)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
|
|
|
@ -8,6 +8,7 @@ from fastapi import HTTPException
|
|||
from fastapi import Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from loguru import logger
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import select
|
||||
|
||||
from app import models
|
||||
|
@ -204,7 +205,13 @@ async def _handle_webmention_side_effects(
|
|||
) -> None:
|
||||
if webmention.webmention_type == models.WebmentionType.UNKNOWN:
|
||||
# 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:
|
||||
mentioned_object.likes_count = await _get_outbox_likes_count(
|
||||
db_session, mentioned_object
|
||||
|
|
Loading…
Reference in New Issue