mirror of
				https://git.sr.ht/~tsileo/microblog.pub
				synced 2025-06-05 21:59:23 +02:00 
			
		
		
		
	Improve Block support
This commit is contained in:
		
							
								
								
									
										12
									
								
								app/admin.py
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								app/admin.py
									
									
									
									
									
								
							| @@ -25,7 +25,9 @@ from app.actor import fetch_actor | ||||
| from app.actor import get_actors_metadata | ||||
| from app.boxes import get_inbox_object_by_ap_id | ||||
| from app.boxes import get_outbox_object_by_ap_id | ||||
| from app.boxes import send_block | ||||
| from app.boxes import send_follow | ||||
| from app.boxes import send_unblock | ||||
| from app.config import EMOJIS | ||||
| from app.config import generate_csrf_token | ||||
| from app.config import session_serializer | ||||
| @@ -340,6 +342,7 @@ async def admin_inbox( | ||||
|                 "Update", | ||||
|                 "Undo", | ||||
|                 "Read", | ||||
|                 "Reject", | ||||
|                 "Add", | ||||
|                 "Remove", | ||||
|                 "EmojiReact", | ||||
| @@ -868,10 +871,7 @@ async def admin_actions_block( | ||||
|     csrf_check: None = Depends(verify_csrf_token), | ||||
|     db_session: AsyncSession = Depends(get_db_session), | ||||
| ) -> RedirectResponse: | ||||
|     logger.info(f"Blocking {ap_actor_id}") | ||||
|     actor = await fetch_actor(db_session, ap_actor_id) | ||||
|     actor.is_blocked = True | ||||
|     await db_session.commit() | ||||
|     await send_block(db_session, ap_actor_id) | ||||
|     return RedirectResponse(redirect_url, status_code=302) | ||||
|  | ||||
|  | ||||
| @@ -884,9 +884,7 @@ async def admin_actions_unblock( | ||||
|     db_session: AsyncSession = Depends(get_db_session), | ||||
| ) -> RedirectResponse: | ||||
|     logger.info(f"Unblocking {ap_actor_id}") | ||||
|     actor = await fetch_actor(db_session, ap_actor_id) | ||||
|     actor.is_blocked = False | ||||
|     await db_session.commit() | ||||
|     await send_unblock(db_session, ap_actor_id) | ||||
|     return RedirectResponse(redirect_url, status_code=302) | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										113
									
								
								app/boxes.py
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								app/boxes.py
									
									
									
									
									
								
							| @@ -90,6 +90,87 @@ async def save_outbox_object( | ||||
|     return outbox_object | ||||
|  | ||||
|  | ||||
| async def send_unblock(db_session: AsyncSession, ap_actor_id: str) -> None: | ||||
|     actor = await fetch_actor(db_session, ap_actor_id) | ||||
|  | ||||
|     block_activity = ( | ||||
|         await db_session.scalars( | ||||
|             select(models.OutboxObject).where( | ||||
|                 models.OutboxObject.activity_object_ap_id == actor.ap_id, | ||||
|                 models.OutboxObject.is_deleted.is_(False), | ||||
|             ) | ||||
|         ) | ||||
|     ).one_or_none() | ||||
|     if not block_activity: | ||||
|         raise ValueError(f"No Block activity for {ap_actor_id}") | ||||
|  | ||||
|     await _send_undo(db_session, block_activity.ap_id) | ||||
|  | ||||
|     await db_session.commit() | ||||
|  | ||||
|  | ||||
| async def send_block(db_session: AsyncSession, ap_actor_id: str) -> None: | ||||
|     logger.info(f"Blocking {ap_actor_id}") | ||||
|     actor = await fetch_actor(db_session, ap_actor_id) | ||||
|     actor.is_blocked = True | ||||
|  | ||||
|     # 1. Unfollow the actor | ||||
|     following = ( | ||||
|         await db_session.scalars( | ||||
|             select(models.Following) | ||||
|             .options(joinedload(models.Following.outbox_object)) | ||||
|             .where( | ||||
|                 models.Following.ap_actor_id == actor.ap_id, | ||||
|             ) | ||||
|         ) | ||||
|     ).one_or_none() | ||||
|     if following: | ||||
|         await _send_undo(db_session, following.outbox_object.ap_id) | ||||
|  | ||||
|     # 2. If the blocked actor is a follower, reject the follow request | ||||
|     follower = ( | ||||
|         await db_session.scalars( | ||||
|             select(models.Follower) | ||||
|             .options(joinedload(models.Follower.inbox_object)) | ||||
|             .where( | ||||
|                 models.Follower.ap_actor_id == actor.ap_id, | ||||
|             ) | ||||
|         ) | ||||
|     ).one_or_none() | ||||
|     if follower: | ||||
|         await _send_reject(db_session, actor, follower.inbox_object) | ||||
|         await db_session.delete(follower) | ||||
|  | ||||
|     # 3. Send a block | ||||
|     block_id = allocate_outbox_id() | ||||
|     block = { | ||||
|         "@context": ap.AS_EXTENDED_CTX, | ||||
|         "id": outbox_object_id(block_id), | ||||
|         "type": "Block", | ||||
|         "actor": LOCAL_ACTOR.ap_id, | ||||
|         "object": actor.ap_id, | ||||
|     } | ||||
|     outbox_object = await save_outbox_object( | ||||
|         db_session, | ||||
|         block_id, | ||||
|         block, | ||||
|     ) | ||||
|     if not outbox_object.id: | ||||
|         raise ValueError("Should never happen") | ||||
|  | ||||
|     await new_outgoing_activity(db_session, actor.inbox_url, outbox_object.id) | ||||
|  | ||||
|     # 4. Create a notification | ||||
|     notif = models.Notification( | ||||
|         notification_type=models.NotificationType.BLOCK, | ||||
|         actor_id=actor.id, | ||||
|         outbox_object_id=outbox_object.id, | ||||
|     ) | ||||
|     db_session.add(notif) | ||||
|  | ||||
|     await db_session.commit() | ||||
|  | ||||
|  | ||||
| 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: | ||||
| @@ -266,7 +347,7 @@ async def _send_undo(db_session: AsyncSession, ap_object_id: str) -> None: | ||||
|     if not outbox_object_to_undo: | ||||
|         raise ValueError(f"{ap_object_id} not found in the outbox") | ||||
|  | ||||
|     if outbox_object_to_undo.ap_type not in ["Follow", "Like", "Announce"]: | ||||
|     if outbox_object_to_undo.ap_type not in ["Follow", "Like", "Announce", "Block"]: | ||||
|         raise ValueError( | ||||
|             f"Cannot build Undo for {outbox_object_to_undo.ap_type} activity" | ||||
|         ) | ||||
| @@ -339,6 +420,30 @@ async def _send_undo(db_session: AsyncSession, ap_object_id: str) -> None: | ||||
|         recipients = await _compute_recipients(db_session, outbox_object.ap_object) | ||||
|         for rcp in recipients: | ||||
|             await new_outgoing_activity(db_session, rcp, outbox_object.id) | ||||
|     elif outbox_object_to_undo.ap_type == "Block": | ||||
|         if not outbox_object_to_undo.activity_object_ap_id: | ||||
|             raise ValueError(f"Invalid block activity {outbox_object_to_undo.ap_id}") | ||||
|  | ||||
|         # Send the Undo to the blocked actor | ||||
|         blocked_actor = await fetch_actor( | ||||
|             db_session, outbox_object_to_undo.activity_object_ap_id | ||||
|         ) | ||||
|  | ||||
|         blocked_actor.is_blocked = False | ||||
|  | ||||
|         await new_outgoing_activity( | ||||
|             db_session, | ||||
|             blocked_actor.inbox_url,  # type: ignore | ||||
|             outbox_object.id, | ||||
|         ) | ||||
|  | ||||
|         notif = models.Notification( | ||||
|             notification_type=models.NotificationType.UNBLOCK, | ||||
|             actor_id=blocked_actor.id, | ||||
|             outbox_object_id=outbox_object.id, | ||||
|         ) | ||||
|         db_session.add(notif) | ||||
|  | ||||
|     else: | ||||
|         raise ValueError("Should never happen") | ||||
|  | ||||
| @@ -2034,8 +2139,10 @@ async def save_to_inbox( | ||||
|         await _process_transient_object(db_session, raw_object, actor) | ||||
|         return None | ||||
|  | ||||
|     if actor.is_blocked: | ||||
|         logger.warning("Actor {actor.ap_id} is blocked, ignoring object") | ||||
|     # If we just blocked an actor, we want to process any undo sent as side | ||||
|     # effects | ||||
|     if actor.is_blocked and ap.as_list(raw_object["type"])[0] != "Undo": | ||||
|         logger.warning(f"Actor {actor.ap_id} is blocked, ignoring object") | ||||
|         return None | ||||
|  | ||||
|     raw_object_id = ap.get_id(raw_object) | ||||
|   | ||||
| @@ -551,9 +551,14 @@ class NotificationType(str, enum.Enum): | ||||
|     UPDATED_WEBMENTION = "updated_webmention" | ||||
|     DELETED_WEBMENTION = "deleted_webmention" | ||||
|  | ||||
|     # incoming | ||||
|     BLOCKED = "blocked" | ||||
|     UNBLOCKED = "unblocked" | ||||
|  | ||||
|     # outgoing | ||||
|     BLOCK = "block" | ||||
|     UNBLOCK = "unblock" | ||||
|  | ||||
|  | ||||
| class Notification(Base): | ||||
|     __tablename__ = "notifications" | ||||
|   | ||||
| @@ -42,6 +42,12 @@ | ||||
|             {% elif notif.notification_type.value == "unblocked" %} | ||||
|                 {{ notif_actor_action(notif, "unblocked you") }} | ||||
|                 {{ utils.display_actor(notif.actor, actors_metadata) }} | ||||
|             {% elif notif.notification_type.value == "block" %} | ||||
|                 {{ notif_actor_action(notif, "was blocked") }} | ||||
|                 {{ utils.display_actor(notif.actor, actors_metadata) }} | ||||
|             {% elif notif.notification_type.value == "unblock" %} | ||||
|                 {{ notif_actor_action(notif, "was unblocked") }} | ||||
|                 {{ utils.display_actor(notif.actor, actors_metadata) }} | ||||
|             {%- elif notif.notification_type.value == "move" %} | ||||
|                 {# for move notif, the actor is the target and the inbox object the Move activity #} | ||||
|                 <div class="actor-action"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user