diff --git a/changelog.d/10394.feature b/changelog.d/10394.feature
new file mode 100644
index 0000000000..c8bbc5a740
--- /dev/null
+++ b/changelog.d/10394.feature
@@ -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.
diff --git a/mypy.ini b/mypy.ini
index 5d6cd557bc..e1b9405daa 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -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,
diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index 4c60ee8c28..b918fb15b0 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.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)
diff --git a/synapse/federation/transport/server/federation.py b/synapse/federation/transport/server/federation.py
index 2806337846..7d81cc642c 100644
--- a/synapse/federation/transport/server/federation.py
+++ b/synapse/federation/transport/server/federation.py
@@ -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,
diff --git a/synapse/handlers/space_summary.py b/synapse/handlers/room_summary.py
index c74e90abbc..ac6cfc0da9 100644
--- a/synapse/handlers/space_summary.py
+++ b/synapse/handlers/room_summary.py
@@ -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:
diff --git a/synapse/http/servlet.py b/synapse/http/servlet.py
index 732a1e6aeb..a12fa30bfd 100644
--- a/synapse/http/servlet.py
+++ b/synapse/http/servlet.py
@@ -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
diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py
index 40ee33646c..975c28b225 100644
--- a/synapse/rest/admin/rooms.py
+++ b/synapse/rest/admin/rooms.py
@@ -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
diff --git a/synapse/rest/client/v1/room.py b/synapse/rest/client/v1/room.py
index 2c3be23bc8..d3882a84e2 100644
--- a/synapse/rest/client/v1/room.py
+++ b/synapse/rest/client/v1/room.py
@@ -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)
diff --git a/synapse/server.py b/synapse/server.py
index 6c867f0f47..de6517663e 100644
--- a/synapse/server.py
+++ b/synapse/server.py
@@ -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:
diff --git a/tests/handlers/test_space_summary.py b/tests/handlers/test_room_summary.py
index bc8e131f4a..732d746e38 100644
--- a/tests/handlers/test_space_summary.py
+++ b/tests/handlers/test_room_summary.py
@@ -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)
|