Improve Delete handling
parent
9d6a3ea3cf
commit
9c325674c6
78
app/boxes.py
78
app/boxes.py
|
@ -629,12 +629,20 @@ async def _get_followers(db_session: AsyncSession) -> list[models.Follower]:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _get_followers_recipients(db_session: AsyncSession) -> set[str]:
|
async def _get_followers_recipients(
|
||||||
|
db_session: AsyncSession,
|
||||||
|
skip_actors: list[models.Actor] | None = None,
|
||||||
|
) -> set[str]:
|
||||||
"""Returns all the recipients from the local follower collection."""
|
"""Returns all the recipients from the local follower collection."""
|
||||||
|
actor_ap_ids_to_skip = []
|
||||||
|
if skip_actors:
|
||||||
|
actor_ap_ids_to_skip = [actor.ap_id for actor in skip_actors]
|
||||||
|
|
||||||
followers = await _get_followers(db_session)
|
followers = await _get_followers(db_session)
|
||||||
return {
|
return {
|
||||||
follower.actor.shared_inbox_url or follower.actor.inbox_url # type: ignore
|
follower.actor.shared_inbox_url or follower.actor.inbox_url # type: ignore
|
||||||
for follower in followers
|
for follower in followers
|
||||||
|
if follower.actor.ap_id not in actor_ap_ids_to_skip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -715,6 +723,7 @@ async def _handle_delete_activity(
|
||||||
from_actor: models.Actor,
|
from_actor: models.Actor,
|
||||||
delete_activity: models.InboxObject,
|
delete_activity: models.InboxObject,
|
||||||
ap_object_to_delete: models.InboxObject | None,
|
ap_object_to_delete: models.InboxObject | None,
|
||||||
|
forwarded_by_actor: models.Actor | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if ap_object_to_delete is None:
|
if ap_object_to_delete is None:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
@ -731,33 +740,26 @@ async def _handle_delete_activity(
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# If it's a local replies, it was forwarded, so we also need to forward
|
|
||||||
# the Delete activity if possible
|
|
||||||
if (
|
|
||||||
delete_activity.has_ld_signature
|
|
||||||
and ap_object_to_delete.in_reply_to
|
|
||||||
and ap_object_to_delete.in_reply_to.startswith(BASE_URL)
|
|
||||||
):
|
|
||||||
logger.info("Forwarding Delete activity as it's a local reply")
|
|
||||||
recipients = await _get_followers_recipients(db_session)
|
|
||||||
for rcp in recipients:
|
|
||||||
await new_outgoing_activity(
|
|
||||||
db_session,
|
|
||||||
rcp,
|
|
||||||
outbox_object_id=None,
|
|
||||||
inbox_object_id=delete_activity.id,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.info(f"Deleting {ap_object_to_delete.ap_type}/{ap_object_to_delete.ap_id}")
|
logger.info(f"Deleting {ap_object_to_delete.ap_type}/{ap_object_to_delete.ap_id}")
|
||||||
|
await _revert_side_effect_for_deleted_object(
|
||||||
|
db_session,
|
||||||
|
delete_activity,
|
||||||
|
ap_object_to_delete,
|
||||||
|
forwarded_by_actor,
|
||||||
|
)
|
||||||
ap_object_to_delete.is_deleted = True
|
ap_object_to_delete.is_deleted = True
|
||||||
|
|
||||||
await _revert_side_effect_for_deleted_object(db_session, ap_object_to_delete)
|
await db_session.flush()
|
||||||
|
|
||||||
|
|
||||||
async def _revert_side_effect_for_deleted_object(
|
async def _revert_side_effect_for_deleted_object(
|
||||||
db_session: AsyncSession,
|
db_session: AsyncSession,
|
||||||
|
delete_activity: models.InboxObject,
|
||||||
deleted_ap_object: models.InboxObject,
|
deleted_ap_object: models.InboxObject,
|
||||||
|
forwarded_by_actor: models.Actor | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
is_delete_needs_to_be_forwarded = False
|
||||||
|
|
||||||
# Decrement the replies counter if needed
|
# Decrement the replies counter if needed
|
||||||
if deleted_ap_object.in_reply_to:
|
if deleted_ap_object.in_reply_to:
|
||||||
replied_object = await get_anybox_object_by_ap_id(
|
replied_object = await get_anybox_object_by_ap_id(
|
||||||
|
@ -766,6 +768,10 @@ async def _revert_side_effect_for_deleted_object(
|
||||||
)
|
)
|
||||||
if replied_object:
|
if replied_object:
|
||||||
if replied_object.is_from_outbox:
|
if replied_object.is_from_outbox:
|
||||||
|
# It's a local reply that was likely forwarded, the Delete
|
||||||
|
# also needs to be forwarded
|
||||||
|
is_delete_needs_to_be_forwarded = True
|
||||||
|
|
||||||
await db_session.execute(
|
await db_session.execute(
|
||||||
update(models.OutboxObject)
|
update(models.OutboxObject)
|
||||||
.where(
|
.where(
|
||||||
|
@ -782,6 +788,36 @@ async def _revert_side_effect_for_deleted_object(
|
||||||
.values(replies_count=models.InboxObject.replies_count - 1)
|
.values(replies_count=models.InboxObject.replies_count - 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Delete any Like/Announce
|
||||||
|
await db_session.execute(
|
||||||
|
update(models.OutboxObject)
|
||||||
|
.where(
|
||||||
|
models.OutboxObject.activity_object_ap_id == deleted_ap_object.ap_id,
|
||||||
|
)
|
||||||
|
.values(is_deleted=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
# If it's a local replies, it was forwarded, so we also need to forward
|
||||||
|
# the Delete activity if possible
|
||||||
|
if delete_activity.has_ld_signature and is_delete_needs_to_be_forwarded:
|
||||||
|
logger.info("Forwarding Delete activity as it's a local reply")
|
||||||
|
|
||||||
|
# Don't forward to the forwarding actor and the original Delete actor
|
||||||
|
skip_actors = [delete_activity.actor]
|
||||||
|
if forwarded_by_actor:
|
||||||
|
skip_actors.append(forwarded_by_actor)
|
||||||
|
recipients = await _get_followers_recipients(
|
||||||
|
db_session,
|
||||||
|
skip_actors=skip_actors,
|
||||||
|
)
|
||||||
|
for rcp in recipients:
|
||||||
|
await new_outgoing_activity(
|
||||||
|
db_session,
|
||||||
|
rcp,
|
||||||
|
outbox_object_id=None,
|
||||||
|
inbox_object_id=delete_activity.id,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _handle_follow_follow_activity(
|
async def _handle_follow_follow_activity(
|
||||||
db_session: AsyncSession,
|
db_session: AsyncSession,
|
||||||
|
@ -1222,12 +1258,15 @@ async def save_to_inbox(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
raw_object_id = ap.get_id(raw_object)
|
raw_object_id = ap.get_id(raw_object)
|
||||||
|
forwarded_by_actor = None
|
||||||
|
|
||||||
# Ensure forwarded activities have a valid LD sig
|
# Ensure forwarded activities have a valid LD sig
|
||||||
if sent_by_ap_actor_id != actor.ap_id:
|
if sent_by_ap_actor_id != actor.ap_id:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Processing a forwarded activity {sent_by_ap_actor_id=}/{actor.ap_id}"
|
f"Processing a forwarded activity {sent_by_ap_actor_id=}/{actor.ap_id}"
|
||||||
)
|
)
|
||||||
|
forwarded_by_actor = await fetch_actor(db_session, sent_by_ap_actor_id)
|
||||||
|
|
||||||
if not (await ldsig.verify_signature(db_session, raw_object)):
|
if not (await ldsig.verify_signature(db_session, raw_object)):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Failed to verify LD sig, fetching remote object {raw_object_id}"
|
f"Failed to verify LD sig, fetching remote object {raw_object_id}"
|
||||||
|
@ -1314,6 +1353,7 @@ async def save_to_inbox(
|
||||||
actor,
|
actor,
|
||||||
inbox_object,
|
inbox_object,
|
||||||
relates_to_inbox_object,
|
relates_to_inbox_object,
|
||||||
|
forwarded_by_actor=forwarded_by_actor,
|
||||||
)
|
)
|
||||||
elif activity_ro.ap_type == "Follow":
|
elif activity_ro.ap_type == "Follow":
|
||||||
await _handle_follow_follow_activity(db_session, actor, inbox_object)
|
await _handle_follow_follow_activity(db_session, actor, inbox_object)
|
||||||
|
|
Loading…
Reference in New Issue