mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-28 05:39:36 +03:00
Ensure local invited & knocking users leave before purge. (#16559)
This is mostly useful for federated rooms where some users would get stuck in the invite or knock state when the room was purged from their homeserver.
This commit is contained in:
parent
5413cefe32
commit
2bf9341406
4 changed files with 73 additions and 4 deletions
1
changelog.d/16559.bugfix
Normal file
1
changelog.d/16559.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix a long-standing bug where invited/knocking users would not leave during a room purge.
|
|
@ -1939,9 +1939,10 @@ class RoomShutdownHandler:
|
||||||
else:
|
else:
|
||||||
logger.info("Shutting down room %r", room_id)
|
logger.info("Shutting down room %r", room_id)
|
||||||
|
|
||||||
users = await self.store.get_users_in_room(room_id)
|
users = await self.store.get_local_users_related_to_room(room_id)
|
||||||
for user_id in users:
|
for user_id, membership in users:
|
||||||
if not self.hs.is_mine_id(user_id):
|
# If the user is not in the room (or is banned), nothing to do.
|
||||||
|
if membership not in (Membership.JOIN, Membership.INVITE, Membership.KNOCK):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info("Kicking %r from %r...", user_id, room_id)
|
logger.info("Kicking %r from %r...", user_id, room_id)
|
||||||
|
|
|
@ -482,6 +482,22 @@ class RoomMemberWorkerStore(EventsWorkerStore, CacheInvalidationWorkerStore):
|
||||||
desc="get_local_users_in_room",
|
desc="get_local_users_in_room",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def get_local_users_related_to_room(
|
||||||
|
self, room_id: str
|
||||||
|
) -> List[Tuple[str, str]]:
|
||||||
|
"""
|
||||||
|
Retrieves a list of the current roommembers who are local to the server and their membership status.
|
||||||
|
"""
|
||||||
|
return cast(
|
||||||
|
List[Tuple[str, str]],
|
||||||
|
await self.db_pool.simple_select_list(
|
||||||
|
table="local_current_membership",
|
||||||
|
keyvalues={"room_id": room_id},
|
||||||
|
retcols=("user_id", "membership"),
|
||||||
|
desc="get_local_users_in_room",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
async def check_local_user_in_room(self, user_id: str, room_id: str) -> bool:
|
async def check_local_user_in_room(self, user_id: str, room_id: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Check whether a given local user is currently joined to the given room.
|
Check whether a given local user is currently joined to the given room.
|
||||||
|
|
|
@ -29,7 +29,7 @@ from synapse.handlers.pagination import (
|
||||||
PURGE_ROOM_ACTION_NAME,
|
PURGE_ROOM_ACTION_NAME,
|
||||||
SHUTDOWN_AND_PURGE_ROOM_ACTION_NAME,
|
SHUTDOWN_AND_PURGE_ROOM_ACTION_NAME,
|
||||||
)
|
)
|
||||||
from synapse.rest.client import directory, events, login, room
|
from synapse.rest.client import directory, events, knock, login, room, sync
|
||||||
from synapse.server import HomeServer
|
from synapse.server import HomeServer
|
||||||
from synapse.types import UserID
|
from synapse.types import UserID
|
||||||
from synapse.util import Clock
|
from synapse.util import Clock
|
||||||
|
@ -49,6 +49,8 @@ class DeleteRoomTestCase(unittest.HomeserverTestCase):
|
||||||
login.register_servlets,
|
login.register_servlets,
|
||||||
events.register_servlets,
|
events.register_servlets,
|
||||||
room.register_servlets,
|
room.register_servlets,
|
||||||
|
knock.register_servlets,
|
||||||
|
sync.register_servlets,
|
||||||
room.register_deprecated_servlets,
|
room.register_deprecated_servlets,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -254,6 +256,55 @@ class DeleteRoomTestCase(unittest.HomeserverTestCase):
|
||||||
self._is_blocked(self.room_id, expect=False)
|
self._is_blocked(self.room_id, expect=False)
|
||||||
self._has_no_members(self.room_id)
|
self._has_no_members(self.room_id)
|
||||||
|
|
||||||
|
def test_purge_room_unjoined(self) -> None:
|
||||||
|
"""Test to purge a room when there are invited or knocked users."""
|
||||||
|
# Test that room is not purged
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self._is_purged(self.room_id)
|
||||||
|
|
||||||
|
# Test that room is not blocked
|
||||||
|
self._is_blocked(self.room_id, expect=False)
|
||||||
|
|
||||||
|
# Assert one user in room
|
||||||
|
self._is_member(room_id=self.room_id, user_id=self.other_user)
|
||||||
|
self.helper.send_state(
|
||||||
|
self.room_id,
|
||||||
|
EventTypes.JoinRules,
|
||||||
|
{"join_rule": "knock"},
|
||||||
|
tok=self.other_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Invite a user.
|
||||||
|
invited_user = self.register_user("invited", "pass")
|
||||||
|
self.helper.invite(
|
||||||
|
self.room_id, self.other_user, invited_user, tok=self.other_user_tok
|
||||||
|
)
|
||||||
|
|
||||||
|
# Have a user knock.
|
||||||
|
knocked_user = self.register_user("knocked", "pass")
|
||||||
|
knocked_user_tok = self.login("knocked", "pass")
|
||||||
|
self.helper.knock(self.room_id, knocked_user, tok=knocked_user_tok)
|
||||||
|
|
||||||
|
channel = self.make_request(
|
||||||
|
"DELETE",
|
||||||
|
self.url.encode("ascii"),
|
||||||
|
content={"block": False, "purge": True},
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(None, channel.json_body["new_room_id"])
|
||||||
|
self.assertCountEqual(
|
||||||
|
[self.other_user, invited_user, knocked_user],
|
||||||
|
channel.json_body["kicked_users"],
|
||||||
|
)
|
||||||
|
self.assertIn("failed_to_kick_users", channel.json_body)
|
||||||
|
self.assertIn("local_aliases", channel.json_body)
|
||||||
|
|
||||||
|
self._is_purged(self.room_id)
|
||||||
|
self._is_blocked(self.room_id, expect=False)
|
||||||
|
self._has_no_members(self.room_id)
|
||||||
|
|
||||||
def test_block_room_and_not_purge(self) -> None:
|
def test_block_room_and_not_purge(self) -> None:
|
||||||
"""Test to block a room without purging it.
|
"""Test to block a room without purging it.
|
||||||
Members will not be moved to a new room and will not receive a message.
|
Members will not be moved to a new room and will not receive a message.
|
||||||
|
|
Loading…
Reference in a new issue