summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Robertson <davidr@element.io>2021-10-08 16:57:36 +0100
committerDavid Robertson <davidr@element.io>2021-10-08 17:18:00 +0100
commit18df1c142adea722d91abf27520ae6bac9f915ef (patch)
treeb60fa994fd7285eec0323b635f4705498d462142
parentchanged -> joined (diff)
downloadsynapse-github/dmr/user-dir/dont-remove-local-users.tar.xz
-rw-r--r--synapse/handlers/user_directory.py10
-rw-r--r--tests/handlers/test_user_directory.py29
2 files changed, 35 insertions, 4 deletions
diff --git a/synapse/handlers/user_directory.py b/synapse/handlers/user_directory.py
index 22905eda12..de7ecd42b8 100644
--- a/synapse/handlers/user_directory.py
+++ b/synapse/handlers/user_directory.py
@@ -413,11 +413,13 @@ class UserDirectoryHandler(StateDeltasHandler):
         # Remove user from sharing tables
         await self.store.remove_user_who_share_room(user_id, room_id)
 
-        # Are they still in any rooms? If not, remove them entirely.
-        rooms_user_is_in = await self.store.get_user_dir_rooms_user_is_in(user_id)
+        # If they're a remote user and not in any rooms we can see,
+        # remove their user_directory entry.
+        if not self.is_mine_id(user_id):
+            rooms_user_is_in = await self.store.get_user_dir_rooms_user_is_in(user_id)
 
-        if len(rooms_user_is_in) == 0:
-            await self.store.remove_from_user_dir(user_id)
+            if len(rooms_user_is_in) == 0:
+                await self.store.remove_from_user_dir(user_id)
 
     async def _handle_possible_remote_profile_change(
         self,
diff --git a/tests/handlers/test_user_directory.py b/tests/handlers/test_user_directory.py
index db65253773..07d9df47d0 100644
--- a/tests/handlers/test_user_directory.py
+++ b/tests/handlers/test_user_directory.py
@@ -503,6 +503,35 @@ class UserDirectoryTestCase(unittest.HomeserverTestCase):
             0,
         )
 
+    def test_local_user_remains_in_directory_after_leaving_all_rooms(self) -> None:
+        """We should preserve the invariant that local, non-excluded users are
+        always in the user_directory table.
+
+        This is a choice to simplify the implementation, and also ensure that
+        the config option to search for all users works in this case."""
+        alice = self.register_user("alice", "pass")
+        alice_token = self.login(alice, "pass")
+
+        # Alice should have a user directory entry created at registration.
+        users = self.get_success(self.user_dir_helper.get_profiles_in_user_directory())
+        self.assertEqual(
+            users, {alice: ProfileInfo(display_name="alice", avatar_url=None)}
+        )
+
+        # Alice makes a room for herself.
+        room = self.helper.create_room_as(alice, tok=alice_token)
+
+        # Alice leaves that room.
+        self.helper.leave(room, alice, tok=alice_token)
+
+        # Wait for background updates to ensure that the user directory handler
+        # handler has processed all events. Alice should remain in the directory.
+        self.wait_for_background_updates()
+        users = self.get_success(self.user_dir_helper.get_profiles_in_user_directory())
+        self.assertEqual(
+            users, {alice: ProfileInfo(display_name="alice", avatar_url=None)}
+        )
+
     def test_private_room(self) -> None:
         """
         A user can be searched for only by people that are either in a public