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

Commit 0ace38b

Browse files
authored
Experimental support for MSC3266 Room Summary API. (#10394)
1 parent 87b62f8 commit 0ace38b

File tree

10 files changed

+289
-115
lines changed

10 files changed

+289
-115
lines changed

changelog.d/10394.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Initial local support for [MSC3266](https://github.com/matrix-org/synapse/pull/10394), Room Summary over the unstable `/rooms/{roomIdOrAlias}/summary` API.

mypy.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ files =
8686
tests/test_event_auth.py,
8787
tests/test_utils,
8888
tests/handlers/test_password_providers.py,
89-
tests/handlers/test_space_summary.py,
89+
tests/handlers/test_room_summary.py,
9090
tests/rest/client/v1/test_login.py,
9191
tests/rest/client/v2_alpha/test_auth.py,
9292
tests/util/test_itertools.py,

synapse/config/experimental.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@ def read_config(self, config: JsonDict, **kwargs):
3838

3939
# MSC3244 (room version capabilities)
4040
self.msc3244_enabled: bool = experimental.get("msc3244_enabled", False)
41+
42+
# MSC3266 (room summary api)
43+
self.msc3266_enabled: bool = experimental.get("msc3266_enabled", False)

synapse/federation/transport/server/federation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ def __init__(
547547
server_name: str,
548548
):
549549
super().__init__(hs, authenticator, ratelimiter, server_name)
550-
self.handler = hs.get_space_summary_handler()
550+
self.handler = hs.get_room_summary_handler()
551551

552552
async def on_GET(
553553
self,
@@ -608,7 +608,7 @@ def __init__(
608608
server_name: str,
609609
):
610610
super().__init__(hs, authenticator, ratelimiter, server_name)
611-
self.handler = hs.get_space_summary_handler()
611+
self.handler = hs.get_room_summary_handler()
612612

613613
async def on_GET(
614614
self,
Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
Membership,
2929
RoomTypes,
3030
)
31-
from synapse.api.errors import AuthError, Codes, SynapseError
31+
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError
3232
from synapse.events import EventBase
3333
from synapse.events.utils import format_event_for_client_v2
3434
from synapse.types import JsonDict
@@ -75,7 +75,7 @@ class _PaginationSession:
7575
processed_rooms: Set[str]
7676

7777

78-
class SpaceSummaryHandler:
78+
class RoomSummaryHandler:
7979
# The time a pagination session remains valid for.
8080
_PAGINATION_SESSION_VALIDITY_PERIOD_MS = 5 * 60 * 1000
8181

@@ -412,7 +412,7 @@ async def _get_room_hierarchy(
412412
room_entry,
413413
children_room_entries,
414414
inaccessible_children,
415-
) = await self._summarize_remote_room_hiearchy(
415+
) = await self._summarize_remote_room_hierarchy(
416416
queue_entry,
417417
suggested_only,
418418
)
@@ -724,7 +724,7 @@ async def _summarize_remote_room(
724724

725725
return results
726726

727-
async def _summarize_remote_room_hiearchy(
727+
async def _summarize_remote_room_hierarchy(
728728
self, room: "_RoomQueueEntry", suggested_only: bool
729729
) -> Tuple[Optional["_RoomEntry"], Dict[str, JsonDict], Set[str]]:
730730
"""
@@ -781,25 +781,25 @@ async def _is_local_room_accessible(
781781
self, room_id: str, requester: Optional[str], origin: Optional[str] = None
782782
) -> bool:
783783
"""
784-
Calculate whether the room should be shown in the spaces summary.
784+
Calculate whether the room should be shown to the requester.
785785
786-
It should be included if:
786+
It should return true if:
787787
788788
* The requester is joined or can join the room (per MSC3173).
789789
* The origin server has any user that is joined or can join the room.
790790
* The history visibility is set to world readable.
791791
792792
Args:
793-
room_id: The room ID to summarize.
793+
room_id: The room ID to check accessibility of.
794794
requester:
795-
The user requesting the summary, if it is a local request. None
796-
if this is a federation request.
795+
The user making the request, if it is a local request.
796+
None if this is a federation request.
797797
origin:
798-
The server requesting the summary, if it is a federation request.
798+
The server making the request, if it is a federation request.
799799
None if this is a local request.
800800
801801
Returns:
802-
True if the room should be included in the spaces summary.
802+
True if the room is accessible to the requesting user or server.
803803
"""
804804
state_ids = await self._store.get_current_state_ids(room_id)
805805

@@ -893,9 +893,9 @@ async def _is_remote_room_accessible(
893893
self, requester: str, room_id: str, room: JsonDict
894894
) -> bool:
895895
"""
896-
Calculate whether the room received over federation should be shown in the spaces summary.
896+
Calculate whether the room received over federation should be shown to the requester.
897897
898-
It should be included if:
898+
It should return true if:
899899
900900
* The requester is joined or can join the room (per MSC3173).
901901
* The history visibility is set to world readable.
@@ -907,10 +907,10 @@ async def _is_remote_room_accessible(
907907
Args:
908908
requester: The user requesting the summary.
909909
room_id: The room ID returned over federation.
910-
room: The summary of the child room returned over federation.
910+
room: The summary of the room returned over federation.
911911
912912
Returns:
913-
True if the room should be included in the spaces summary.
913+
True if the room is accessible to the requesting user.
914914
"""
915915
# The API doesn't return the room version so assume that a
916916
# join rule of knock is valid.
@@ -936,7 +936,7 @@ async def _is_remote_room_accessible(
936936

937937
async def _build_room_entry(self, room_id: str, for_federation: bool) -> JsonDict:
938938
"""
939-
Generate en entry suitable for the 'rooms' list in the summary response.
939+
Generate en entry summarising a single room.
940940
941941
Args:
942942
room_id: The room ID to summarize.
@@ -1024,6 +1024,61 @@ async def _get_child_events(self, room_id: str) -> Iterable[EventBase]:
10241024
# and order to ensure we return stable results.
10251025
return sorted(filter(_has_valid_via, events), key=_child_events_comparison_key)
10261026

1027+
async def get_room_summary(
1028+
self,
1029+
requester: Optional[str],
1030+
room_id: str,
1031+
remote_room_hosts: Optional[List[str]] = None,
1032+
) -> JsonDict:
1033+
"""
1034+
Implementation of the room summary C-S API from MSC3266
1035+
1036+
Args:
1037+
requester: user id of the user making this request, will be None
1038+
for unauthenticated requests
1039+
1040+
room_id: room id to summarise.
1041+
1042+
remote_room_hosts: a list of homeservers to try fetching data through
1043+
if we don't know it ourselves
1044+
1045+
Returns:
1046+
summary dict to return
1047+
"""
1048+
is_in_room = await self._store.is_host_joined(room_id, self._server_name)
1049+
1050+
if is_in_room:
1051+
room_entry = await self._summarize_local_room(
1052+
requester,
1053+
None,
1054+
room_id,
1055+
# Suggested-only doesn't matter since no children are requested.
1056+
suggested_only=False,
1057+
max_children=0,
1058+
)
1059+
1060+
if not room_entry:
1061+
raise NotFoundError("Room not found or is not accessible")
1062+
1063+
room_summary = room_entry.room
1064+
1065+
# If there was a requester, add their membership.
1066+
if requester:
1067+
(
1068+
membership,
1069+
_,
1070+
) = await self._store.get_local_current_membership_for_user_in_room(
1071+
requester, room_id
1072+
)
1073+
1074+
room_summary["membership"] = membership or "leave"
1075+
else:
1076+
# TODO federation API, descoped from initial unstable implementation
1077+
# as MSC needs more maturing on that side.
1078+
raise SynapseError(400, "Federation is not currently supported.")
1079+
1080+
return room_summary
1081+
10271082

10281083
@attr.s(frozen=True, slots=True, auto_attribs=True)
10291084
class _RoomQueueEntry:

synapse/http/servlet.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,28 @@
1414

1515
""" This module contains base REST classes for constructing REST servlets. """
1616
import logging
17-
from typing import Iterable, List, Mapping, Optional, Sequence, overload
17+
from typing import (
18+
TYPE_CHECKING,
19+
Iterable,
20+
List,
21+
Mapping,
22+
Optional,
23+
Sequence,
24+
Tuple,
25+
overload,
26+
)
1827

1928
from typing_extensions import Literal
2029

2130
from twisted.web.server import Request
2231

2332
from synapse.api.errors import Codes, SynapseError
24-
from synapse.types import JsonDict
33+
from synapse.types import JsonDict, RoomAlias, RoomID
2534
from synapse.util import json_decoder
2635

36+
if TYPE_CHECKING:
37+
from synapse.server import HomeServer
38+
2739
logger = logging.getLogger(__name__)
2840

2941

@@ -663,3 +675,45 @@ def register(self, http_server):
663675

664676
else:
665677
raise NotImplementedError("RestServlet must register something.")
678+
679+
680+
class ResolveRoomIdMixin:
681+
def __init__(self, hs: "HomeServer"):
682+
self.room_member_handler = hs.get_room_member_handler()
683+
684+
async def resolve_room_id(
685+
self, room_identifier: str, remote_room_hosts: Optional[List[str]] = None
686+
) -> Tuple[str, Optional[List[str]]]:
687+
"""
688+
Resolve a room identifier to a room ID, if necessary.
689+
690+
This also performanes checks to ensure the room ID is of the proper form.
691+
692+
Args:
693+
room_identifier: The room ID or alias.
694+
remote_room_hosts: The potential remote room hosts to use.
695+
696+
Returns:
697+
The resolved room ID.
698+
699+
Raises:
700+
SynapseError if the room ID is of the wrong form.
701+
"""
702+
if RoomID.is_valid(room_identifier):
703+
resolved_room_id = room_identifier
704+
elif RoomAlias.is_valid(room_identifier):
705+
room_alias = RoomAlias.from_string(room_identifier)
706+
(
707+
room_id,
708+
remote_room_hosts,
709+
) = await self.room_member_handler.lookup_room_alias(room_alias)
710+
resolved_room_id = room_id.to_string()
711+
else:
712+
raise SynapseError(
713+
400, "%s was not legal room ID or room alias" % (room_identifier,)
714+
)
715+
if not resolved_room_id:
716+
raise SynapseError(
717+
400, "Unknown room ID or room alias %s" % room_identifier
718+
)
719+
return resolved_room_id, remote_room_hosts

synapse/rest/admin/rooms.py

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError
2121
from synapse.api.filtering import Filter
2222
from synapse.http.servlet import (
23+
ResolveRoomIdMixin,
2324
RestServlet,
2425
assert_params_in_dict,
2526
parse_integer,
@@ -33,7 +34,7 @@
3334
assert_user_is_admin,
3435
)
3536
from synapse.storage.databases.main.room import RoomSortOrder
36-
from synapse.types import JsonDict, RoomAlias, RoomID, UserID, create_requester
37+
from synapse.types import JsonDict, UserID, create_requester
3738
from synapse.util import json_decoder
3839

3940
if TYPE_CHECKING:
@@ -45,48 +46,6 @@
4546
logger = logging.getLogger(__name__)
4647

4748

48-
class ResolveRoomIdMixin:
49-
def __init__(self, hs: "HomeServer"):
50-
self.room_member_handler = hs.get_room_member_handler()
51-
52-
async def resolve_room_id(
53-
self, room_identifier: str, remote_room_hosts: Optional[List[str]] = None
54-
) -> Tuple[str, Optional[List[str]]]:
55-
"""
56-
Resolve a room identifier to a room ID, if necessary.
57-
58-
This also performanes checks to ensure the room ID is of the proper form.
59-
60-
Args:
61-
room_identifier: The room ID or alias.
62-
remote_room_hosts: The potential remote room hosts to use.
63-
64-
Returns:
65-
The resolved room ID.
66-
67-
Raises:
68-
SynapseError if the room ID is of the wrong form.
69-
"""
70-
if RoomID.is_valid(room_identifier):
71-
resolved_room_id = room_identifier
72-
elif RoomAlias.is_valid(room_identifier):
73-
room_alias = RoomAlias.from_string(room_identifier)
74-
(
75-
room_id,
76-
remote_room_hosts,
77-
) = await self.room_member_handler.lookup_room_alias(room_alias)
78-
resolved_room_id = room_id.to_string()
79-
else:
80-
raise SynapseError(
81-
400, "%s was not legal room ID or room alias" % (room_identifier,)
82-
)
83-
if not resolved_room_id:
84-
raise SynapseError(
85-
400, "Unknown room ID or room alias %s" % room_identifier
86-
)
87-
return resolved_room_id, remote_room_hosts
88-
89-
9049
class ShutdownRoomRestServlet(RestServlet):
9150
"""Shuts down a room by removing all local users from the room and blocking
9251
all future invites and joins to the room. Any local aliases will be repointed

0 commit comments

Comments
 (0)