mirror of
				https://git.sr.ht/~tsileo/microblog.pub
				synced 2025-06-05 21:59:23 +02:00 
			
		
		
		
	Improve Delete handling
This commit is contained in:
		
							
								
								
									
										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."""
 | 
			
		||||
    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)
 | 
			
		||||
    return {
 | 
			
		||||
        follower.actor.shared_inbox_url or follower.actor.inbox_url  # type: ignore
 | 
			
		||||
        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,
 | 
			
		||||
    delete_activity: models.InboxObject,
 | 
			
		||||
    ap_object_to_delete: models.InboxObject | None,
 | 
			
		||||
    forwarded_by_actor: models.Actor | None,
 | 
			
		||||
) -> None:
 | 
			
		||||
    if ap_object_to_delete is None:
 | 
			
		||||
        logger.info(
 | 
			
		||||
@@ -731,33 +740,26 @@ async def _handle_delete_activity(
 | 
			
		||||
        )
 | 
			
		||||
        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}")
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    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(
 | 
			
		||||
    db_session: AsyncSession,
 | 
			
		||||
    delete_activity: models.InboxObject,
 | 
			
		||||
    deleted_ap_object: models.InboxObject,
 | 
			
		||||
    forwarded_by_actor: models.Actor | None,
 | 
			
		||||
) -> None:
 | 
			
		||||
    is_delete_needs_to_be_forwarded = False
 | 
			
		||||
 | 
			
		||||
    # Decrement the replies counter if needed
 | 
			
		||||
    if deleted_ap_object.in_reply_to:
 | 
			
		||||
        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.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(
 | 
			
		||||
                    update(models.OutboxObject)
 | 
			
		||||
                    .where(
 | 
			
		||||
@@ -782,6 +788,36 @@ async def _revert_side_effect_for_deleted_object(
 | 
			
		||||
                    .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(
 | 
			
		||||
    db_session: AsyncSession,
 | 
			
		||||
@@ -1222,12 +1258,15 @@ async def save_to_inbox(
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    raw_object_id = ap.get_id(raw_object)
 | 
			
		||||
    forwarded_by_actor = None
 | 
			
		||||
 | 
			
		||||
    # Ensure forwarded activities have a valid LD sig
 | 
			
		||||
    if sent_by_ap_actor_id != actor.ap_id:
 | 
			
		||||
        logger.info(
 | 
			
		||||
            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)):
 | 
			
		||||
            logger.warning(
 | 
			
		||||
                f"Failed to verify LD sig, fetching remote object {raw_object_id}"
 | 
			
		||||
@@ -1314,6 +1353,7 @@ async def save_to_inbox(
 | 
			
		||||
            actor,
 | 
			
		||||
            inbox_object,
 | 
			
		||||
            relates_to_inbox_object,
 | 
			
		||||
            forwarded_by_actor=forwarded_by_actor,
 | 
			
		||||
        )
 | 
			
		||||
    elif activity_ro.ap_type == "Follow":
 | 
			
		||||
        await _handle_follow_follow_activity(db_session, actor, inbox_object)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user