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

Commit

Permalink
Merge pull request #2252 from matrix-org/erikj/user_dir
Browse files Browse the repository at this point in the history
Add a user directory
  • Loading branch information
erikjohnston authored Jun 1, 2017
2 parents 5dbaa52 + 4d039aa commit 87e5e05
Show file tree
Hide file tree
Showing 13 changed files with 1,043 additions and 1 deletion.
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);
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

0 comments on commit 87e5e05

Please sign in to comment.