From 26634cb0d9f4fc71f2de6ef8e3586d6dc9d72eb4 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 11:46:51 +0100 Subject: [PATCH 01/32] Add shared_rooms api --- synapse/rest/__init__.py | 2 + synapse/rest/client/v2_alpha/shared_rooms.py | 50 ++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 synapse/rest/client/v2_alpha/shared_rooms.py diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py index 46e458e95ba0..3a04b6f70352 100644 --- a/synapse/rest/__init__.py +++ b/synapse/rest/__init__.py @@ -50,6 +50,7 @@ room_keys, room_upgrade_rest_servlet, sendtodevice, + shared_rooms, sync, tags, thirdparty, @@ -113,6 +114,7 @@ def register_servlets(client_resource, hs): devices.register_servlets(hs, client_resource) thirdparty.register_servlets(hs, client_resource) sendtodevice.register_servlets(hs, client_resource) + shared_rooms.register_servlets(hs, client_resource) user_directory.register_servlets(hs, client_resource) groups.register_servlets(hs, client_resource) room_upgrade_rest_servlet.register_servlets(hs, client_resource) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py new file mode 100644 index 000000000000..11e18debf146 --- /dev/null +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Copyright 2020 Half-Shot +# +# 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.http.servlet import RestServlet +from ._base import client_patterns + +logger = logging.getLogger(__name__) + + +class UserSharedRoomsServlet(RestServlet): + """ + GET /user/{user_id}/shared_rooms/(?P[^/]*) HTTP/1.1 + """ + + PATTERNS = client_patterns( + "/user/(?P[^/]*)/shared_rooms/(?P[^/]*)", + releases=(), # This is an unstable feature + ) + + def __init__(self, hs): + super(UserSharedRoomsServlet, self).__init__() + self.auth = hs.get_auth() + self.store = hs.get_datastore() + + async def on_GET(self, request, user_id, other_user_id): + requester = await self.auth.get_user_by_req(request) + if user_id != requester.user.to_string(): + raise AuthError(403, "Cannot get shared rooms for other users.") + + rooms = await self.store.get_rooms_in_common_for_users(user_id, other_user_id) + + return 200, rooms + + +def register_servlets(hs, http_server): + UserSharedRoomsServlet(hs).register(http_server) From 0f6800f45bb53e985565ceb76b39da465330ac5c Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 13:00:33 +0100 Subject: [PATCH 02/32] Add changelog --- changelog.d/7785.feature | 1 + synapse/rest/client/v2_alpha/shared_rooms.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/7785.feature diff --git a/changelog.d/7785.feature b/changelog.d/7785.feature new file mode 100644 index 000000000000..d86ddd1c9088 --- /dev/null +++ b/changelog.d/7785.feature @@ -0,0 +1 @@ +Add `/user/{user_id}/shared_rooms/{other_user_id}` endpoint \ No newline at end of file diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 11e18debf146..9046f9c22320 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -23,7 +23,7 @@ class UserSharedRoomsServlet(RestServlet): """ - GET /user/{user_id}/shared_rooms/(?P[^/]*) HTTP/1.1 + GET /user/{user_id}/shared_rooms/{other_user_id} HTTP/1.1 """ PATTERNS = client_patterns( From 984c52b4e6fddd058d46301bcfcf933b328a905b Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 13:01:00 +0100 Subject: [PATCH 03/32] Add . --- changelog.d/7785.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/7785.feature b/changelog.d/7785.feature index d86ddd1c9088..c71e8e12b969 100644 --- a/changelog.d/7785.feature +++ b/changelog.d/7785.feature @@ -1 +1 @@ -Add `/user/{user_id}/shared_rooms/{other_user_id}` endpoint \ No newline at end of file +Add `/user/{user_id}/shared_rooms/{other_user_id}` endpoint. \ No newline at end of file From f43bf0cc6b97a152c3a70d6d7639890e1e831065 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 13:46:53 +0100 Subject: [PATCH 04/32] Wrap response in {"rooms": } --- synapse/rest/client/v2_alpha/shared_rooms.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 9046f9c22320..7742e4a78fb9 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -43,7 +43,9 @@ async def on_GET(self, request, user_id, other_user_id): rooms = await self.store.get_rooms_in_common_for_users(user_id, other_user_id) - return 200, rooms + return 200, { + "rooms": rooms, + } def register_servlets(hs, http_server): From 9c1e934d9499e4f3a36f6995d979ea8208aaaa8b Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 13:50:27 +0100 Subject: [PATCH 05/32] linting --- synapse/rest/client/v2_alpha/shared_rooms.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 7742e4a78fb9..79998af1a377 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -15,6 +15,7 @@ import logging +from synapse.api.errors import AuthError from synapse.http.servlet import RestServlet from ._base import client_patterns @@ -28,7 +29,7 @@ class UserSharedRoomsServlet(RestServlet): PATTERNS = client_patterns( "/user/(?P[^/]*)/shared_rooms/(?P[^/]*)", - releases=(), # This is an unstable feature + releases=(), # This is an unstable feature ) def __init__(self, hs): @@ -43,9 +44,7 @@ async def on_GET(self, request, user_id, other_user_id): rooms = await self.store.get_rooms_in_common_for_users(user_id, other_user_id) - return 200, { - "rooms": rooms, - } + return 200, {"rooms": rooms,} def register_servlets(hs, http_server): From 208d3cfa8ad8d0933d86fdb69c996da797a4e253 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 14:06:32 +0100 Subject: [PATCH 06/32] Add unstable_features key --- synapse/rest/client/v2_alpha/shared_rooms.py | 2 +- synapse/rest/client/versions.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 79998af1a377..944dd3dd2dc0 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -44,7 +44,7 @@ async def on_GET(self, request, user_id, other_user_id): rooms = await self.store.get_rooms_in_common_for_users(user_id, other_user_id) - return 200, {"rooms": rooms,} + return 200, {"rooms": rooms} def register_servlets(hs, http_server): diff --git a/synapse/rest/client/versions.py b/synapse/rest/client/versions.py index 0d668df0b6f4..24ac57f35d8a 100644 --- a/synapse/rest/client/versions.py +++ b/synapse/rest/client/versions.py @@ -60,6 +60,8 @@ def on_GET(self, request): "org.matrix.e2e_cross_signing": True, # Implements additional endpoints as described in MSC2432 "org.matrix.msc2432": True, + # Implements additional endpoints as described in MSC2666 + "uk.half-shot.msc2666": True, }, }, ) From 90a5975c7b8e826efa8f6dfa62510acbf1ee396f Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 14:25:44 +0100 Subject: [PATCH 07/32] Remove options from isort that aren't part of 5.x `-y` and `-rc` are now default behaviour and no longer exist. `dont-skip` is no longer required https://timothycrosley.github.io/isort/CHANGELOG/#500-penny-july-4-2020 --- scripts-dev/lint.sh | 2 +- setup.cfg | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts-dev/lint.sh b/scripts-dev/lint.sh index 6f1ba2293196..66b056885879 100755 --- a/scripts-dev/lint.sh +++ b/scripts-dev/lint.sh @@ -15,7 +15,7 @@ else fi echo "Linting these locations: $files" -isort -y -rc $files +isort $files python3 -m black $files ./scripts-dev/config-lint.sh flake8 $files diff --git a/setup.cfg b/setup.cfg index f2bca272e17c..a32278ea8a08 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,7 +26,6 @@ ignore=W503,W504,E203,E731,E501 [isort] line_length = 88 -not_skip = __init__.py sections=FUTURE,STDLIB,COMPAT,THIRDPARTY,TWISTED,FIRSTPARTY,TESTS,LOCALFOLDER default_section=THIRDPARTY known_first_party = synapse From 3fa92f545f4ae6ec3be7adadff32fe5f90d8254f Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 14:27:08 +0100 Subject: [PATCH 08/32] Update imports to make isort happy --- scripts-dev/check_signature.py | 2 +- synapse/api/auth.py | 3 +-- synapse/config/__main__.py | 1 + synapse/config/emailconfig.py | 3 +-- synapse/handlers/auth.py | 3 +-- synapse/handlers/cas_handler.py | 3 +-- synapse/logging/opentracing.py | 4 ++-- synapse/replication/tcp/client.py | 2 +- synapse/replication/tcp/handler.py | 4 ++-- synapse/replication/tcp/streams/events.py | 2 -- synapse/rest/media/v1/thumbnailer.py | 3 +-- synapse/secrets.py | 3 +-- synapse/storage/data_stores/main/events.py | 3 +-- synapse/storage/data_stores/main/ui_auth.py | 2 +- synapse/storage/types.py | 2 -- synapse/types.py | 2 +- tests/handlers/test_e2e_keys.py | 4 +--- tests/rest/media/v1/test_media_storage.py | 4 +--- tests/test_utils/event_injection.py | 2 -- 19 files changed, 18 insertions(+), 34 deletions(-) diff --git a/scripts-dev/check_signature.py b/scripts-dev/check_signature.py index ecda103cf7c4..6755bc528287 100644 --- a/scripts-dev/check_signature.py +++ b/scripts-dev/check_signature.py @@ -2,9 +2,9 @@ import json import logging import sys -import urllib2 import dns.resolver +import urllib2 from signedjson.key import decode_verify_key_bytes, write_signing_keys from signedjson.sign import verify_signed_json from unpaddedbase64 import decode_base64 diff --git a/synapse/api/auth.py b/synapse/api/auth.py index 06ba6604f327..cb22508f4d76 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -12,7 +12,6 @@ # 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 typing import Optional @@ -22,7 +21,6 @@ from twisted.internet import defer from twisted.web.server import Request -import synapse.logging.opentracing as opentracing import synapse.types from synapse import event_auth from synapse.api.auth_blocking import AuthBlocking @@ -35,6 +33,7 @@ ) from synapse.api.room_versions import KNOWN_ROOM_VERSIONS from synapse.events import EventBase +from synapse.logging import opentracing as opentracing from synapse.types import StateMap, UserID from synapse.util.caches import register_cache from synapse.util.caches.lrucache import LruCache diff --git a/synapse/config/__main__.py b/synapse/config/__main__.py index fca35b008c6e..65043d5b5b5f 100644 --- a/synapse/config/__main__.py +++ b/synapse/config/__main__.py @@ -16,6 +16,7 @@ if __name__ == "__main__": import sys + from synapse.config.homeserver import HomeServerConfig action = sys.argv[1] diff --git a/synapse/config/emailconfig.py b/synapse/config/emailconfig.py index ca61214454f8..df08bcd1bcaf 100644 --- a/synapse/config/emailconfig.py +++ b/synapse/config/emailconfig.py @@ -14,7 +14,6 @@ # 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. - from __future__ import print_function # This file can't be called email.py because if it is, we cannot: @@ -145,8 +144,8 @@ def read_config(self, config, **kwargs): or self.threepid_behaviour_email == ThreepidBehaviour.LOCAL ): # make sure we can import the required deps - import jinja2 import bleach + import jinja2 # prevent unused warnings jinja2 diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index d713a06bf918..a162392e4cb3 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -13,7 +13,6 @@ # 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 import time import unicodedata @@ -24,7 +23,6 @@ import bcrypt # type: ignore[import] import pymacaroons -import synapse.util.stringutils as stringutils from synapse.api.constants import LoginType from synapse.api.errors import ( AuthError, @@ -45,6 +43,7 @@ from synapse.module_api import ModuleApi from synapse.push.mailer import load_jinja2_templates from synapse.types import Requester, UserID +from synapse.util import stringutils as stringutils from synapse.util.threepids import canonicalise_email from ._base import BaseHandler diff --git a/synapse/handlers/cas_handler.py b/synapse/handlers/cas_handler.py index 76f213723a0d..d79ffefdb563 100644 --- a/synapse/handlers/cas_handler.py +++ b/synapse/handlers/cas_handler.py @@ -12,11 +12,10 @@ # 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 import urllib -import xml.etree.ElementTree as ET from typing import Dict, Optional, Tuple +from xml.etree import ElementTree as ET from twisted.web.client import PartialDownloadError diff --git a/synapse/logging/opentracing.py b/synapse/logging/opentracing.py index 1676771ef0fb..c6c0e623c16e 100644 --- a/synapse/logging/opentracing.py +++ b/synapse/logging/opentracing.py @@ -164,7 +164,6 @@ def set_fates(clotho, lachesis, atropos, father="Zues", mother="Themis"): than one caller? Will all of those calling functions have be in a context with an active span? """ - import contextlib import inspect import logging @@ -180,8 +179,8 @@ def set_fates(clotho, lachesis, atropos, father="Zues", mother="Themis"): from synapse.config import ConfigError if TYPE_CHECKING: - from synapse.server import HomeServer from synapse.http.site import SynapseRequest + from synapse.server import HomeServer # Helper class @@ -227,6 +226,7 @@ class _DummyTagNames(object): tags = _DummyTagNames try: from jaeger_client import Config as JaegerConfig + from synapse.logging.scopecontextmanager import LogContextScopeManager except ImportError: JaegerConfig = None # type: ignore diff --git a/synapse/replication/tcp/client.py b/synapse/replication/tcp/client.py index df29732f51a1..4985e40b1ff4 100644 --- a/synapse/replication/tcp/client.py +++ b/synapse/replication/tcp/client.py @@ -33,8 +33,8 @@ from synapse.util.metrics import Measure if TYPE_CHECKING: - from synapse.server import HomeServer from synapse.replication.tcp.handler import ReplicationCommandHandler + from synapse.server import HomeServer logger = logging.getLogger(__name__) diff --git a/synapse/replication/tcp/handler.py b/synapse/replication/tcp/handler.py index e6a2e2598b66..55b3b7900876 100644 --- a/synapse/replication/tcp/handler.py +++ b/synapse/replication/tcp/handler.py @@ -13,7 +13,6 @@ # 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 typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, TypeVar @@ -149,10 +148,11 @@ def start_replication(self, hs): using TCP. """ if hs.config.redis.redis_enabled: + import txredisapi + from synapse.replication.tcp.redis import ( RedisDirectTcpReplicationClientFactory, ) - import txredisapi logger.info( "Connecting to redis (host=%r port=%r)", diff --git a/synapse/replication/tcp/streams/events.py b/synapse/replication/tcp/streams/events.py index f3703903314d..bdddb62ad634 100644 --- a/synapse/replication/tcp/streams/events.py +++ b/synapse/replication/tcp/streams/events.py @@ -13,7 +13,6 @@ # 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 heapq from collections import Iterable from typing import List, Tuple, Type @@ -22,7 +21,6 @@ from ._base import Stream, StreamUpdateResult, Token, current_token_without_instance - """Handling of the 'events' replication stream This stream contains rows of various types. Each row therefore contains a 'type' diff --git a/synapse/rest/media/v1/thumbnailer.py b/synapse/rest/media/v1/thumbnailer.py index c234ea74212f..7126997134d2 100644 --- a/synapse/rest/media/v1/thumbnailer.py +++ b/synapse/rest/media/v1/thumbnailer.py @@ -12,11 +12,10 @@ # 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 io import BytesIO -import PIL.Image as Image +from PIL import Image as Image logger = logging.getLogger(__name__) diff --git a/synapse/secrets.py b/synapse/secrets.py index 0b327a0f8233..5f43f81eb0fd 100644 --- a/synapse/secrets.py +++ b/synapse/secrets.py @@ -19,7 +19,6 @@ See https://docs.python.org/3/library/secrets.html#module-secrets for the API used in Python 3.6, and the API emulated in Python 2.7. """ - import sys # secrets is available since python 3.6 @@ -31,8 +30,8 @@ def Secrets(): else: - import os import binascii + import os class Secrets(object): def token_bytes(self, nbytes=32): diff --git a/synapse/storage/data_stores/main/events.py b/synapse/storage/data_stores/main/events.py index cfd24d2f061d..b7bf3fbd9d36 100644 --- a/synapse/storage/data_stores/main/events.py +++ b/synapse/storage/data_stores/main/events.py @@ -14,7 +14,6 @@ # 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 itertools import logging from collections import OrderedDict, namedtuple @@ -48,8 +47,8 @@ from synapse.util.iterutils import batch_iter if TYPE_CHECKING: - from synapse.storage.data_stores.main import DataStore from synapse.server import HomeServer + from synapse.storage.data_stores.main import DataStore logger = logging.getLogger(__name__) diff --git a/synapse/storage/data_stores/main/ui_auth.py b/synapse/storage/data_stores/main/ui_auth.py index ec2f38c37357..4c044b1a1549 100644 --- a/synapse/storage/data_stores/main/ui_auth.py +++ b/synapse/storage/data_stores/main/ui_auth.py @@ -17,10 +17,10 @@ import attr -import synapse.util.stringutils as stringutils from synapse.api.errors import StoreError from synapse.storage._base import SQLBaseStore from synapse.types import JsonDict +from synapse.util import stringutils as stringutils @attr.s diff --git a/synapse/storage/types.py b/synapse/storage/types.py index daff81c5ee23..2d2b560e748e 100644 --- a/synapse/storage/types.py +++ b/synapse/storage/types.py @@ -12,12 +12,10 @@ # 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. - from typing import Any, Iterable, Iterator, List, Tuple from typing_extensions import Protocol - """ Some very basic protocol definitions for the DB-API2 classes specified in PEP-249 """ diff --git a/synapse/types.py b/synapse/types.py index acf60baddc6b..238b93806448 100644 --- a/synapse/types.py +++ b/synapse/types.py @@ -29,7 +29,7 @@ if sys.version_info[:3] >= (3, 6, 0): from typing import Collection else: - from typing import Sized, Iterable, Container + from typing import Container, Iterable, Sized T_co = TypeVar("T_co", covariant=True) diff --git a/tests/handlers/test_e2e_keys.py b/tests/handlers/test_e2e_keys.py index 6c1dc72bd111..1acf287ca4e8 100644 --- a/tests/handlers/test_e2e_keys.py +++ b/tests/handlers/test_e2e_keys.py @@ -14,11 +14,9 @@ # 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 mock -import signedjson.key as key -import signedjson.sign as sign +from signedjson import key as key, sign as sign from twisted.internet import defer diff --git a/tests/rest/media/v1/test_media_storage.py b/tests/rest/media/v1/test_media_storage.py index 2ed9312d564d..66fa5978b2fd 100644 --- a/tests/rest/media/v1/test_media_storage.py +++ b/tests/rest/media/v1/test_media_storage.py @@ -12,8 +12,6 @@ # 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 os import shutil import tempfile @@ -25,8 +23,8 @@ from mock import Mock import attr -import PIL.Image as Image from parameterized import parameterized_class +from PIL import Image as Image from twisted.internet.defer import Deferred diff --git a/tests/test_utils/event_injection.py b/tests/test_utils/event_injection.py index 431e9f8e5e34..43297b530cbe 100644 --- a/tests/test_utils/event_injection.py +++ b/tests/test_utils/event_injection.py @@ -13,7 +13,6 @@ # 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. - from typing import Optional, Tuple import synapse.server @@ -25,7 +24,6 @@ from tests.test_utils import get_awaitable_result - """ Utility functions for poking events into the storage of the server under test. """ From 6bd34c7e5186d8c5c735cd466975b44e902c6145 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 14:30:08 +0100 Subject: [PATCH 09/32] Add changelog --- changelog.d/7786.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7786.misc diff --git a/changelog.d/7786.misc b/changelog.d/7786.misc new file mode 100644 index 000000000000..f092208d9c80 --- /dev/null +++ b/changelog.d/7786.misc @@ -0,0 +1 @@ +Update linting scripts and codebase to be isort5 compatible. \ No newline at end of file From 09e09a3cf9df4e74497f7ea0fb9695f2e0f381db Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 14:33:00 +0100 Subject: [PATCH 10/32] Update tox.ini file with correct invocation --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index ab6557f15e71..6068d0af385d 100644 --- a/tox.ini +++ b/tox.ini @@ -132,7 +132,7 @@ commands = [testenv:check_isort] skip_install = True deps = isort -commands = /bin/sh -c "isort -c -df -sp setup.cfg -rc synapse tests scripts-dev scripts" +commands = /bin/sh -c "isort -c --df --sp setup.cfg synapse tests scripts-dev scripts" [testenv:check-newsfragment] skip_install = True From 676edeaeac9f51b18fab0b8f39e98e2aad7b81ad Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sun, 5 Jul 2020 14:35:53 +0100 Subject: [PATCH 11/32] fix linting again for isort --- synapse/rest/client/v2_alpha/shared_rooms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 944dd3dd2dc0..9080ff721cdd 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -12,11 +12,11 @@ # 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.api.errors import AuthError from synapse.http.servlet import RestServlet + from ._base import client_patterns logger = logging.getLogger(__name__) From dde46cf6afdcc858501b5c5afc84d2fe9c06542d Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Fri, 10 Jul 2020 11:59:54 +0100 Subject: [PATCH 12/32] Vendor prefix unstable API --- synapse/rest/client/v2_alpha/shared_rooms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 9080ff721cdd..a638baa81035 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -24,11 +24,11 @@ class UserSharedRoomsServlet(RestServlet): """ - GET /user/{user_id}/shared_rooms/{other_user_id} HTTP/1.1 + GET /uk.half-shot.msc2666/user/{user_id}/shared_rooms/{other_user_id} HTTP/1.1 """ PATTERNS = client_patterns( - "/user/(?P[^/]*)/shared_rooms/(?P[^/]*)", + "/uk.half-shot.msc2666/user/(?P[^/]*)/shared_rooms/(?P[^/]*)", releases=(), # This is an unstable feature ) From 256e0172acdaa795f67fdf0fc3b307502c5265ac Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 31 Jul 2020 14:41:43 +0100 Subject: [PATCH 13/32] Fix to match spec --- synapse/rest/client/v2_alpha/shared_rooms.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index a638baa81035..4bef767f6ea2 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -14,7 +14,7 @@ # limitations under the License. import logging -from synapse.api.errors import AuthError +from synapse.api.errors import SynapseError from synapse.http.servlet import RestServlet from ._base import client_patterns @@ -24,11 +24,11 @@ class UserSharedRoomsServlet(RestServlet): """ - GET /uk.half-shot.msc2666/user/{user_id}/shared_rooms/{other_user_id} HTTP/1.1 + GET /uk.half-shot.msc2666/user/shared_rooms/{user_id} HTTP/1.1 """ PATTERNS = client_patterns( - "/uk.half-shot.msc2666/user/(?P[^/]*)/shared_rooms/(?P[^/]*)", + "/uk.half-shot.msc2666/user/shared_rooms/(?P[^/]*)", releases=(), # This is an unstable feature ) @@ -37,14 +37,18 @@ def __init__(self, hs): self.auth = hs.get_auth() self.store = hs.get_datastore() - async def on_GET(self, request, user_id, other_user_id): + async def on_GET(self, request, user_id): requester = await self.auth.get_user_by_req(request) - if user_id != requester.user.to_string(): - raise AuthError(403, "Cannot get shared rooms for other users.") + if user_id == requester.user.to_string(): + raise SynapseError( + code=400, + msg="'user_id' must not be the authenticated user", + errcode=Codes.BAD_JSON, + ) - rooms = await self.store.get_rooms_in_common_for_users(user_id, other_user_id) + rooms = await self.store.get_rooms_in_common_for_users(requester.user.to_string(), user_id) - return 200, {"rooms": rooms} + return 200, {"joined": rooms} def register_servlets(hs, http_server): From 9cd5116be062cd1f9d74ed5dcf8eecd1f1308fb8 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 31 Jul 2020 14:43:01 +0100 Subject: [PATCH 14/32] import Codes --- synapse/rest/client/v2_alpha/shared_rooms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 4bef767f6ea2..e82a019b5392 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -14,7 +14,7 @@ # limitations under the License. import logging -from synapse.api.errors import SynapseError +from synapse.api.errors import Codes, SynapseError from synapse.http.servlet import RestServlet from ._base import client_patterns From 72e90a2196856ab85734d58c8a3d7898f718e942 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 31 Jul 2020 14:43:01 +0100 Subject: [PATCH 15/32] import Codes --- synapse/rest/client/v2_alpha/shared_rooms.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 4bef767f6ea2..ca86a9a91050 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -14,7 +14,7 @@ # limitations under the License. import logging -from synapse.api.errors import SynapseError +from synapse.api.errors import Codes, SynapseError from synapse.http.servlet import RestServlet from ._base import client_patterns @@ -46,7 +46,9 @@ async def on_GET(self, request, user_id): errcode=Codes.BAD_JSON, ) - rooms = await self.store.get_rooms_in_common_for_users(requester.user.to_string(), user_id) + rooms = await self.store.get_rooms_in_common_for_users( + requester.user.to_string(), user_id + ) return 200, {"joined": rooms} From ce49d19bf63d925c8a0906a77972a8db961eaedc Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 18 Aug 2020 18:33:33 +0100 Subject: [PATCH 16/32] Use FORBIDDEN --- synapse/rest/client/v2_alpha/shared_rooms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index ca86a9a91050..86feec214514 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -43,7 +43,7 @@ async def on_GET(self, request, user_id): raise SynapseError( code=400, msg="'user_id' must not be the authenticated user", - errcode=Codes.BAD_JSON, + errcode=Codes.FORBIDDEN, ) rooms = await self.store.get_rooms_in_common_for_users( From 42a09b999fdb943d35f4d165ad36352186323218 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 18 Aug 2020 18:51:37 +0100 Subject: [PATCH 17/32] Update changelog.d/7785.feature Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- changelog.d/7785.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/7785.feature b/changelog.d/7785.feature index c71e8e12b969..c7e51c932035 100644 --- a/changelog.d/7785.feature +++ b/changelog.d/7785.feature @@ -1 +1 @@ -Add `/user/{user_id}/shared_rooms/{other_user_id}` endpoint. \ No newline at end of file +Add an endpoint to query your shared rooms with another user as an implementation of [MSC2666](https://github.com/matrix-org/matrix-doc/pull/2666). From 7905978cf3c6aa56beaa14a1892934f48bbd9ba7 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 18 Aug 2020 19:30:17 +0100 Subject: [PATCH 18/32] Implement get_shared_rooms_for_users --- synapse/rest/client/v2_alpha/shared_rooms.py | 2 +- .../storage/databases/main/user_directory.py | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 86feec214514..69ecd552ec61 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -46,7 +46,7 @@ async def on_GET(self, request, user_id): errcode=Codes.FORBIDDEN, ) - rooms = await self.store.get_rooms_in_common_for_users( + rooms = await self.store.get_shared_rooms_for_users( requester.user.to_string(), user_id ) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index af21fe457adb..1c73e51c213f 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -663,6 +663,42 @@ async def get_user_dir_rooms_user_is_in(self, user_id): users.update(rows) return list(users) + @cached() + async def get_shared_rooms_for_users(self, user_id, other_user_id): + """ + Returns the rooms that a user is in. + + Args: + user_id(str): Must be a local user + + Returns: + list: user_id + """ + SQL = """ + SELECT p1.room_id + FROM users_in_public_rooms as p1 + INNER JOIN users_in_public_rooms as p2 + ON p1.room_id = p2.room_id + AND p1.user_id = ? + AND p2.user_id = ? + UNION + SELECT room_id + FROM users_who_share_private_rooms + WHERE + user_id = ? + AND other_user_id = ?; + """ + rows = await self.db_pool.execute( + "get_shared_rooms_for_users", + None, + SQL, + user_id, + other_user_id, + user_id, + other_user_id + ) + return list({row[0] for row in rows}) + def get_user_directory_stream_pos(self): return self.db_pool.simple_select_one_onecol( table="user_directory_stream_pos", From 130d2f3e9225ef328d5c83896bc21d31bd5bf32b Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 18 Aug 2020 19:39:59 +0100 Subject: [PATCH 19/32] a comma --- synapse/storage/databases/main/user_directory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index 1c73e51c213f..33eee96a4760 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -695,7 +695,7 @@ async def get_shared_rooms_for_users(self, user_id, other_user_id): user_id, other_user_id, user_id, - other_user_id + other_user_id, ) return list({row[0] for row in rows}) From c120fd3740af07e72f9d170625058943c0be7f54 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 19 Aug 2020 09:34:31 +0100 Subject: [PATCH 20/32] trailing whitespace --- synapse/storage/databases/main/user_directory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index 33eee96a4760..7df068273137 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -675,7 +675,7 @@ async def get_shared_rooms_for_users(self, user_id, other_user_id): list: user_id """ SQL = """ - SELECT p1.room_id + SELECT p1.room_id FROM users_in_public_rooms as p1 INNER JOIN users_in_public_rooms as p2 ON p1.room_id = p2.room_id From e135cd515e58c33f20087dcd3001854a26dbe8ed Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 28 Aug 2020 15:24:01 +0100 Subject: [PATCH 21/32] Handle the easy feedback --- docs/workers.md | 1 + synapse/rest/client/v2_alpha/shared_rooms.py | 16 ++++++++++++++-- synapse/storage/databases/main/user_directory.py | 14 +++++++++----- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/workers.md b/docs/workers.md index bfec745897c2..b1cad9d0e415 100644 --- a/docs/workers.md +++ b/docs/workers.md @@ -380,6 +380,7 @@ Handles searches in the user directory. It can handle REST endpoints matching the following regular expressions: ^/_matrix/client/(api/v1|r0|unstable)/user_directory/search$ + ^/_matrix/client/uk.half-shot.msc2666/user/shared_rooms/.*$ When using this worker you must also set `update_user_directory: False` in the shared configuration file to stop the main synapse running background diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 69ecd552ec61..60f6d98c0e5c 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -16,6 +16,7 @@ from synapse.api.errors import Codes, SynapseError from synapse.http.servlet import RestServlet +from synapse.types import UserID from ._base import client_patterns @@ -36,13 +37,24 @@ def __init__(self, hs): super(UserSharedRoomsServlet, self).__init__() self.auth = hs.get_auth() self.store = hs.get_datastore() + self.user_directory_active = hs.config.update_user_directory async def on_GET(self, request, user_id): + + if not self.user_directory_active: + raise SynapseError( + code=400, + msg="The user directory is disabled on this server. Cannot determine shared rooms.", + errcode=Codes.FORBIDDEN, + ) + + UserID.from_string(user_id) + requester = await self.auth.get_user_by_req(request) if user_id == requester.user.to_string(): raise SynapseError( code=400, - msg="'user_id' must not be the authenticated user", + msg="You cannot request a list of shared rooms with yourself", errcode=Codes.FORBIDDEN, ) @@ -50,7 +62,7 @@ async def on_GET(self, request, user_id): requester.user.to_string(), user_id ) - return 200, {"joined": rooms} + return 200, {"joined": list(rooms)} def register_servlets(hs, http_server): diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index 7df068273137..ea2efddcde43 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -15,6 +15,7 @@ import logging import re +from typing import Set from synapse.api.constants import EventTypes, JoinRules from synapse.storage.database import DatabasePool @@ -664,15 +665,18 @@ async def get_user_dir_rooms_user_is_in(self, user_id): return list(users) @cached() - async def get_shared_rooms_for_users(self, user_id, other_user_id): + async def get_shared_rooms_for_users( + self, user_id: str, other_user_id: str + ) -> Set[str]: """ - Returns the rooms that a user is in. + Returns the rooms that a local user shares with another local or remote user. Args: - user_id(str): Must be a local user + user_id: The MXID of a local user + other_user_id: The MXID of the other user Returns: - list: user_id + A set of room ID's that the users share. """ SQL = """ SELECT p1.room_id @@ -697,7 +701,7 @@ async def get_shared_rooms_for_users(self, user_id, other_user_id): user_id, other_user_id, ) - return list({row[0] for row in rows}) + return set(row[0] for row in rows) def get_user_directory_stream_pos(self): return self.db_pool.simple_select_one_onecol( From e785cc641e47493cf782aee348fedab48f26954d Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 28 Aug 2020 15:27:20 +0100 Subject: [PATCH 22/32] Switch to using runInteraction --- .../storage/databases/main/user_directory.py | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index ea2efddcde43..04907980a341 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -678,28 +678,26 @@ async def get_shared_rooms_for_users( Returns: A set of room ID's that the users share. """ - SQL = """ - SELECT p1.room_id - FROM users_in_public_rooms as p1 - INNER JOIN users_in_public_rooms as p2 - ON p1.room_id = p2.room_id - AND p1.user_id = ? - AND p2.user_id = ? - UNION - SELECT room_id - FROM users_who_share_private_rooms - WHERE - user_id = ? - AND other_user_id = ?; - """ - rows = await self.db_pool.execute( - "get_shared_rooms_for_users", - None, - SQL, - user_id, - other_user_id, - user_id, - other_user_id, + + def _get_shared_rooms_for_users_txn(txn): + SQL = """ + SELECT p1.room_id + FROM users_in_public_rooms as p1 + INNER JOIN users_in_public_rooms as p2 + ON p1.room_id = p2.room_id + AND p1.user_id = ? + AND p2.user_id = ? + UNION + SELECT room_id + FROM users_who_share_private_rooms + WHERE + user_id = ? + AND other_user_id = ?; + """ + txn.execute(SQL) + + rows = await self.db_pool.runInteraction( + "get_shared_rooms_for_users", _get_shared_rooms_for_users_txn ) return set(row[0] for row in rows) From 8a4c5abe72705ddf2246d023657a14c5b0033e8f Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Fri, 28 Aug 2020 16:16:00 +0100 Subject: [PATCH 23/32] Add tests --- synapse/rest/client/v2_alpha/shared_rooms.py | 1 - .../storage/databases/main/user_directory.py | 13 +- .../rest/client/v2_alpha/test_shared_rooms.py | 143 ++++++++++++++++++ 3 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 tests/rest/client/v2_alpha/test_shared_rooms.py diff --git a/synapse/rest/client/v2_alpha/shared_rooms.py b/synapse/rest/client/v2_alpha/shared_rooms.py index 60f6d98c0e5c..2492634dace1 100644 --- a/synapse/rest/client/v2_alpha/shared_rooms.py +++ b/synapse/rest/client/v2_alpha/shared_rooms.py @@ -57,7 +57,6 @@ async def on_GET(self, request, user_id): msg="You cannot request a list of shared rooms with yourself", errcode=Codes.FORBIDDEN, ) - rooms = await self.store.get_shared_rooms_for_users( requester.user.to_string(), user_id ) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index 04907980a341..48a5f6fa2dc2 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -680,7 +680,8 @@ async def get_shared_rooms_for_users( """ def _get_shared_rooms_for_users_txn(txn): - SQL = """ + txn.execute( + """ SELECT p1.room_id FROM users_in_public_rooms as p1 INNER JOIN users_in_public_rooms as p2 @@ -693,13 +694,17 @@ def _get_shared_rooms_for_users_txn(txn): WHERE user_id = ? AND other_user_id = ?; - """ - txn.execute(SQL) + """, + (user_id, other_user_id, user_id, other_user_id), + ) + rows = self.db_pool.cursor_to_dict(txn) + return rows rows = await self.db_pool.runInteraction( "get_shared_rooms_for_users", _get_shared_rooms_for_users_txn ) - return set(row[0] for row in rows) + + return set(row["room_id"] for row in rows) def get_user_directory_stream_pos(self): return self.db_pool.simple_select_one_onecol( diff --git a/tests/rest/client/v2_alpha/test_shared_rooms.py b/tests/rest/client/v2_alpha/test_shared_rooms.py new file mode 100644 index 000000000000..f22b2261dbe0 --- /dev/null +++ b/tests/rest/client/v2_alpha/test_shared_rooms.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 New Vector +# +# 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 synapse.rest.admin +from synapse.rest.client.v1 import login, room +from synapse.rest.client.v2_alpha import shared_rooms + +from tests import unittest + + +class UserSharedRoomsTest(unittest.HomeserverTestCase): + """ + Tests the UserSharedRoomsServlet. + """ + + servlets = [ + login.register_servlets, + synapse.rest.admin.register_servlets_for_client_rest_resource, + room.register_servlets, + shared_rooms.register_servlets, + ] + + def make_homeserver(self, reactor, clock): + + config = self.default_config() + config["update_user_directory"] = True + return self.setup_test_homeserver(config=config) + + def prepare(self, reactor, clock, hs): + self.store = hs.get_datastore() + self.handler = hs.get_user_directory_handler() + + def _get_shared_rooms(self, token, other_user): + # Assert user directory is not empty + request, channel = self.make_request( + "GET", + "/_matrix/client/unstable/uk.half-shot.msc2666/user/shared_rooms/%s" + % other_user, + access_token=token, + ) + self.render(request) + return request, channel + + def test_shared_room_list_public(self): + """ + A room should show up in the shared list of rooms between two users + if it is public. + """ + u1 = self.register_user("user1", "pass") + u1_token = self.login(u1, "pass") + u2 = self.register_user("user2", "pass") + u2_token = self.login(u2, "pass") + + room = self.helper.create_room_as(u1, is_public=True, tok=u1_token) + self.helper.invite(room, src=u1, targ=u2, tok=u1_token) + self.helper.join(room, user=u2, tok=u2_token) + + # Assert user directory is not empty + request, channel = self._get_shared_rooms(u1_token, u2) + self.assertEquals(200, channel.code, channel.result) + self.assertEquals(len(channel.json_body["joined"]), 1) + self.assertEquals(channel.json_body["joined"][0], room) + + def test_shared_room_list_private(self): + """ + A room should show up in the shared list of rooms between two users + if it is private. + """ + u1 = self.register_user("user1", "pass") + u1_token = self.login(u1, "pass") + u2 = self.register_user("user2", "pass") + u2_token = self.login(u2, "pass") + + room = self.helper.create_room_as(u1, is_public=False, tok=u1_token) + self.helper.invite(room, src=u1, targ=u2, tok=u1_token) + self.helper.join(room, user=u2, tok=u2_token) + + # Assert user directory is not empty + request, channel = self._get_shared_rooms(u1_token, u2) + self.assertEquals(200, channel.code, channel.result) + self.assertEquals(len(channel.json_body["joined"]), 1) + self.assertEquals(channel.json_body["joined"][0], room) + + def test_shared_room_list_mixed(self): + """ + The shared room list between two users should contain both public and private + rooms. + """ + u1 = self.register_user("user1", "pass") + u1_token = self.login(u1, "pass") + u2 = self.register_user("user2", "pass") + u2_token = self.login(u2, "pass") + + room_public = self.helper.create_room_as(u1, is_public=False, tok=u1_token) + room_private = self.helper.create_room_as(u2, is_public=True, tok=u2_token) + self.helper.invite(room_public, src=u1, targ=u2, tok=u1_token) + self.helper.invite(room_private, src=u2, targ=u1, tok=u2_token) + self.helper.join(room_public, user=u2, tok=u2_token) + self.helper.join(room_private, user=u1, tok=u1_token) + + # Assert user directory is not empty + request, channel = self._get_shared_rooms(u1_token, u2) + self.assertEquals(200, channel.code, channel.result) + self.assertEquals(len(channel.json_body["joined"]), 2) + self.assertTrue(room_public in channel.json_body["joined"]) + self.assertTrue(room_private in channel.json_body["joined"]) + + def test_shared_room_list_after_leave(self): + """ + A room should no longer be considered shared if the other + user has left it. + """ + u1 = self.register_user("user1", "pass") + u1_token = self.login(u1, "pass") + u2 = self.register_user("user2", "pass") + u2_token = self.login(u2, "pass") + + room = self.helper.create_room_as(u1, is_public=True, tok=u1_token) + self.helper.invite(room, src=u1, targ=u2, tok=u1_token) + self.helper.join(room, user=u2, tok=u2_token) + + # Assert user directory is not empty + request, channel = self._get_shared_rooms(u1_token, u2) + self.assertEquals(200, channel.code, channel.result) + self.assertEquals(len(channel.json_body["joined"]), 1) + self.assertEquals(channel.json_body["joined"][0], room) + + self.helper.leave(room, user=u1, tok=u1_token) + + request, channel = self._get_shared_rooms(u2_token, u1) + self.assertEquals(200, channel.code, channel.result) + self.assertEquals(len(channel.json_body["joined"]), 0) From e86f4062cea816bcf347daf40a2221af15f34cfa Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sat, 29 Aug 2020 10:01:15 +0100 Subject: [PATCH 24/32] Feedback --- synapse/storage/databases/main/user_directory.py | 2 +- tests/rest/client/v2_alpha/test_shared_rooms.py | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index d8f3c411fb0d..736e8f845d9d 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -15,7 +15,7 @@ import logging import re -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, Set from synapse.api.constants import EventTypes, JoinRules from synapse.storage.database import DatabasePool diff --git a/tests/rest/client/v2_alpha/test_shared_rooms.py b/tests/rest/client/v2_alpha/test_shared_rooms.py index f22b2261dbe0..6562780e4bb4 100644 --- a/tests/rest/client/v2_alpha/test_shared_rooms.py +++ b/tests/rest/client/v2_alpha/test_shared_rooms.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright 2018 New Vector +# Copyright 2020 Half-Shot # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -42,7 +42,6 @@ def prepare(self, reactor, clock, hs): self.handler = hs.get_user_directory_handler() def _get_shared_rooms(self, token, other_user): - # Assert user directory is not empty request, channel = self.make_request( "GET", "/_matrix/client/unstable/uk.half-shot.msc2666/user/shared_rooms/%s" @@ -66,7 +65,6 @@ def test_shared_room_list_public(self): self.helper.invite(room, src=u1, targ=u2, tok=u1_token) self.helper.join(room, user=u2, tok=u2_token) - # Assert user directory is not empty request, channel = self._get_shared_rooms(u1_token, u2) self.assertEquals(200, channel.code, channel.result) self.assertEquals(len(channel.json_body["joined"]), 1) @@ -86,7 +84,6 @@ def test_shared_room_list_private(self): self.helper.invite(room, src=u1, targ=u2, tok=u1_token) self.helper.join(room, user=u2, tok=u2_token) - # Assert user directory is not empty request, channel = self._get_shared_rooms(u1_token, u2) self.assertEquals(200, channel.code, channel.result) self.assertEquals(len(channel.json_body["joined"]), 1) @@ -102,14 +99,13 @@ def test_shared_room_list_mixed(self): u2 = self.register_user("user2", "pass") u2_token = self.login(u2, "pass") - room_public = self.helper.create_room_as(u1, is_public=False, tok=u1_token) - room_private = self.helper.create_room_as(u2, is_public=True, tok=u2_token) + room_public = self.helper.create_room_as(u1, is_public=True, tok=u1_token) + room_private = self.helper.create_room_as(u2, is_public=False, tok=u2_token) self.helper.invite(room_public, src=u1, targ=u2, tok=u1_token) self.helper.invite(room_private, src=u2, targ=u1, tok=u2_token) self.helper.join(room_public, user=u2, tok=u2_token) self.helper.join(room_private, user=u1, tok=u1_token) - # Assert user directory is not empty request, channel = self._get_shared_rooms(u1_token, u2) self.assertEquals(200, channel.code, channel.result) self.assertEquals(len(channel.json_body["joined"]), 2) From 7554836b237c8f222c0269c419311fffe83cb7c0 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sat, 29 Aug 2020 10:01:22 +0100 Subject: [PATCH 25/32] Seperate unstable endpoint from v2 --- synapse/rest/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py index 3a04b6f70352..4151d4d3e0a9 100644 --- a/synapse/rest/__init__.py +++ b/synapse/rest/__init__.py @@ -114,7 +114,6 @@ def register_servlets(client_resource, hs): devices.register_servlets(hs, client_resource) thirdparty.register_servlets(hs, client_resource) sendtodevice.register_servlets(hs, client_resource) - shared_rooms.register_servlets(hs, client_resource) user_directory.register_servlets(hs, client_resource) groups.register_servlets(hs, client_resource) room_upgrade_rest_servlet.register_servlets(hs, client_resource) @@ -127,3 +126,6 @@ def register_servlets(client_resource, hs): synapse.rest.admin.register_servlets_for_client_rest_resource( hs, client_resource ) + + # unstable + shared_rooms.register_servlets(hs, client_resource) \ No newline at end of file From 1fa8b84cc1f487d101a8c6b774a75741eb141041 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sat, 29 Aug 2020 10:01:36 +0100 Subject: [PATCH 26/32] Add upgrade node --- UPGRADE.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/UPGRADE.rst b/UPGRADE.rst index 6492fa011f4a..519eceb61041 100644 --- a/UPGRADE.rst +++ b/UPGRADE.rst @@ -1,3 +1,16 @@ +Upgrading to v1.20.0 +==================== + +Shared rooms endpoint (MSC2666) +------------------------------ + +This release contains a new unstable endpoint `/_matrix/client/uk.half-shot.msc2666/user/shared_rooms/.*` +for fetching rooms one user has in common with another. This feature requires the +`update_user_directory` config flag to be `True`. If you are you are using a `synapse.app.user_dir` +worker, requests to this endpoint must be handled by that worker. +See `docs/workers.md `_ for more details. + + Upgrading Synapse ================= From 783f8f548147ff9faff482cf500f46459ad3a523 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Sat, 29 Aug 2020 10:02:57 +0100 Subject: [PATCH 27/32] a line --- tests/rest/client/v2_alpha/test_shared_rooms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/rest/client/v2_alpha/test_shared_rooms.py b/tests/rest/client/v2_alpha/test_shared_rooms.py index 6562780e4bb4..5ae72fd00825 100644 --- a/tests/rest/client/v2_alpha/test_shared_rooms.py +++ b/tests/rest/client/v2_alpha/test_shared_rooms.py @@ -32,7 +32,6 @@ class UserSharedRoomsTest(unittest.HomeserverTestCase): ] def make_homeserver(self, reactor, clock): - config = self.default_config() config["update_user_directory"] = True return self.setup_test_homeserver(config=config) From a444ab01d94da543a92f86f1b636f65ef9d57a98 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Mon, 31 Aug 2020 07:04:57 -0400 Subject: [PATCH 28/32] Fix style by adding a blank line at EOF. --- synapse/rest/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py index 4151d4d3e0a9..87f927890c5e 100644 --- a/synapse/rest/__init__.py +++ b/synapse/rest/__init__.py @@ -128,4 +128,4 @@ def register_servlets(client_resource, hs): ) # unstable - shared_rooms.register_servlets(hs, client_resource) \ No newline at end of file + shared_rooms.register_servlets(hs, client_resource) From 837cf3183821287fb1ce4482a926319a168554b3 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Mon, 31 Aug 2020 16:11:18 +0100 Subject: [PATCH 29/32] Update synapse/storage/databases/main/user_directory.py Co-authored-by: Tulir Asokan --- synapse/storage/databases/main/user_directory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index 736e8f845d9d..c6a2ace88cdb 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -704,7 +704,7 @@ def _get_shared_rooms_for_users_txn(txn): "get_shared_rooms_for_users", _get_shared_rooms_for_users_txn ) - return set(row["room_id"] for row in rows) + return {row["room_id"] for row in rows} async def get_user_directory_stream_pos(self) -> int: return await self.db_pool.simple_select_one_onecol( From 679810a9458ed137e9f6f63efd970289476d073e Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 2 Sep 2020 12:07:24 +0100 Subject: [PATCH 30/32] Update synapse/storage/databases/main/user_directory.py Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- synapse/storage/databases/main/user_directory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/storage/databases/main/user_directory.py b/synapse/storage/databases/main/user_directory.py index c6a2ace88cdb..e198f3dc721c 100644 --- a/synapse/storage/databases/main/user_directory.py +++ b/synapse/storage/databases/main/user_directory.py @@ -693,7 +693,7 @@ def _get_shared_rooms_for_users_txn(txn): FROM users_who_share_private_rooms WHERE user_id = ? - AND other_user_id = ?; + AND other_user_id = ? """, (user_id, other_user_id, user_id, other_user_id), ) From 0578bb99a1b9677ddda26951c5852229e1bab399 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 2 Sep 2020 12:07:39 +0100 Subject: [PATCH 31/32] Update UPGRADE.rst Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> --- UPGRADE.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE.rst b/UPGRADE.rst index 519eceb61041..44af6ca1032f 100644 --- a/UPGRADE.rst +++ b/UPGRADE.rst @@ -2,7 +2,7 @@ Upgrading to v1.20.0 ==================== Shared rooms endpoint (MSC2666) ------------------------------- +------------------------------- This release contains a new unstable endpoint `/_matrix/client/uk.half-shot.msc2666/user/shared_rooms/.*` for fetching rooms one user has in common with another. This feature requires the From 078b3e39e6ca5538fcf27e4cc28c25a3131e8377 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Wed, 2 Sep 2020 12:18:16 +0100 Subject: [PATCH 32/32] Fix UPGRADE/CHANGELOG unstable paths unstable unstable unstable Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Co-authored-by: Tulir Asokan --- UPGRADE.rst | 2 +- docs/workers.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/UPGRADE.rst b/UPGRADE.rst index 44af6ca1032f..77be1b2952a6 100644 --- a/UPGRADE.rst +++ b/UPGRADE.rst @@ -4,7 +4,7 @@ Upgrading to v1.20.0 Shared rooms endpoint (MSC2666) ------------------------------- -This release contains a new unstable endpoint `/_matrix/client/uk.half-shot.msc2666/user/shared_rooms/.*` +This release contains a new unstable endpoint `/_matrix/client/unstable/uk.half-shot.msc2666/user/shared_rooms/.*` for fetching rooms one user has in common with another. This feature requires the `update_user_directory` config flag to be `True`. If you are you are using a `synapse.app.user_dir` worker, requests to this endpoint must be handled by that worker. diff --git a/docs/workers.md b/docs/workers.md index b1cad9d0e415..7a8f5c89fced 100644 --- a/docs/workers.md +++ b/docs/workers.md @@ -380,7 +380,7 @@ Handles searches in the user directory. It can handle REST endpoints matching the following regular expressions: ^/_matrix/client/(api/v1|r0|unstable)/user_directory/search$ - ^/_matrix/client/uk.half-shot.msc2666/user/shared_rooms/.*$ + ^/_matrix/client/unstable/uk.half-shot.msc2666/user/shared_rooms/.*$ When using this worker you must also set `update_user_directory: False` in the shared configuration file to stop the main synapse running background