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

Commit d75512d

Browse files
authored
Add forgotten status to Room Details API (#13503)
1 parent c6ee9c0 commit d75512d

File tree

6 files changed

+101
-1
lines changed

6 files changed

+101
-1
lines changed

changelog.d/13503.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add forgotten status to Room Details API.

docs/admin_api/rooms.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ The following fields are possible in the JSON response body:
302302
* `state_events` - Total number of state_events of a room. Complexity of the room.
303303
* `room_type` - The type of the room taken from the room's creation event; for example "m.space" if the room is a space.
304304
If the room does not define a type, the value will be `null`.
305+
* `forgotten` - Whether all local users have
306+
[forgotten](https://spec.matrix.org/latest/client-server-api/#leaving-rooms) the room.
305307

306308
The API is:
307309

@@ -330,7 +332,8 @@ A response body like the following is returned:
330332
"guest_access": null,
331333
"history_visibility": "shared",
332334
"state_events": 93534,
333-
"room_type": "m.space"
335+
"room_type": "m.space",
336+
"forgotten": false
334337
}
335338
```
336339

synapse/rest/admin/rooms.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ async def on_GET(
303303

304304
members = await self.store.get_users_in_room(room_id)
305305
ret["joined_local_devices"] = await self.store.count_devices_by_users(members)
306+
ret["forgotten"] = await self.store.is_locally_forgotten_room(room_id)
306307

307308
return HTTPStatus.OK, ret
308309

synapse/storage/databases/main/roommember.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,30 @@ def _get_forgotten_rooms_for_user_txn(txn: LoggingTransaction) -> Set[str]:
12151215
"get_forgotten_rooms_for_user", _get_forgotten_rooms_for_user_txn
12161216
)
12171217

1218+
async def is_locally_forgotten_room(self, room_id: str) -> bool:
1219+
"""Returns whether all local users have forgotten this room_id.
1220+
1221+
Args:
1222+
room_id: The room ID to query.
1223+
1224+
Returns:
1225+
Whether the room is forgotten.
1226+
"""
1227+
1228+
sql = """
1229+
SELECT count(*) > 0 FROM local_current_membership
1230+
INNER JOIN room_memberships USING (room_id, event_id)
1231+
WHERE
1232+
room_id = ?
1233+
AND forgotten = 0;
1234+
"""
1235+
1236+
rows = await self.db_pool.execute("is_forgotten_room", None, sql, room_id)
1237+
1238+
# `count(*)` returns always an integer
1239+
# If any rows still exist it means someone has not forgotten this room yet
1240+
return not rows[0][0]
1241+
12181242
async def get_rooms_user_has_been_in(self, user_id: str) -> Set[str]:
12191243
"""Get all rooms that the user has ever been in.
12201244

tests/rest/admin/test_room.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,6 +1633,7 @@ def test_single_room(self) -> None:
16331633
self.assertIn("history_visibility", channel.json_body)
16341634
self.assertIn("state_events", channel.json_body)
16351635
self.assertIn("room_type", channel.json_body)
1636+
self.assertIn("forgotten", channel.json_body)
16361637
self.assertEqual(room_id_1, channel.json_body["room_id"])
16371638

16381639
def test_single_room_devices(self) -> None:

tests/storage/test_roommember.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from tests import unittest
2525
from tests.server import TestHomeServer
26+
from tests.test_utils import event_injection
2627

2728

2829
class RoomMemberStoreTestCase(unittest.HomeserverTestCase):
@@ -157,6 +158,75 @@ def test__null_byte_in_display_name_properly_handled(self) -> None:
157158
# Check that alice's display name is now None
158159
self.assertEqual(row[0]["display_name"], None)
159160

161+
def test_room_is_locally_forgotten(self):
162+
"""Test that when the last local user has forgotten a room it is known as forgotten."""
163+
# join two local and one remote user
164+
self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
165+
self.get_success(
166+
event_injection.inject_member_event(self.hs, self.room, self.u_bob, "join")
167+
)
168+
self.get_success(
169+
event_injection.inject_member_event(
170+
self.hs, self.room, self.u_charlie.to_string(), "join"
171+
)
172+
)
173+
self.assertFalse(
174+
self.get_success(self.store.is_locally_forgotten_room(self.room))
175+
)
176+
177+
# local users leave the room and the room is not forgotten
178+
self.get_success(
179+
event_injection.inject_member_event(
180+
self.hs, self.room, self.u_alice, "leave"
181+
)
182+
)
183+
self.get_success(
184+
event_injection.inject_member_event(self.hs, self.room, self.u_bob, "leave")
185+
)
186+
self.assertFalse(
187+
self.get_success(self.store.is_locally_forgotten_room(self.room))
188+
)
189+
190+
# first user forgets the room, room is not forgotten
191+
self.get_success(self.store.forget(self.u_alice, self.room))
192+
self.assertFalse(
193+
self.get_success(self.store.is_locally_forgotten_room(self.room))
194+
)
195+
196+
# second (last local) user forgets the room and the room is forgotten
197+
self.get_success(self.store.forget(self.u_bob, self.room))
198+
self.assertTrue(
199+
self.get_success(self.store.is_locally_forgotten_room(self.room))
200+
)
201+
202+
def test_join_locally_forgotten_room(self):
203+
"""Tests if a user joins a forgotten room the room is not forgotten anymore."""
204+
self.room = self.helper.create_room_as(self.u_alice, tok=self.t_alice)
205+
self.assertFalse(
206+
self.get_success(self.store.is_locally_forgotten_room(self.room))
207+
)
208+
209+
# after leaving and forget the room, it is forgotten
210+
self.get_success(
211+
event_injection.inject_member_event(
212+
self.hs, self.room, self.u_alice, "leave"
213+
)
214+
)
215+
self.get_success(self.store.forget(self.u_alice, self.room))
216+
self.assertTrue(
217+
self.get_success(self.store.is_locally_forgotten_room(self.room))
218+
)
219+
220+
# after rejoin the room is not forgotten anymore
221+
self.get_success(
222+
event_injection.inject_member_event(
223+
self.hs, self.room, self.u_alice, "join"
224+
)
225+
)
226+
self.assertFalse(
227+
self.get_success(self.store.is_locally_forgotten_room(self.room))
228+
)
229+
160230

161231
class CurrentStateMembershipUpdateTestCase(unittest.HomeserverTestCase):
162232
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:

0 commit comments

Comments
 (0)