summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erikj@jki.re>2017-06-01 17:33:20 +0100
committerGitHub <noreply@github.com>2017-06-01 17:33:20 +0100
commit8d34120a533889eb783c9b858d7d5dae5018ee3e (patch)
tree6451d37794ea282887b2edc64228a6fbdf430ec5
parentMerge pull request #2252 from matrix-org/erikj/user_dir (diff)
parentHandle profile updates in user directory (diff)
downloadsynapse-8d34120a533889eb783c9b858d7d5dae5018ee3e.tar.xz
Merge pull request #2253 from matrix-org/erikj/user_dir
Handle profile updates in user directory
-rw-r--r--synapse/handlers/user_directory.py25
-rw-r--r--synapse/storage/user_directory.py49
2 files changed, 74 insertions, 0 deletions
diff --git a/synapse/handlers/user_directory.py b/synapse/handlers/user_directory.py
index d795a9f8d5..0182cf86d6 100644
--- a/synapse/handlers/user_directory.py
+++ b/synapse/handlers/user_directory.py
@@ -192,6 +192,8 @@ class UserDirectoyHandler(object):
                 )
 
                 if change is None:
+                    # Handle any profile changes
+                    yield self._handle_profile_change(state_key, prev_event_id, event_id)
                     continue
 
                 if not change:
@@ -360,6 +362,29 @@ class UserDirectoyHandler(object):
             yield self.store.remove_from_user_in_public_room(user_id)
 
     @defer.inlineCallbacks
+    def _handle_profile_change(self, user_id, prev_event_id, event_id):
+        """Check member event changes for any profile changes and update the
+        database if there are.
+        """
+        if not prev_event_id or not event_id:
+            return
+
+        prev_event = yield self.store.get_event(prev_event_id)
+        event = yield self.store.get_event(event_id)
+
+        if event.membership != Membership.JOIN:
+            return
+
+        prev_name = prev_event.content.get("displayname")
+        new_name = event.content.get("displayname")
+
+        prev_avatar = prev_event.content.get("avatar_url")
+        new_avatar = event.content.get("avatar_url")
+
+        if prev_name != new_name or prev_avatar != new_avatar:
+            yield self.store.update_profile_in_user_dir(user_id, new_name, new_avatar)
+
+    @defer.inlineCallbacks
     def _get_key_change(self, prev_event_id, event_id, key_name, public_value):
         """Given two events check if the `key_name` field in content changed
         from not matching `public_value` to doing so.
diff --git a/synapse/storage/user_directory.py b/synapse/storage/user_directory.py
index bcf24fa4d0..6a4bf63f0d 100644
--- a/synapse/storage/user_directory.py
+++ b/synapse/storage/user_directory.py
@@ -147,6 +147,53 @@ class UserDirectoryStore(SQLBaseStore):
             updatevalues={"room_id": room_id},
             desc="update_user_in_user_dir",
         )
+        self.get_user_in_directory.invalidate((user_id,))
+
+    def update_profile_in_user_dir(self, user_id, display_name, avatar_url):
+        def _update_profile_in_user_dir_txn(txn):
+            self._simple_update_one_txn(
+                txn,
+                table="user_directory",
+                keyvalues={"user_id": user_id},
+                updatevalues={"display_name": display_name, "avatar_url": avatar_url},
+            )
+
+            if isinstance(self.database_engine, PostgresEngine):
+                # We weight the loclpart most highly, then display name and finally
+                # server name
+                sql = """
+                    UPDATE user_directory_search
+                    SET vector = setweight(to_tsvector('english', ?), 'A')
+                        || setweight(to_tsvector('english', ?), 'D')
+                        || setweight(to_tsvector('english', COALESCE(?, '')), 'B')
+                    WHERE user_id = ?
+                """
+                args = (
+                    get_localpart_from_id(user_id), get_domain_from_id(user_id),
+                    display_name,
+                    user_id,
+                )
+            elif isinstance(self.database_engine, Sqlite3Engine):
+                sql = """
+                    UPDATE user_directory_search
+                    set value = ?
+                    WHERE user_id = ?
+                """
+                args = (
+                    "%s %s" % (user_id, display_name,) if display_name else user_id,
+                    user_id,
+                )
+            else:
+                # This should be unreachable.
+                raise Exception("Unrecognized database engine")
+
+            txn.execute(sql, args)
+
+            txn.call_after(self.get_user_in_directory.invalidate, (user_id,))
+
+        return self.runInteraction(
+            "update_profile_in_user_dir", _update_profile_in_user_dir_txn
+        )
 
     @defer.inlineCallbacks
     def update_user_in_public_user_list(self, user_id, room_id):
@@ -156,6 +203,7 @@ class UserDirectoryStore(SQLBaseStore):
             updatevalues={"room_id": room_id},
             desc="update_user_in_public_user_list",
         )
+        self.get_user_in_public_room.invalidate((user_id,))
 
     def remove_from_user_dir(self, user_id):
         def _remove_from_user_dir_txn(txn):
@@ -233,6 +281,7 @@ class UserDirectoryStore(SQLBaseStore):
             txn.execute("DELETE FROM user_directory_search")
             txn.execute("DELETE FROM users_in_pubic_room")
             txn.call_after(self.get_user_in_directory.invalidate_all)
+            txn.call_after(self.get_user_in_public_room.invalidate_all)
         return self.runInteraction(
             "delete_all_from_user_dir", _delete_all_from_user_dir_txn
         )