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

Add a user directory #2252

Merged
merged 34 commits into from
Jun 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
eeb2f9e
Add user_directory to database
erikjohnston May 31, 2017
42137ef
Don't go round in circles
erikjohnston May 31, 2017
3e123b8
Start later
erikjohnston May 31, 2017
1685245
Add call later
erikjohnston May 31, 2017
b5db4ed
Update room column when room becomes unpublic
erikjohnston May 31, 2017
3b5f22c
Add search
erikjohnston May 31, 2017
45a5df5
Add REST API
erikjohnston May 31, 2017
535c99f
Use POST
erikjohnston May 31, 2017
293ef29
Weight differently
erikjohnston May 31, 2017
63fda37
Add comments
erikjohnston May 31, 2017
350622a
Handle the server leaving a public room
erikjohnston May 31, 2017
dc51af3
Pull max id from correct table
erikjohnston May 31, 2017
5d79d72
Split out directory and search tables
erikjohnston May 31, 2017
304880d
Add stream change cache
erikjohnston May 31, 2017
63c58c2
Limit number of things we fetch out of the db
erikjohnston May 31, 2017
4abcff0
Fix typo
erikjohnston May 31, 2017
f091061
Fix tests
erikjohnston May 31, 2017
f979149
Typos
erikjohnston May 31, 2017
b2d8d07
Lifts things into separate function
erikjohnston May 31, 2017
f1378ae
Convert to int
erikjohnston May 31, 2017
cc7609a
Comment briefly on how we keep user_directory up to date
erikjohnston May 31, 2017
5dd1b2c
Use unique indices
erikjohnston May 31, 2017
f5cc22b
Comment on why arbitrary comments
erikjohnston May 31, 2017
a757dd4
Use prefix matching
erikjohnston May 31, 2017
036362e
Order by if they have profile info
erikjohnston May 31, 2017
0fe6f3c
Bug fixes and logging
erikjohnston Jun 1, 2017
9c7db24
Fix removing users
erikjohnston Jun 1, 2017
59dbb47
Remove spurious inlineCallbacks
erikjohnston Jun 1, 2017
8be6fd9
Check if host is still in room
erikjohnston Jun 1, 2017
7233341
Comments
erikjohnston Jun 1, 2017
02a6108
Tweak search query
erikjohnston Jun 1, 2017
d5477c7
Tweak search query
erikjohnston Jun 1, 2017
21e255a
Split the table in two
erikjohnston Jun 1, 2017
4d039aa
Fix sqlite
erikjohnston Jun 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
404 changes: 404 additions & 0 deletions synapse/handlers/user_directory.py

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion synapse/notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def __init__(self, hs):

self.clock = hs.get_clock()
self.appservice_handler = hs.get_application_service_handler()
self.user_directory_handler = hs.get_user_directory_handler()

if hs.should_send_federation():
self.federation_sender = hs.get_federation_sender()
Expand Down Expand Up @@ -251,7 +252,10 @@ def _on_new_room_event(self, event, room_stream_id, extra_users=[]):
"""Notify any user streams that are interested in this room event"""
# poke any interested application service.
preserve_fn(self.appservice_handler.notify_interested_services)(
room_stream_id)
room_stream_id
)

preserve_fn(self.user_directory_handler.notify_new_event)()

if self.federation_sender:
preserve_fn(self.federation_sender.notify_new_events)(
Expand Down
2 changes: 2 additions & 0 deletions synapse/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
devices,
thirdparty,
sendtodevice,
user_directory,
)

from synapse.http.server import JsonResource
Expand Down Expand Up @@ -100,3 +101,4 @@ def register_servlets(client_resource, hs):
devices.register_servlets(hs, client_resource)
thirdparty.register_servlets(hs, client_resource)
sendtodevice.register_servlets(hs, client_resource)
user_directory.register_servlets(hs, client_resource)
75 changes: 75 additions & 0 deletions synapse/rest/client/v2_alpha/user_directory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Vector Creations Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from twisted.internet import defer

