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

Commit

Permalink
Experimental support for MSC3266 Room Summary API. (#10394)
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy authored Aug 16, 2021
1 parent 87b62f8 commit 0ace38b
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 115 deletions.
1 change: 1 addition & 0 deletions changelog.d/10394.feature
Original file line number Diff line number Diff line change
@@ -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 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions synapse/config/experimental.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ def read_config(self, config: JsonDict, **kwargs):

# 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)
4 changes: 2 additions & 2 deletions synapse/federation/transport/server/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ def __init__(
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,
Expand Down Expand Up @@ -608,7 +608,7 @@ def __init__(
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -412,7 +412,7 @@ async def _get_room_hierarchy(
room_entry,
children_room_entries,
inaccessible_children,
) = await self._summarize_remote_room_hiearchy(
) = await self._summarize_remote_room_hierarchy(
queue_entry,
suggested_only,
)
Expand Down Expand Up @@ -724,7 +724,7 @@ async def _summarize_remote_room(

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]]:
"""
Expand Down Expand Up @@ -781,25 +781,25 @@ async def _is_local_room_accessible(
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)

Expand Down Expand Up @@ -893,9 +893,9 @@ async def _is_remote_room_accessible(
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.
Expand All @@ -907,10 +907,10 @@ async def _is_remote_room_accessible(
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.
Expand All @@ -936,7 +936,7 @@ async def _is_remote_room_accessible(

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.
Expand Down Expand Up @@ -1024,6 +1024,61 @@ async def _get_child_events(self, room_id: str) -> Iterable[EventBase]:
# 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:
Expand Down
58 changes: 56 additions & 2 deletions synapse/http/servlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)


Expand Down Expand Up @@ -663,3 +675,45 @@ def register(self, http_server):

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
45 changes: 2 additions & 43 deletions synapse/rest/admin/rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
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,
Expand All @@ -33,7 +34,7 @@
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:
Expand All @@ -45,48 +46,6 @@
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
Expand Down
Loading

0 comments on commit 0ace38b

Please sign in to comment.