@@ -0,0 +1 @@ | |||
Initial local support for [MSC3266](https://github.com/matrix-org/synapse/pull/10394), Room Summary over the unstable `/rooms/{roomIdOrAlias}/summary` API. |
@@ -86,7 +86,7 @@ files = | |||
tests/test_event_auth.py, | |||
tests/test_utils, | |||
tests/handlers/test_password_providers.py, | |||
tests/handlers/test_space_summary.py, | |||
tests/handlers/test_room_summary.py, | |||
tests/rest/client/v1/test_login.py, | |||
tests/rest/client/v2_alpha/test_auth.py, | |||
tests/util/test_itertools.py, | |||
@@ -38,3 +38,6 @@ class ExperimentalConfig(Config): | |||
# MSC3244 (room version capabilities) | |||
self.msc3244_enabled: bool = experimental.get("msc3244_enabled", False) | |||
# MSC3266 (room summary api) | |||
self.msc3266_enabled: bool = experimental.get("msc3266_enabled", False) |
@@ -547,7 +547,7 @@ class FederationSpaceSummaryServlet(BaseFederationServlet): | |||
server_name: str, | |||
): | |||
super().__init__(hs, authenticator, ratelimiter, server_name) | |||
self.handler = hs.get_space_summary_handler() | |||
self.handler = hs.get_room_summary_handler() | |||
async def on_GET( | |||
self, | |||
@@ -608,7 +608,7 @@ class FederationRoomHierarchyServlet(BaseFederationServlet): | |||
server_name: str, | |||
): | |||
super().__init__(hs, authenticator, ratelimiter, server_name) | |||
self.handler = hs.get_space_summary_handler() | |||
self.handler = hs.get_room_summary_handler() | |||
async def on_GET( | |||
self, | |||
@@ -28,7 +28,7 @@ from synapse.api.constants import ( | |||
Membership, | |||
RoomTypes, | |||
) | |||
from synapse.api.errors import AuthError, Codes, SynapseError | |||
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError | |||
from synapse.events import EventBase | |||
from synapse.events.utils import format_event_for_client_v2 | |||
from synapse.types import JsonDict | |||
@@ -75,7 +75,7 @@ class _PaginationSession: | |||
processed_rooms: Set[str] | |||
class SpaceSummaryHandler: | |||
class RoomSummaryHandler: | |||
# The time a pagination session remains valid for. | |||
_PAGINATION_SESSION_VALIDITY_PERIOD_MS = 5 * 60 * 1000 | |||
@@ -412,7 +412,7 @@ class SpaceSummaryHandler: | |||
room_entry, | |||
children_room_entries, | |||
inaccessible_children, | |||
) = await self._summarize_remote_room_hiearchy( | |||
) = await self._summarize_remote_room_hierarchy( | |||
queue_entry, | |||
suggested_only, | |||
) | |||
@@ -724,7 +724,7 @@ class SpaceSummaryHandler: | |||
return results | |||
async def _summarize_remote_room_hiearchy( | |||
async def _summarize_remote_room_hierarchy( | |||
self, room: "_RoomQueueEntry", suggested_only: bool | |||
) -> Tuple[Optional["_RoomEntry"], Dict[str, JsonDict], Set[str]]: | |||
""" | |||
@@ -781,25 +781,25 @@ class SpaceSummaryHandler: | |||
self, room_id: str, requester: Optional[str], origin: Optional[str] = None | |||
) -> bool: | |||
""" | |||
Calculate whether the room should be shown in the spaces summary. | |||
Calculate whether the room should be shown to the requester. | |||
It should be included if: | |||
It should return true if: | |||
* The requester is joined or can join the room (per MSC3173). | |||
* The origin server has any user that is joined or can join the room. | |||
* The history visibility is set to world readable. | |||
Args: | |||
room_id: The room ID to summarize. | |||
room_id: The room ID to check accessibility of. | |||
requester: | |||
The user requesting the summary, if it is a local request. None | |||
if this is a federation request. | |||
The user making the request, if it is a local request. | |||
None if this is a federation request. | |||
origin: | |||
The server requesting the summary, if it is a federation request. | |||
The server making the request, if it is a federation request. | |||
None if this is a local request. | |||
Returns: | |||
True if the room should be included in the spaces summary. | |||
True if the room is accessible to the requesting user or server. | |||
""" | |||
state_ids = await self._store.get_current_state_ids(room_id) | |||
@@ -893,9 +893,9 @@ class SpaceSummaryHandler: | |||
self, requester: str, room_id: str, room: JsonDict | |||
) -> bool: | |||
""" | |||
Calculate whether the room received over federation should be shown in the spaces summary. | |||
Calculate whether the room received over federation should be shown to the requester. | |||
It should be included if: | |||
It should return true if: | |||
* The requester is joined or can join the room (per MSC3173). | |||
* The history visibility is set to world readable. | |||
@@ -907,10 +907,10 @@ class SpaceSummaryHandler: | |||
Args: | |||
requester: The user requesting the summary. | |||
room_id: The room ID returned over federation. | |||
room: The summary of the child room returned over federation. | |||
room: The summary of the room returned over federation. | |||
Returns: | |||
True if the room should be included in the spaces summary. | |||
True if the room is accessible to the requesting user. | |||
""" | |||
# The API doesn't return the room version so assume that a | |||
# join rule of knock is valid. | |||
@@ -936,7 +936,7 @@ class SpaceSummaryHandler: | |||
async def _build_room_entry(self, room_id: str, for_federation: bool) -> JsonDict: | |||
""" | |||
Generate en entry suitable for the 'rooms' list in the summary response. | |||
Generate en entry summarising a single room. | |||
Args: | |||
room_id: The room ID to summarize. | |||
@@ -1024,6 +1024,61 @@ class SpaceSummaryHandler: | |||
# and order to ensure we return stable results. | |||
return sorted(filter(_has_valid_via, events), key=_child_events_comparison_key) | |||
async def get_room_summary( | |||
self, | |||
requester: Optional[str], | |||
room_id: str, | |||
remote_room_hosts: Optional[List[str]] = None, | |||
) -> JsonDict: | |||
""" | |||
Implementation of the room summary C-S API from MSC3266 | |||
Args: | |||
requester: user id of the user making this request, will be None | |||
for unauthenticated requests | |||
room_id: room id to summarise. | |||
remote_room_hosts: a list of homeservers to try fetching data through | |||
if we don't know it ourselves | |||
Returns: | |||
summary dict to return | |||
""" | |||
is_in_room = await self._store.is_host_joined(room_id, self._server_name) | |||
if is_in_room: | |||
room_entry = await self._summarize_local_room( | |||
requester, | |||
None, | |||
room_id, | |||
# Suggested-only doesn't matter since no children are requested. | |||
suggested_only=False, | |||
max_children=0, | |||
) | |||
if not room_entry: | |||
raise NotFoundError("Room not found or is not accessible") | |||
room_summary = room_entry.room | |||
# If there was a requester, add their membership. | |||
if requester: | |||
( | |||
membership, | |||
_, | |||
) = await self._store.get_local_current_membership_for_user_in_room( | |||
requester, room_id | |||
) | |||
room_summary["membership"] = membership or "leave" | |||
else: | |||
# TODO federation API, descoped from initial unstable implementation | |||
# as MSC needs more maturing on that side. | |||
raise SynapseError(400, "Federation is not currently supported.") | |||
return room_summary | |||
@attr.s(frozen=True, slots=True, auto_attribs=True) | |||
class _RoomQueueEntry: |
@@ -14,16 +14,28 @@ | |||
""" This module contains base REST classes for constructing REST servlets. """ | |||
import logging | |||
from typing import Iterable, List, Mapping, Optional, Sequence, overload | |||
from typing import ( | |||
TYPE_CHECKING, | |||
Iterable, | |||
List, | |||
Mapping, | |||
Optional, | |||
Sequence, | |||
Tuple, | |||
overload, | |||
) | |||
from typing_extensions import Literal | |||
from twisted.web.server import Request | |||
from synapse.api.errors import Codes, SynapseError | |||
from synapse.types import JsonDict | |||
from synapse.types import JsonDict, RoomAlias, RoomID | |||
from synapse.util import json_decoder | |||
if TYPE_CHECKING: | |||
from synapse.server import HomeServer | |||
logger = logging.getLogger(__name__) | |||
@@ -663,3 +675,45 @@ class RestServlet: | |||
else: | |||
raise NotImplementedError("RestServlet must register something.") | |||
class ResolveRoomIdMixin: | |||
def __init__(self, hs: "HomeServer"): | |||
self.room_member_handler = hs.get_room_member_handler() | |||
async def resolve_room_id( | |||
self, room_identifier: str, remote_room_hosts: Optional[List[str]] = None | |||
) -> Tuple[str, Optional[List[str]]]: | |||
""" | |||
Resolve a room identifier to a room ID, if necessary. | |||
This also performanes checks to ensure the room ID is of the proper form. | |||
Args: | |||
room_identifier: The room ID or alias. | |||
remote_room_hosts: The potential remote room hosts to use. | |||
Returns: | |||
The resolved room ID. | |||
Raises: | |||
SynapseError if the room ID is of the wrong form. | |||
""" | |||
if RoomID.is_valid(room_identifier): | |||
resolved_room_id = room_identifier | |||
elif RoomAlias.is_valid(room_identifier): | |||
room_alias = RoomAlias.from_string(room_identifier) | |||
( | |||
room_id, | |||
remote_room_hosts, | |||
) = await self.room_member_handler.lookup_room_alias(room_alias) | |||
resolved_room_id = room_id.to_string() | |||
else: | |||
raise SynapseError( | |||
400, "%s was not legal room ID or room alias" % (room_identifier,) | |||
) | |||
if not resolved_room_id: | |||
raise SynapseError( | |||
400, "Unknown room ID or room alias %s" % room_identifier | |||
) | |||
return resolved_room_id, remote_room_hosts |
@@ -20,6 +20,7 @@ from synapse.api.constants import EventTypes, JoinRules, Membership | |||
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError | |||
from synapse.api.filtering import Filter | |||
from synapse.http.servlet import ( | |||
ResolveRoomIdMixin, | |||
RestServlet, | |||
assert_params_in_dict, | |||
parse_integer, | |||
@@ -33,7 +34,7 @@ from synapse.rest.admin._base import ( | |||
assert_user_is_admin, | |||
) | |||
from synapse.storage.databases.main.room import RoomSortOrder | |||
from synapse.types import JsonDict, RoomAlias, RoomID, UserID, create_requester | |||
from synapse.types import JsonDict, UserID, create_requester | |||
from synapse.util import json_decoder | |||
if TYPE_CHECKING: | |||
@@ -45,48 +46,6 @@ if TYPE_CHECKING: | |||
logger = logging.getLogger(__name__) | |||
class ResolveRoomIdMixin: | |||
def __init__(self, hs: "HomeServer"): | |||
self.room_member_handler = hs.get_room_member_handler() | |||
async def resolve_room_id( | |||
self, room_identifier: str, remote_room_hosts: Optional[List[str]] = None | |||
) -> Tuple[str, Optional[List[str]]]: | |||
""" | |||
Resolve a room identifier to a room ID, if necessary. | |||
This also performanes checks to ensure the room ID is of the proper form. | |||
Args: | |||
room_identifier: The room ID or alias. | |||
remote_room_hosts: The potential remote room hosts to use. | |||
Returns: | |||
The resolved room ID. | |||
Raises: | |||
SynapseError if the room ID is of the wrong form. | |||
""" | |||
if RoomID.is_valid(room_identifier): | |||
resolved_room_id = room_identifier | |||
elif RoomAlias.is_valid(room_identifier): | |||
room_alias = RoomAlias.from_string(room_identifier) | |||
( | |||
room_id, | |||
remote_room_hosts, | |||
) = await self.room_member_handler.lookup_room_alias(room_alias) | |||
resolved_room_id = room_id.to_string() | |||
else: | |||
raise SynapseError( | |||
400, "%s was not legal room ID or room alias" % (room_identifier,) | |||
) | |||
if not resolved_room_id: | |||
raise SynapseError( | |||
400, "Unknown room ID or room alias %s" % room_identifier | |||
) | |||
return resolved_room_id, remote_room_hosts | |||
class ShutdownRoomRestServlet(RestServlet): | |||
"""Shuts down a room by removing all local users from the room and blocking | |||
all future invites and joins to the room. Any local aliases will be repointed | |||
@@ -24,12 +24,14 @@ from synapse.api.errors import ( | |||
AuthError, | |||
Codes, | |||
InvalidClientCredentialsError, | |||
MissingClientTokenError, | |||
ShadowBanError, | |||
SynapseError, | |||
) | |||
from synapse.api.filtering import Filter | |||
from synapse.events.utils import format_event_for_client_v2 | |||
from synapse.http.servlet import ( | |||
ResolveRoomIdMixin, | |||
RestServlet, | |||
assert_params_in_dict, | |||
parse_boolean, | |||
@@ -44,14 +46,7 @@ from synapse.rest.client.transactions import HttpTransactionCache | |||
from synapse.rest.client.v2_alpha._base import client_patterns | |||
from synapse.storage.state import StateFilter | |||
from synapse.streams.config import PaginationConfig | |||
from synapse.types import ( | |||
JsonDict, | |||
RoomAlias, | |||
RoomID, | |||
StreamToken, | |||
ThirdPartyInstanceID, | |||
UserID, | |||
) | |||
from synapse.types import JsonDict, StreamToken, ThirdPartyInstanceID, UserID | |||
from synapse.util import json_decoder | |||
from synapse.util.stringutils import parse_and_validate_server_name, random_string | |||
@@ -266,10 +261,10 @@ class RoomSendEventRestServlet(TransactionRestServlet): | |||
# TODO: Needs unit testing for room ID + alias joins | |||
class JoinRoomAliasServlet(TransactionRestServlet): | |||
class JoinRoomAliasServlet(ResolveRoomIdMixin, TransactionRestServlet): | |||
def __init__(self, hs): | |||
super().__init__(hs) | |||
self.room_member_handler = hs.get_room_member_handler() | |||
super(ResolveRoomIdMixin, self).__init__(hs) # ensure the Mixin is set up | |||
self.auth = hs.get_auth() | |||
def register(self, http_server): | |||
@@ -292,24 +287,13 @@ class JoinRoomAliasServlet(TransactionRestServlet): | |||
# cheekily send invalid bodies. | |||
content = {} | |||
if RoomID.is_valid(room_identifier): | |||
room_id = room_identifier | |||
# twisted.web.server.Request.args is incorrectly defined as Optional[Any] | |||
args: Dict[bytes, List[bytes]] = request.args # type: ignore | |||
remote_room_hosts = parse_strings_from_args( | |||
args, "server_name", required=False | |||
) | |||
elif RoomAlias.is_valid(room_identifier): | |||
handler = self.room_member_handler | |||
room_alias = RoomAlias.from_string(room_identifier) | |||
room_id_obj, remote_room_hosts = await handler.lookup_room_alias(room_alias) | |||
room_id = room_id_obj.to_string() | |||
else: | |||
raise SynapseError( | |||
400, "%s was not legal room ID or room alias" % (room_identifier,) | |||
) | |||
# twisted.web.server.Request.args is incorrectly defined as Optional[Any] | |||
args: Dict[bytes, List[bytes]] = request.args # type: ignore | |||
remote_room_hosts = parse_strings_from_args(args, "server_name", required=False) | |||
room_id, remote_room_hosts = await self.resolve_room_id( | |||
room_identifier, | |||
remote_room_hosts, | |||
) | |||
await self.room_member_handler.update_membership( | |||
requester=requester, | |||
@@ -1002,14 +986,14 @@ class RoomSpaceSummaryRestServlet(RestServlet): | |||
def __init__(self, hs: "HomeServer"): | |||
super().__init__() | |||
self._auth = hs.get_auth() | |||
self._space_summary_handler = hs.get_space_summary_handler() | |||
self._room_summary_handler = hs.get_room_summary_handler() | |||
async def on_GET( | |||
self, request: SynapseRequest, room_id: str | |||
) -> Tuple[int, JsonDict]: | |||
requester = await self._auth.get_user_by_req(request, allow_guest=True) | |||
return 200, await self._space_summary_handler.get_space_summary( | |||
return 200, await self._room_summary_handler.get_space_summary( | |||
requester.user.to_string(), | |||
room_id, | |||
suggested_only=parse_boolean(request, "suggested_only", default=False), | |||
@@ -1035,7 +1019,7 @@ class RoomSpaceSummaryRestServlet(RestServlet): | |||
400, "'max_rooms_per_space' must be an integer", Codes.BAD_JSON | |||
) | |||
return 200, await self._space_summary_handler.get_space_summary( | |||
return 200, await self._room_summary_handler.get_space_summary( | |||
requester.user.to_string(), | |||
room_id, | |||
suggested_only=suggested_only, | |||
@@ -1054,7 +1038,7 @@ class RoomHierarchyRestServlet(RestServlet): | |||
def __init__(self, hs: "HomeServer"): | |||
super().__init__() | |||
self._auth = hs.get_auth() | |||
self._space_summary_handler = hs.get_space_summary_handler() | |||
self._room_summary_handler = hs.get_room_summary_handler() | |||
async def on_GET( | |||
self, request: SynapseRequest, room_id: str | |||
@@ -1073,7 +1057,7 @@ class RoomHierarchyRestServlet(RestServlet): | |||
400, "'limit' must be a positive integer", Codes.BAD_JSON | |||
) | |||
return 200, await self._space_summary_handler.get_room_hierarchy( | |||
return 200, await self._room_summary_handler.get_room_hierarchy( | |||
requester.user.to_string(), | |||
room_id, | |||
suggested_only=parse_boolean(request, "suggested_only", default=False), | |||
@@ -1083,6 +1067,44 @@ class RoomHierarchyRestServlet(RestServlet): | |||
) | |||
class RoomSummaryRestServlet(ResolveRoomIdMixin, RestServlet): | |||
PATTERNS = ( | |||
re.compile( | |||
"^/_matrix/client/unstable/im.nheko.summary" | |||
"/rooms/(?P<room_identifier>[^/]*)/summary$" | |||
), | |||
) | |||
def __init__(self, hs: "HomeServer"): | |||
super().__init__(hs) | |||
self._auth = hs.get_auth() | |||
self._room_summary_handler = hs.get_room_summary_handler() | |||
async def on_GET( | |||
self, request: SynapseRequest, room_identifier: str | |||
) -> Tuple[int, JsonDict]: | |||
try: | |||
requester = await self._auth.get_user_by_req(request, allow_guest=True) | |||
requester_user_id: Optional[str] = requester.user.to_string() | |||
except MissingClientTokenError: | |||
# auth is optional | |||
requester_user_id = None | |||
# twisted.web.server.Request.args is incorrectly defined as Optional[Any] | |||
args: Dict[bytes, List[bytes]] = request.args # type: ignore | |||
remote_room_hosts = parse_strings_from_args(args, "via", required=False) | |||
room_id, remote_room_hosts = await self.resolve_room_id( | |||
room_identifier, | |||
remote_room_hosts, | |||
) | |||
return 200, await self._room_summary_handler.get_room_summary( | |||
requester_user_id, | |||
room_id, | |||
remote_room_hosts, | |||
) | |||
def register_servlets(hs: "HomeServer", http_server, is_worker=False): | |||
RoomStateEventRestServlet(hs).register(http_server) | |||
RoomMemberListRestServlet(hs).register(http_server) | |||
@@ -1098,6 +1120,8 @@ def register_servlets(hs: "HomeServer", http_server, is_worker=False): | |||
RoomEventContextServlet(hs).register(http_server) | |||
RoomSpaceSummaryRestServlet(hs).register(http_server) | |||
RoomHierarchyRestServlet(hs).register(http_server) | |||
if hs.config.experimental.msc3266_enabled: | |||
RoomSummaryRestServlet(hs).register(http_server) | |||
RoomEventServlet(hs).register(http_server) | |||
JoinedRoomsRestServlet(hs).register(http_server) | |||
RoomAliasListServlet(hs).register(http_server) | |||
@@ -99,10 +99,10 @@ from synapse.handlers.room import ( | |||
from synapse.handlers.room_list import RoomListHandler | |||
from synapse.handlers.room_member import RoomMemberHandler, RoomMemberMasterHandler | |||
from synapse.handlers.room_member_worker import RoomMemberWorkerHandler | |||
from synapse.handlers.room_summary import RoomSummaryHandler | |||
from synapse.handlers.search import SearchHandler | |||
from synapse.handlers.send_email import SendEmailHandler | |||
from synapse.handlers.set_password import SetPasswordHandler | |||
from synapse.handlers.space_summary import SpaceSummaryHandler | |||
from synapse.handlers.sso import SsoHandler | |||
from synapse.handlers.stats import StatsHandler | |||
from synapse.handlers.sync import SyncHandler | |||
@@ -772,8 +772,8 @@ class HomeServer(metaclass=abc.ABCMeta): | |||
return AccountDataHandler(self) | |||
@cache_in_self | |||
def get_space_summary_handler(self) -> SpaceSummaryHandler: | |||
return SpaceSummaryHandler(self) | |||
def get_room_summary_handler(self) -> RoomSummaryHandler: | |||
return RoomSummaryHandler(self) | |||
@cache_in_self | |||
def get_event_auth_handler(self) -> EventAuthHandler: | |||
@@ -23,10 +23,10 @@ from synapse.api.constants import ( | |||
RestrictedJoinRuleTypes, | |||
RoomTypes, | |||
) | |||
from synapse.api.errors import AuthError, SynapseError | |||
from synapse.api.errors import AuthError, NotFoundError, SynapseError | |||
from synapse.api.room_versions import RoomVersions | |||
from synapse.events import make_event_from_dict | |||
from synapse.handlers.space_summary import _child_events_comparison_key, _RoomEntry | |||
from synapse.handlers.room_summary import _child_events_comparison_key, _RoomEntry | |||
from synapse.rest import admin | |||
from synapse.rest.client.v1 import login, room | |||
from synapse.server import HomeServer | |||
@@ -106,7 +106,7 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
def prepare(self, reactor, clock, hs: HomeServer): | |||
self.hs = hs | |||
self.handler = self.hs.get_space_summary_handler() | |||
self.handler = self.hs.get_room_summary_handler() | |||
# Create a user. | |||
self.user = self.register_user("user", "pass") | |||
@@ -624,14 +624,14 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
), | |||
] | |||
async def summarize_remote_room_hiearchy(_self, room, suggested_only): | |||
async def summarize_remote_room_hierarchy(_self, room, suggested_only): | |||
return requested_room_entry, {subroom: child_room}, set() | |||
# Add a room to the space which is on another server. | |||
self._add_child(self.space, subspace, self.token) | |||
with mock.patch( | |||
"synapse.handlers.space_summary.SpaceSummaryHandler._summarize_remote_room", | |||
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room", | |||
new=summarize_remote_room, | |||
): | |||
result = self.get_success( | |||
@@ -647,8 +647,8 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
self._assert_rooms(result, expected) | |||
with mock.patch( | |||
"synapse.handlers.space_summary.SpaceSummaryHandler._summarize_remote_room_hiearchy", | |||
new=summarize_remote_room_hiearchy, | |||
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room_hierarchy", | |||
new=summarize_remote_room_hierarchy, | |||
): | |||
result = self.get_success( | |||
self.handler.get_room_hierarchy(self.user, self.space) | |||
@@ -774,14 +774,14 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
for child_room in children_rooms | |||
] | |||
async def summarize_remote_room_hiearchy(_self, room, suggested_only): | |||
async def summarize_remote_room_hierarchy(_self, room, suggested_only): | |||
return subspace_room_entry, dict(children_rooms), set() | |||
# Add a room to the space which is on another server. | |||
self._add_child(self.space, subspace, self.token) | |||
with mock.patch( | |||
"synapse.handlers.space_summary.SpaceSummaryHandler._summarize_remote_room", | |||
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room", | |||
new=summarize_remote_room, | |||
): | |||
result = self.get_success( | |||
@@ -814,8 +814,8 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
self._assert_rooms(result, expected) | |||
with mock.patch( | |||
"synapse.handlers.space_summary.SpaceSummaryHandler._summarize_remote_room_hiearchy", | |||
new=summarize_remote_room_hiearchy, | |||
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room_hierarchy", | |||
new=summarize_remote_room_hierarchy, | |||
): | |||
result = self.get_success( | |||
self.handler.get_room_hierarchy(self.user, self.space) | |||
@@ -850,14 +850,14 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
): | |||
return [fed_room_entry] | |||
async def summarize_remote_room_hiearchy(_self, room, suggested_only): | |||
async def summarize_remote_room_hierarchy(_self, room, suggested_only): | |||
return fed_room_entry, {}, set() | |||
# Add a room to the space which is on another server. | |||
self._add_child(self.space, fed_room, self.token) | |||
with mock.patch( | |||
"synapse.handlers.space_summary.SpaceSummaryHandler._summarize_remote_room", | |||
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room", | |||
new=summarize_remote_room, | |||
): | |||
result = self.get_success( | |||
@@ -872,10 +872,88 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase): | |||
self._assert_rooms(result, expected) | |||
with mock.patch( | |||
"synapse.handlers.space_summary.SpaceSummaryHandler._summarize_remote_room_hiearchy", | |||
new=summarize_remote_room_hiearchy, | |||
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room_hierarchy", | |||
new=summarize_remote_room_hierarchy, | |||
): | |||
result = self.get_success( | |||
self.handler.get_room_hierarchy(self.user, self.space) | |||
) | |||
self._assert_hierarchy(result, expected) | |||
class RoomSummaryTestCase(unittest.HomeserverTestCase): | |||
servlets = [ | |||
admin.register_servlets_for_client_rest_resource, | |||
room.register_servlets, | |||
login.register_servlets, | |||
] | |||
def prepare(self, reactor, clock, hs: HomeServer): | |||
self.hs = hs | |||
self.handler = self.hs.get_room_summary_handler() | |||
# Create a user. | |||
self.user = self.register_user("user", "pass") | |||
self.token = self.login("user", "pass") | |||
# Create a simple room. | |||
self.room = self.helper.create_room_as(self.user, tok=self.token) | |||
self.helper.send_state( | |||
self.room, | |||
event_type=EventTypes.JoinRules, | |||
body={"join_rule": JoinRules.INVITE}, | |||
tok=self.token, | |||
) | |||
def test_own_room(self): | |||
"""Test a simple room created by the requester.""" | |||
result = self.get_success(self.handler.get_room_summary(self.user, self.room)) | |||
self.assertEqual(result.get("room_id"), self.room) | |||
def test_visibility(self): | |||
"""A user not in a private room cannot get its summary.""" | |||
user2 = self.register_user("user2", "pass") | |||
token2 = self.login("user2", "pass") | |||
# The user cannot see the room. | |||
self.get_failure(self.handler.get_room_summary(user2, self.room), NotFoundError) | |||
# If the room is made world-readable it should return a result. | |||
self.helper.send_state( | |||
self.room, | |||
event_type=EventTypes.RoomHistoryVisibility, | |||
body={"history_visibility": HistoryVisibility.WORLD_READABLE}, | |||
tok=self.token, | |||
) | |||
result = self.get_success(self.handler.get_room_summary(user2, self.room)) | |||
self.assertEqual(result.get("room_id"), self.room) | |||
# Make it not world-readable again and confirm it results in an error. | |||
self.helper.send_state( | |||
self.room, | |||
event_type=EventTypes.RoomHistoryVisibility, | |||
body={"history_visibility": HistoryVisibility.JOINED}, | |||
tok=self.token, | |||
) | |||
self.get_failure(self.handler.get_room_summary(user2, self.room), NotFoundError) | |||
# If the room is made public it should return a result. | |||
self.helper.send_state( | |||
self.room, | |||
event_type=EventTypes.JoinRules, | |||
body={"join_rule": JoinRules.PUBLIC}, | |||
tok=self.token, | |||
) | |||
result = self.get_success(self.handler.get_room_summary(user2, self.room)) | |||
self.assertEqual(result.get("room_id"), self.room) | |||
# Join the space, make it invite-only again and results should be returned. | |||
self.helper.join(self.room, user2, tok=token2) | |||
self.helper.send_state( | |||
self.room, | |||
event_type=EventTypes.JoinRules, | |||
body={"join_rule": JoinRules.INVITE}, | |||
tok=self.token, | |||
) | |||
result = self.get_success(self.handler.get_room_summary(user2, self.room)) | |||
self.assertEqual(result.get("room_id"), self.room) |