from synapse.api.errors import SynapseError
from synapse.http.servlet import RestServlet, parse_json_object_from_request
from ._base import client_v2_patterns

logger = logging.getLogger(__name__)


class UserDirectorySearchRestServlet(RestServlet):
PATTERNS = client_v2_patterns("/user_directory/search$")

def __init__(self, hs):
"""
Args:
hs (synapse.server.HomeServer): server
"""
super(UserDirectorySearchRestServlet, self).__init__()
self.hs = hs
self.auth = hs.get_auth()
self.user_directory_handler = hs.get_user_directory_handler()

@defer.inlineCallbacks
def on_POST(self, request):
"""Searches for users in directory

Returns:
dict of the form::

{
"limited": <bool>, # whether there were more results or not
"results": [ # Ordered by best match first
{
"user_id": <user_id>,
"display_name": <display_name>,
"avatar_url": <avatar_url>
}
]
}
"""
yield self.auth.get_user_by_req(request, allow_guest=False)
body = parse_json_object_from_request(request)

limit = body.get("limit", 10)
limit = min(limit, 50)

try:
search_term = body["search_term"]
except:
raise SynapseError(400, "`search_term` is required field")

results = yield self.user_directory_handler.search_users(search_term, limit)

defer.returnValue((200, results))


def register_servlets(hs, http_server):
UserDirectorySearchRestServlet(hs).register(http_server)
5 changes: 5 additions & 0 deletions synapse/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from synapse.handlers.initial_sync import InitialSyncHandler
from synapse.handlers.receipts import ReceiptsHandler
from synapse.handlers.read_marker import ReadMarkerHandler
from synapse.handlers.user_directory import UserDirectoyHandler
from synapse.http.client import SimpleHttpClient, InsecureInterceptableContextFactory
from synapse.http.matrixfederationclient import MatrixFederationHttpClient
from synapse.notifier import Notifier
Expand Down Expand Up @@ -137,6 +138,7 @@ def build_DEPENDENCY(self)
'tcp_replication',
'read_marker_handler',
'action_generator',
'user_directory_handler',
]

def __init__(self, hostname, **kwargs):
Expand Down Expand Up @@ -304,6 +306,9 @@ def build_tcp_replication(self):
def build_action_generator(self):
return ActionGenerator(self)

def build_user_directory_handler(self):
return UserDirectoyHandler(self)

def remove_pusher(self, app_id, push_key, user_id):
return self.get_pusherpool().remove_pusher(app_id, push_key, user_id)

Expand Down
11 changes: 11 additions & 0 deletions synapse/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,17 @@ def get_current_hosts_in_room(self, room_id, latest_event_ids=None):
)
defer.returnValue(joined_hosts)

@defer.inlineCallbacks
def get_is_host_in_room(self, room_id, host, latest_event_ids=None):
if not latest_event_ids:
latest_event_ids = yield self.store.get_latest_event_ids_in_room(room_id)
logger.debug("calling resolve_state_groups from get_is_host_in_room")
entry = yield self.resolve_state_groups(room_id, latest_event_ids)
is_host_joined = yield self.store.is_host_joined(
room_id, host, entry.state_id, entry.state
)
defer.returnValue(is_host_joined)

