Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 0085dc5

Browse files
authored
Delete room endpoint (#9889)
Support the delete of a room through DELETE request and mark previous request as deprecated through documentation. Signed-off-by: Thibault Ferrante <[email protected]>
1 parent 8025602 commit 0085dc5

File tree

5 files changed

+128
-64
lines changed

5 files changed

+128
-64
lines changed

changelog.d/9889.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for `DELETE /_synapse/admin/v1/rooms/<room_id>`.

changelog.d/9889.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Mark as deprecated `POST /_synapse/admin/v1/rooms/<room_id>/delete`.

docs/admin_api/rooms.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ the new room. Users on other servers will be unaffected.
427427
The API is:
428428

429429
```
430-
POST /_synapse/admin/v1/rooms/<room_id>/delete
430+
DELETE /_synapse/admin/v1/rooms/<room_id>
431431
```
432432

433433
with a body of:
@@ -528,6 +528,15 @@ You will have to manually handle, if you so choose, the following:
528528
* Users that would have been booted from the room (and will have been force-joined to the Content Violation room).
529529
* Removal of the Content Violation room if desired.
530530

531+
## Deprecated endpoint
532+
533+
The previous deprecated API will be removed in a future release, it was:
534+
535+
```
536+
POST /_synapse/admin/v1/rooms/<room_id>/delete
537+
```
538+
539+
It behaves the same way than the current endpoint except the path and the method.
531540

532541
# Make Room Admin API
533542

synapse/rest/admin/rooms.py

Lines changed: 90 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@
3737
from synapse.util import json_decoder
3838

3939
if TYPE_CHECKING:
40+
from synapse.api.auth import Auth
41+
from synapse.handlers.pagination import PaginationHandler
42+
from synapse.handlers.room import RoomShutdownHandler
4043
from synapse.server import HomeServer
4144

42-
4345
logger = logging.getLogger(__name__)
4446

4547

@@ -146,50 +148,14 @@ def __init__(self, hs: "HomeServer"):
146148
async def on_POST(
147149
self, request: SynapseRequest, room_id: str
148150
) -> Tuple[int, JsonDict]:
149-
requester = await self.auth.get_user_by_req(request)
150-
await assert_user_is_admin(self.auth, requester.user)
151-
152-
content = parse_json_object_from_request(request)
153-
154-
block = content.get("block", False)
155-
if not isinstance(block, bool):
156-
raise SynapseError(
157-
HTTPStatus.BAD_REQUEST,
158-
"Param 'block' must be a boolean, if given",
159-
Codes.BAD_JSON,
160-
)
161-
162-
purge = content.get("purge", True)
163-
if not isinstance(purge, bool):
164-
raise SynapseError(
165-
HTTPStatus.BAD_REQUEST,
166-
"Param 'purge' must be a boolean, if given",
167-
Codes.BAD_JSON,
168-
)
169-
170-
force_purge = content.get("force_purge", False)
171-
if not isinstance(force_purge, bool):
172-
raise SynapseError(
173-
HTTPStatus.BAD_REQUEST,
174-
"Param 'force_purge' must be a boolean, if given",
175-
Codes.BAD_JSON,
176-
)
177-
178-
ret = await self.room_shutdown_handler.shutdown_room(
179-
room_id=room_id,
180-
new_room_user_id=content.get("new_room_user_id"),
181-
new_room_name=content.get("room_name"),
182-
message=content.get("message"),
183-
requester_user_id=requester.user.to_string(),
184-
block=block,
151+
return await _delete_room(
152+
request,
153+
room_id,
154+
self.auth,
155+
self.room_shutdown_handler,
156+
self.pagination_handler,
185157
)
186158

187-
# Purge room
188-
if purge:
189-
await self.pagination_handler.purge_room(room_id, force=force_purge)
190-
191-
return (200, ret)
192-
193159

194160
class ListRoomRestServlet(RestServlet):
195161
"""
@@ -282,7 +248,22 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
282248

283249

284250
class RoomRestServlet(RestServlet):
285-
"""Get room details.
251+
"""Manage a room.
252+
253+
On GET : Get details of a room.
254+
255+
On DELETE : Delete a room from server.
256+
257+
It is a combination and improvement of shutdown and purge room.
258+
259+
Shuts down a room by removing all local users from the room.
260+
Blocking all future invites and joins to the room is optional.
261+
262+
If desired any local aliases will be repointed to a new room
263+
created by `new_room_user_id` and kicked users will be auto-
264+
joined to the new room.
265+
266+
If 'purge' is true, it will remove all traces of a room from the database.
286267
287268
TODO: Add on_POST to allow room creation without joining the room
288269
"""
@@ -293,6 +274,8 @@ def __init__(self, hs: "HomeServer"):
293274
self.hs = hs
294275
self.auth = hs.get_auth()
295276
self.store = hs.get_datastore()
277+
self.room_shutdown_handler = hs.get_room_shutdown_handler()
278+
self.pagination_handler = hs.get_pagination_handler()
296279

297280
async def on_GET(
298281
self, request: SynapseRequest, room_id: str
@@ -308,6 +291,17 @@ async def on_GET(
308291

309292
return (200, ret)
310293

294+
async def on_DELETE(
295+
self, request: SynapseRequest, room_id: str
296+
) -> Tuple[int, JsonDict]:
297+
return await _delete_room(
298+
request,
299+
room_id,
300+
self.auth,
301+
self.room_shutdown_handler,
302+
self.pagination_handler,
303+
)
304+
311305

312306
class RoomMembersRestServlet(RestServlet):
313307
"""
@@ -694,3 +688,55 @@ async def on_GET(
694688
)
695689

696690
return 200, results
691+
692+
693+
async def _delete_room(
694+
request: SynapseRequest,
695+
room_id: str,
696+
auth: "Auth",
697+
room_shutdown_handler: "RoomShutdownHandler",
698+
pagination_handler: "PaginationHandler",
699+
) -> Tuple[int, JsonDict]:
700+
requester = await auth.get_user_by_req(request)
701+
await assert_user_is_admin(auth, requester.user)
702+
703+
content = parse_json_object_from_request(request)
704+
705+
block = content.get("block", False)
706+
if not isinstance(block, bool):
707+
raise SynapseError(
708+
HTTPStatus.BAD_REQUEST,
709+
"Param 'block' must be a boolean, if given",
710+
Codes.BAD_JSON,
711+
)
712+
713+
purge = content.get("purge", True)
714+
if not isinstance(purge, bool):
715+
raise SynapseError(
716+
HTTPStatus.BAD_REQUEST,
717+
"Param 'purge' must be a boolean, if given",
718+
Codes.BAD_JSON,
719+
)
720+
721+
force_purge = content.get("force_purge", False)
722+
if not isinstance(force_purge, bool):
723+
raise SynapseError(
724+
HTTPStatus.BAD_REQUEST,
725+
"Param 'force_purge' must be a boolean, if given",
726+
Codes.BAD_JSON,
727+
)
728+
729+
ret = await room_shutdown_handler.shutdown_room(
730+
room_id=room_id,
731+
new_room_user_id=content.get("new_room_user_id"),
732+
new_room_name=content.get("room_name"),
733+
message=content.get("message"),
734+
requester_user_id=requester.user.to_string(),
735+
block=block,
736+
)
737+
738+
# Purge room
739+
if purge:
740+
await pagination_handler.purge_room(room_id, force=force_purge)
741+
742+
return (200, ret)

tests/rest/admin/test_room.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from typing import List, Optional
1818
from unittest.mock import Mock
1919

20+
from parameterized import parameterized_class
21+
2022
import synapse.rest.admin
2123
from synapse.api.constants import EventTypes, Membership
2224
from synapse.api.errors import Codes
@@ -144,6 +146,13 @@ def _assert_peek(self, room_id, expect_code):
144146
)
145147

146148

149+
@parameterized_class(
150+
("method", "url_template"),
151+
[
152+
("POST", "/_synapse/admin/v1/rooms/%s/delete"),
153+
("DELETE", "/_synapse/admin/v1/rooms/%s"),
154+
],
155+
)
147156
class DeleteRoomTestCase(unittest.HomeserverTestCase):
148157
servlets = [
149158
synapse.rest.admin.register_servlets,
@@ -175,15 +184,15 @@ def prepare(self, reactor, clock, hs):
175184
self.room_id = self.helper.create_room_as(
176185
self.other_user, tok=self.other_user_tok
177186
)
178-
self.url = "/_synapse/admin/v1/rooms/%s/delete" % self.room_id
187+
self.url = self.url_template % self.room_id
179188

180189
def test_requester_is_no_admin(self):
181190
"""
182191
If the user is not a server admin, an error 403 is returned.
183192
"""
184193

185194
channel = self.make_request(
186-
"POST",
195+
self.method,
187196
self.url,
188197
json.dumps({}),
189198
access_token=self.other_user_tok,
@@ -196,10 +205,10 @@ def test_room_does_not_exist(self):
196205
"""
197206
Check that unknown rooms/server return error 404.
198207
"""
199-
url = "/_synapse/admin/v1/rooms/!unknown:test/delete"
208+
url = self.url_template % "!unknown:test"
200209

201210
channel = self.make_request(
202-
"POST",
211+
self.method,
203212
url,
204213
json.dumps({}),
205214
access_token=self.admin_user_tok,
@@ -212,10 +221,10 @@ def test_room_is_not_valid(self):
212221
"""
213222
Check that invalid room names, return an error 400.
214223
"""
215-
url = "/_synapse/admin/v1/rooms/invalidroom/delete"
224+
url = self.url_template % "invalidroom"
216225

217226
channel = self.make_request(
218-
"POST",
227+
self.method,
219228
url,
220229
json.dumps({}),
221230
access_token=self.admin_user_tok,
@@ -234,7 +243,7 @@ def test_new_room_user_does_not_exist(self):
234243
body = json.dumps({"new_room_user_id": "@unknown:test"})
235244

236245
channel = self.make_request(
237-
"POST",
246+
self.method,
238247
self.url,
239248
content=body.encode(encoding="utf_8"),
240249
access_token=self.admin_user_tok,
@@ -253,7 +262,7 @@ def test_new_room_user_is_not_local(self):
253262
body = json.dumps({"new_room_user_id": "@not:exist.bla"})
254263

255264
channel = self.make_request(
256-
"POST",
265+
self.method,
257266
self.url,
258267
content=body.encode(encoding="utf_8"),
259268
access_token=self.admin_user_tok,
@@ -272,7 +281,7 @@ def test_block_is_not_bool(self):
272281
body = json.dumps({"block": "NotBool"})
273282

274283
channel = self.make_request(
275-
"POST",
284+
self.method,
276285
self.url,
277286
content=body.encode(encoding="utf_8"),
278287
access_token=self.admin_user_tok,
@@ -288,7 +297,7 @@ def test_purge_is_not_bool(self):
288297
body = json.dumps({"purge": "NotBool"})
289298

290299
channel = self.make_request(
291-
"POST",
300+
self.method,
292301
self.url,
293302
content=body.encode(encoding="utf_8"),
294303
access_token=self.admin_user_tok,
@@ -314,7 +323,7 @@ def test_purge_room_and_block(self):
314323
body = json.dumps({"block": True, "purge": True})
315324

316325
channel = self.make_request(
317-
"POST",
326+
self.method,
318327
self.url.encode("ascii"),
319328
content=body.encode(encoding="utf_8"),
320329
access_token=self.admin_user_tok,
@@ -347,7 +356,7 @@ def test_purge_room_and_not_block(self):
347356
body = json.dumps({"block": False, "purge": True})
348357

349358
channel = self.make_request(
350-
"POST",
359+
self.method,
351360
self.url.encode("ascii"),
352361
content=body.encode(encoding="utf_8"),
353362
access_token=self.admin_user_tok,
@@ -381,7 +390,7 @@ def test_block_room_and_not_purge(self):
381390
body = json.dumps({"block": False, "purge": False})
382391

383392
channel = self.make_request(
384-
"POST",
393+
self.method,
385394
self.url.encode("ascii"),
386395
content=body.encode(encoding="utf_8"),
387396
access_token=self.admin_user_tok,
@@ -426,10 +435,9 @@ def test_shutdown_room_consent(self):
426435
self._is_member(room_id=self.room_id, user_id=self.other_user)
427436

428437
# Test that the admin can still send shutdown
429-
url = "/_synapse/admin/v1/rooms/%s/delete" % self.room_id
430438
channel = self.make_request(
431-
"POST",
432-
url.encode("ascii"),
439+
self.method,
440+
self.url,
433441
json.dumps({"new_room_user_id": self.admin_user}),
434442
access_token=self.admin_user_tok,
435443
)
@@ -473,10 +481,9 @@ def test_shutdown_room_block_peek(self):
473481
self._is_member(room_id=self.room_id, user_id=self.other_user)
474482

475483
# Test that the admin can still send shutdown
476-
url = "/_synapse/admin/v1/rooms/%s/delete" % self.room_id
477484
channel = self.make_request(
478-
"POST",
479-
url.encode("ascii"),
485+
self.method,
486+
self.url,
480487
json.dumps({"new_room_user_id": self.admin_user}),
481488
access_token=self.admin_user_tok,
482489
)

0 commit comments

Comments
 (0)