From f46ca7b74b3dae4e442f0fd2690d9aaaa4b6e21d Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 30 Nov 2020 13:27:12 +0000 Subject: [PATCH 1/3] Add `force_purge` option to delete-room admin api. --- changelog.d/8843.feature | 1 + docs/admin_api/rooms.md | 6 +++++- synapse/handlers/pagination.py | 17 +++++++++++------ synapse/rest/admin/rooms.py | 22 +++++++++++++++++----- 4 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 changelog.d/8843.feature diff --git a/changelog.d/8843.feature b/changelog.d/8843.feature new file mode 100644 index 000000000000..824d46d5aa5a --- /dev/null +++ b/changelog.d/8843.feature @@ -0,0 +1 @@ +Add `force_purge` option to delete-room admin api. diff --git a/docs/admin_api/rooms.md b/docs/admin_api/rooms.md index 0c05b0ed555c..004a802e175a 100644 --- a/docs/admin_api/rooms.md +++ b/docs/admin_api/rooms.md @@ -382,7 +382,7 @@ the new room. Users on other servers will be unaffected. The API is: -```json +``` POST /_synapse/admin/v1/rooms//delete ``` @@ -439,6 +439,10 @@ The following JSON body parameters are available: future attempts to join the room. Defaults to `false`. * `purge` - Optional. If set to `true`, it will remove all traces of the room from your database. Defaults to `true`. +* `force_purge` - Optional, and ignored unless `purge` is `true`. If set to `true`, it + will force a purge to go ahead even if there are local users still in the room. Do not + use this unless a regular `purge` operation fails, as it could leave those users' + clients in a confused state. The JSON body must not be empty. The body must be at least `{}`. diff --git a/synapse/handlers/pagination.py b/synapse/handlers/pagination.py index 426b58da9e49..eed738f3810c 100644 --- a/synapse/handlers/pagination.py +++ b/synapse/handlers/pagination.py @@ -299,17 +299,22 @@ def get_purge_status(self, purge_id: str) -> Optional[PurgeStatus]: """ return self._purges_by_id.get(purge_id) - async def purge_room(self, room_id: str) -> None: - """Purge the given room from the database""" + async def purge_room(self, room_id: str, force_purge: bool = False) -> None: + """Purge the given room from the database. + + Args: + room_id: room to be purged + force_purge: set true to skip checking for joined users. + """ with await self.pagination_lock.write(room_id): # check we know about the room await self.store.get_room_version_id(room_id) # first check that we have no users in this room - joined = await self.store.is_host_joined(room_id, self._server_name) - - if joined: - raise SynapseError(400, "Users are still joined to this room") + if not force_purge: + joined = await self.store.is_host_joined(room_id, self._server_name) + if joined: + raise SynapseError(400, "Users are still joined to this room") await self.storage.purge_events.purge_room(room_id) diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index 353151169abe..1b905e68b0a4 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -70,14 +70,18 @@ async def on_POST(self, request, room_id): class DeleteRoomRestServlet(RestServlet): - """Delete a room from server. It is a combination and improvement of - shut down and purge room. + """Delete a room from server. + + It is a combination and improvement of shutdown and purge room. + Shuts down a room by removing all local users from the room. Blocking all future invites and joins to the room is optional. + If desired any local aliases will be repointed to a new room - created by `new_room_user_id` and kicked users will be auto + created by `new_room_user_id` and kicked users will be auto- joined to the new room. - It will remove all trace of a room from the database. + + If 'purge' is true, it will remove all traces of a room from the database. """ PATTERNS = admin_patterns("/rooms/(?P[^/]+)/delete$") @@ -110,6 +114,14 @@ async def on_POST(self, request, room_id): Codes.BAD_JSON, ) + force_purge = content.get("force_purge", False) + if not isinstance(purge, bool): + raise SynapseError( + HTTPStatus.BAD_REQUEST, + "Param 'force_purge' must be a boolean, if given", + Codes.BAD_JSON, + ) + ret = await self.room_shutdown_handler.shutdown_room( room_id=room_id, new_room_user_id=content.get("new_room_user_id"), @@ -121,7 +133,7 @@ async def on_POST(self, request, room_id): # Purge room if purge: - await self.pagination_handler.purge_room(room_id) + await self.pagination_handler.purge_room(room_id, force=force_purge) return (200, ret) From 8fe717a69dadae3844723c01196ff7a2d446c812 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 30 Nov 2020 14:54:14 +0000 Subject: [PATCH 2/3] fix param name --- synapse/handlers/pagination.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/synapse/handlers/pagination.py b/synapse/handlers/pagination.py index eed738f3810c..5372753707f3 100644 --- a/synapse/handlers/pagination.py +++ b/synapse/handlers/pagination.py @@ -299,19 +299,19 @@ def get_purge_status(self, purge_id: str) -> Optional[PurgeStatus]: """ return self._purges_by_id.get(purge_id) - async def purge_room(self, room_id: str, force_purge: bool = False) -> None: + async def purge_room(self, room_id: str, force: bool = False) -> None: """Purge the given room from the database. Args: room_id: room to be purged - force_purge: set true to skip checking for joined users. + force: set true to skip checking for joined users. """ with await self.pagination_lock.write(room_id): # check we know about the room await self.store.get_room_version_id(room_id) # first check that we have no users in this room - if not force_purge: + if not force: joined = await self.store.is_host_joined(room_id, self._server_name) if joined: raise SynapseError(400, "Users are still joined to this room") From b24b64afca4e6e36a423c83b1094716cd2b71c87 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Mon, 30 Nov 2020 15:05:40 +0000 Subject: [PATCH 3/3] fix more --- synapse/rest/admin/rooms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index 1b905e68b0a4..25f89e4685f6 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -115,7 +115,7 @@ async def on_POST(self, request, room_id): ) force_purge = content.get("force_purge", False) - if not isinstance(purge, bool): + if not isinstance(force_purge, bool): raise SynapseError( HTTPStatus.BAD_REQUEST, "Param 'force_purge' must be a boolean, if given",