@defer.inlineCallbacks
def compute_event_context(self, event, old_state=None):
"""Build an EventContext structure for the event.
Expand Down
14 changes: 14 additions & 0 deletions synapse/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from .account_data import AccountDataStore
from .openid import OpenIdStore
from .client_ips import ClientIpStore
from .user_directory import UserDirectoryStore

from .util.id_generators import IdGenerator, StreamIdGenerator, ChainedIdGenerator
from .engines import PostgresEngine
Expand Down Expand Up @@ -86,6 +87,7 @@ class DataStore(RoomMemberStore, RoomStore,
ClientIpStore,
DeviceStore,
DeviceInboxStore,
UserDirectoryStore,
):

def __init__(self, db_conn, hs):
Expand Down Expand Up @@ -221,6 +223,18 @@ def __init__(self, db_conn, hs):
"DeviceListFederationStreamChangeCache", device_list_max,
)

curr_state_delta_prefill, min_curr_state_delta_id = self._get_cache_dict(
db_conn, "current_state_delta_stream",
entity_column="room_id",
stream_column="stream_id",
max_value=events_max, # As we share the stream id with events token
limit=1000,
)
self._curr_state_delta_stream_cache = StreamChangeCache(
"_curr_state_delta_stream_cache", min_curr_state_delta_id,
prefilled_cache=curr_state_delta_prefill,
)

cur = LoggingTransaction(
db_conn.cursor(),
name="_find_stream_orderings_for_times_txn",
Expand Down
5 changes: 5 additions & 0 deletions synapse/storage/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,11 @@ def _simple_insert_txn(txn, table, values):

txn.execute(sql, vals)

def _simple_insert_many(self, table, values, desc):
return self.runInteraction(
desc, self._simple_insert_many_txn, table, values
)

@staticmethod
def _simple_insert_many_txn(txn, table, values):
if not values:
Expand Down
4 changes: 4 additions & 0 deletions synapse/storage/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ def _update_current_state_txn(self, txn, state_delta_by_room, max_stream_order):
]
)

self._curr_state_delta_stream_cache.entity_has_changed(
room_id, max_stream_order,
)

# Invalidate the various caches

# Figure out the changes of membership to invalidate the
Expand Down
84 changes: 84 additions & 0 deletions synapse/storage/schema/delta/42/user_dir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Copyright 2017 Vector Creations Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from synapse.storage.prepare_database import get_statements
from synapse.storage.engines import PostgresEngine, Sqlite3Engine

logger = logging.getLogger(__name__)


BOTH_TABLES = """
CREATE TABLE user_directory_stream_pos (
Lock CHAR(1) NOT NULL DEFAULT 'X' UNIQUE, -- Makes sure this table only has one row.
stream_id BIGINT,
CHECK (Lock='X')
);

INSERT INTO user_directory_stream_pos (stream_id) VALUES (null);

CREATE TABLE user_directory (
user_id TEXT NOT NULL,
room_id TEXT NOT NULL, -- A room_id that we know the user is joined to
display_name TEXT,
avatar_url TEXT
);

CREATE INDEX user_directory_room_idx ON user_directory(room_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a UNIQUE index.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not on room_id, no.

But I've added one to user_id.

CREATE UNIQUE INDEX user_directory_user_idx ON user_directory(user_id);

CREATE TABLE users_in_pubic_room (
user_id TEXT NOT NULL,
room_id TEXT NOT NULL -- A room_id that we know is public
);

CREATE INDEX users_in_pubic_room_room_idx ON users_in_pubic_room(room_id);
CREATE UNIQUE INDEX users_in_pubic_room_user_idx ON users_in_pubic_room(user_id);
"""


POSTGRES_TABLE = """
CREATE TABLE user_directory_search (
user_id TEXT NOT NULL,
vector tsvector
);

CREATE INDEX user_directory_search_fts_idx ON user_directory_search USING gin(vector);
CREATE UNIQUE INDEX user_directory_search_user_idx ON user_directory_search(user_id);
"""


SQLITE_TABLE = """
CREATE VIRTUAL TABLE user_directory_search
USING fts4 ( user_id, value );
"""


def run_create(cur, database_engine, *args, **kwargs):
for statement in get_statements(BOTH_TABLES.splitlines()):
cur.execute(statement)

if isinstance(database_engine, PostgresEngine):
for statement in get_statements(POSTGRES_TABLE.splitlines()):
cur.execute(statement)
elif isinstance(database_engine, Sqlite3Engine):
for statement in get_statements(SQLITE_TABLE.splitlines()):
cur.execute(statement)
else:
raise Exception("Unrecognized database engine")


def run_upgrade(*args, **kwargs):
pass
Loading