Allow modules to delete rooms. (#15997)

* Allow user_id to be optional for room deletion

* Add module API method to delete a room

* Newsfile

Signed-off-by: Olivier Wilkinson (reivilibre) <oliverw@matrix.org>

* Don't worry about the case block=True && requester_user_id is None

---------

Signed-off-by: Olivier Wilkinson (reivilibre) <oliverw@matrix.org>
pull/16263/head
reivilibre 2023-09-06 10:50:07 +00:00 committed by GitHub
parent 4f1840a88a
commit 698f6fa250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 41 additions and 6 deletions

1
changelog.d/15997.misc Normal file
View File

@ -0,0 +1 @@
Allow modules to delete rooms.

View File

@ -713,7 +713,7 @@ class PaginationHandler:
self, self,
delete_id: str, delete_id: str,
room_id: str, room_id: str,
requester_user_id: str, requester_user_id: Optional[str],
new_room_user_id: Optional[str] = None, new_room_user_id: Optional[str] = None,
new_room_name: Optional[str] = None, new_room_name: Optional[str] = None,
message: Optional[str] = None, message: Optional[str] = None,
@ -732,6 +732,10 @@ class PaginationHandler:
requester_user_id: requester_user_id:
User who requested the action. Will be recorded as putting the room on the User who requested the action. Will be recorded as putting the room on the
blocking list. blocking list.
If None, the action was not manually requested but instead
triggered automatically, e.g. through a Synapse module
or some other policy.
MUST NOT be None if block=True.
new_room_user_id: new_room_user_id:
If set, a new room will be created with this user ID If set, a new room will be created with this user ID
as the creator and admin, and all users in the old room will be as the creator and admin, and all users in the old room will be
@ -818,7 +822,7 @@ class PaginationHandler:
def start_shutdown_and_purge_room( def start_shutdown_and_purge_room(
self, self,
room_id: str, room_id: str,
requester_user_id: str, requester_user_id: Optional[str],
new_room_user_id: Optional[str] = None, new_room_user_id: Optional[str] = None,
new_room_name: Optional[str] = None, new_room_name: Optional[str] = None,
message: Optional[str] = None, message: Optional[str] = None,
@ -833,6 +837,10 @@ class PaginationHandler:
requester_user_id: requester_user_id:
User who requested the action and put the room on the User who requested the action and put the room on the
blocking list. blocking list.
If None, the action was not manually requested but instead
triggered automatically, e.g. through a Synapse module
or some other policy.
MUST NOT be None if block=True.
new_room_user_id: new_room_user_id:
If set, a new room will be created with this user ID If set, a new room will be created with this user ID
as the creator and admin, and all users in the old room will be as the creator and admin, and all users in the old room will be

View File

@ -1787,7 +1787,7 @@ class RoomShutdownHandler:
async def shutdown_room( async def shutdown_room(
self, self,
room_id: str, room_id: str,
requester_user_id: str, requester_user_id: Optional[str],
new_room_user_id: Optional[str] = None, new_room_user_id: Optional[str] = None,
new_room_name: Optional[str] = None, new_room_name: Optional[str] = None,
message: Optional[str] = None, message: Optional[str] = None,
@ -1811,6 +1811,10 @@ class RoomShutdownHandler:
requester_user_id: requester_user_id:
User who requested the action and put the room on the User who requested the action and put the room on the
blocking list. blocking list.
If None, the action was not manually requested but instead
triggered automatically, e.g. through a Synapse module
or some other policy.
MUST NOT be None if block=True.
new_room_user_id: new_room_user_id:
If set, a new room will be created with this user ID If set, a new room will be created with this user ID
as the creator and admin, and all users in the old room will be as the creator and admin, and all users in the old room will be
@ -1863,6 +1867,10 @@ class RoomShutdownHandler:
# Action the block first (even if the room doesn't exist yet) # Action the block first (even if the room doesn't exist yet)
if block: if block:
if requester_user_id is None:
raise ValueError(
"shutdown_room: block=True not allowed when requester_user_id is None."
)
# This will work even if the room is already blocked, but that is # This will work even if the room is already blocked, but that is
# desirable in case the first attempt at blocking the room failed below. # desirable in case the first attempt at blocking the room failed below.
await self.store.block_room(room_id, requester_user_id) await self.store.block_room(room_id, requester_user_id)

View File

@ -1730,6 +1730,19 @@ class ModuleApi:
room_alias_str = room_alias.to_string() if room_alias else None room_alias_str = room_alias.to_string() if room_alias else None
return room_id, room_alias_str return room_id, room_alias_str
async def delete_room(self, room_id: str) -> None:
"""
Schedules the deletion of a room from Synapse's database.
If the room is already being deleted, this method does nothing.
This method does not wait for the room to be deleted.
Added in Synapse v1.89.0.
"""
# Future extensions to this method might want to e.g. allow use of `force_purge`.
# TODO In the future we should make sure this is persistent.
self._hs.get_pagination_handler().start_shutdown_and_purge_room(room_id, None)
async def set_displayname( async def set_displayname(
self, self,
user_id: UserID, user_id: UserID,

View File

@ -40,7 +40,7 @@ CHECK_VISIBILITY_CAN_BE_MODIFIED_CALLBACK = Callable[
[str, StateMap[EventBase], str], Awaitable[bool] [str, StateMap[EventBase], str], Awaitable[bool]
] ]
ON_NEW_EVENT_CALLBACK = Callable[[EventBase, StateMap[EventBase]], Awaitable] ON_NEW_EVENT_CALLBACK = Callable[[EventBase, StateMap[EventBase]], Awaitable]
CHECK_CAN_SHUTDOWN_ROOM_CALLBACK = Callable[[str, str], Awaitable[bool]] CHECK_CAN_SHUTDOWN_ROOM_CALLBACK = Callable[[Optional[str], str], Awaitable[bool]]
CHECK_CAN_DEACTIVATE_USER_CALLBACK = Callable[[str, bool], Awaitable[bool]] CHECK_CAN_DEACTIVATE_USER_CALLBACK = Callable[[str, bool], Awaitable[bool]]
ON_PROFILE_UPDATE_CALLBACK = Callable[[str, ProfileInfo, bool, bool], Awaitable] ON_PROFILE_UPDATE_CALLBACK = Callable[[str, ProfileInfo, bool, bool], Awaitable]
ON_USER_DEACTIVATION_STATUS_CHANGED_CALLBACK = Callable[[str, bool, bool], Awaitable] ON_USER_DEACTIVATION_STATUS_CHANGED_CALLBACK = Callable[[str, bool, bool], Awaitable]
@ -429,12 +429,17 @@ class ThirdPartyEventRulesModuleApiCallbacks:
"Failed to run module API callback %s: %s", callback, e "Failed to run module API callback %s: %s", callback, e
) )
async def check_can_shutdown_room(self, user_id: str, room_id: str) -> bool: async def check_can_shutdown_room(
self, user_id: Optional[str], room_id: str
) -> bool:
"""Intercept requests to shutdown a room. If `False` is returned, the """Intercept requests to shutdown a room. If `False` is returned, the
room must not be shut down. room must not be shut down.
Args: Args:
requester: The ID of the user requesting the shutdown. user_id: The ID of the user requesting the shutdown.
If no user ID is supplied, then the room is being shut down through
some mechanism other than a user's request, e.g. through a module's
request.
room_id: The ID of the room. room_id: The ID of the room.
""" """
for callback in self._check_can_shutdown_room_callbacks: for callback in self._check_can_shutdown_room_callbacks: