forked from MirrorHub/synapse
Experimental support for MSC3266 Room Summary API. (#10394)
This commit is contained in:
parent
87b62f8bb2
commit
0ace38b7b3
10 changed files with 289 additions and 115 deletions
1
changelog.d/10394.feature
Normal file
1
changelog.d/10394.feature
Normal file
|
@ -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.
|
2
mypy.ini
2
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,
|
||||
|
|
|
@ -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)
|
Loading…
Reference in a new issue