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

Remove the /send_relation endpoint. #11682

Merged
merged 3 commits into from
Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/11682.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove the unstable `/send_relation` endpoint.
125 changes: 5 additions & 120 deletions synapse/rest/client/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,141 +19,27 @@
"""

import logging
from typing import TYPE_CHECKING, Awaitable, Optional, Tuple
from typing import TYPE_CHECKING, Optional, Tuple

from synapse.api.constants import EventTypes, RelationTypes
from synapse.api.errors import ShadowBanError, SynapseError
from synapse.api.constants import RelationTypes
from synapse.api.errors import SynapseError
from synapse.http.server import HttpServer
from synapse.http.servlet import (
RestServlet,
parse_integer,
parse_json_object_from_request,
parse_string,
)
from synapse.http.servlet import RestServlet, parse_integer, parse_string
from synapse.http.site import SynapseRequest
from synapse.rest.client.transactions import HttpTransactionCache
from synapse.rest.client._base import client_patterns
from synapse.storage.relations import (
AggregationPaginationToken,
PaginationChunk,
RelationPaginationToken,
)
from synapse.types import JsonDict
from synapse.util.stringutils import random_string

from ._base import client_patterns

if TYPE_CHECKING:
from synapse.server import HomeServer

logger = logging.getLogger(__name__)


class RelationSendServlet(RestServlet):
"""Helper API for sending events that have relation data.

Example API shape to send a 👍 reaction to a room:

POST /rooms/!foo/send_relation/$bar/m.annotation/m.reaction?key=%F0%9F%91%8D
{}

{
"event_id": "$foobar"
}
"""

PATTERN = (
"/rooms/(?P<room_id>[^/]*)/send_relation"
"/(?P<parent_id>[^/]*)/(?P<relation_type>[^/]*)/(?P<event_type>[^/]*)"
)

def __init__(self, hs: "HomeServer"):
super().__init__()
self.auth = hs.get_auth()
self.event_creation_handler = hs.get_event_creation_handler()
self.txns = HttpTransactionCache(hs)

def register(self, http_server: HttpServer) -> None:
http_server.register_paths(
"POST",
client_patterns(self.PATTERN + "$", releases=()),
self.on_PUT_or_POST,
self.__class__.__name__,
)
http_server.register_paths(
"PUT",
client_patterns(self.PATTERN + "/(?P<txn_id>[^/]*)$", releases=()),
self.on_PUT,
self.__class__.__name__,
)

def on_PUT(
self,
request: SynapseRequest,
room_id: str,
parent_id: str,
relation_type: str,
event_type: str,
txn_id: Optional[str] = None,
) -> Awaitable[Tuple[int, JsonDict]]:
return self.txns.fetch_or_execute_request(
request,
self.on_PUT_or_POST,
request,
room_id,
parent_id,
relation_type,
event_type,
txn_id,
)

async def on_PUT_or_POST(
self,
request: SynapseRequest,
room_id: str,
parent_id: str,
relation_type: str,
event_type: str,
txn_id: Optional[str] = None,
) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request, allow_guest=True)

if event_type == EventTypes.Member:
# Add relations to a membership is meaningless, so we just deny it
# at the CS API rather than trying to handle it correctly.
raise SynapseError(400, "Cannot send member events with relations")

content = parse_json_object_from_request(request)

aggregation_key = parse_string(request, "key", encoding="utf-8")

content["m.relates_to"] = {
"event_id": parent_id,
"rel_type": relation_type,
}
if aggregation_key is not None:
content["m.relates_to"]["key"] = aggregation_key

event_dict = {
"type": event_type,
"content": content,
"room_id": room_id,
"sender": requester.user.to_string(),
}

try:
(
event,
_,
) = await self.event_creation_handler.create_and_send_nonmember_event(
requester, event_dict=event_dict, txn_id=txn_id
)
event_id = event.event_id
except ShadowBanError:
event_id = "$" + random_string(43)

return 200, {"event_id": event_id}


class RelationPaginationServlet(RestServlet):
"""API to paginate relations on an event by topological ordering, optionally
filtered by relation type and event type.
Expand Down Expand Up @@ -431,7 +317,6 @@ async def on_GET(


def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
RelationSendServlet(hs).register(http_server)
RelationPaginationServlet(hs).register(http_server)
RelationAggregationPaginationServlet(hs).register(http_server)
RelationAggregationGroupPaginationServlet(hs).register(http_server)
26 changes: 13 additions & 13 deletions tests/rest/client/test_relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ def test_send_relation(self):
channel.json_body,
)

def test_deny_membership(self):
"""Test that we deny relations on membership events"""
channel = self._send_relation(RelationTypes.ANNOTATION, EventTypes.Member)
self.assertEquals(400, channel.code, channel.json_body)
Comment on lines -96 to -99
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell there's not need to test this specifically?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure how to confirm that, but the linked MSC didn't have the word "member" or "membership" in it anywhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure either. MSC2677 also doesn't have any mention...

Anyway, I removed this because the client-server API won't let you make a membership event directly anyway, so I don't see why this is an issue!


def test_deny_invalid_event(self):
"""Test that we deny relations on non-existant events"""
channel = self._send_relation(
Expand Down Expand Up @@ -1119,7 +1114,8 @@ def _send_relation(
relation_type: One of `RelationTypes`
event_type: The type of the event to create
key: The aggregation key used for m.annotation relation type.
content: The content of the created event.
content: The content of the created event. Will be modified to configure
the m.relates_to key based on the other provided parameters.
access_token: The access token used to send the relation, defaults
to `self.user_token`
parent_id: The event_id this relation relates to. If None, then self.parent_id
Expand All @@ -1130,17 +1126,21 @@ def _send_relation(
if not access_token:
access_token = self.user_token

query = ""
if key:
query = "?key=" + urllib.parse.quote_plus(key.encode("utf-8"))

original_id = parent_id if parent_id else self.parent_id

if content is None:
content = {}
content["m.relates_to"] = {
"event_id": original_id,
"rel_type": relation_type,
}
if key is not None:
content["m.relates_to"]["key"] = key
Comment on lines +1131 to +1138
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pretty much inlines the logic from /send_relation into the helper method for tests.


channel = self.make_request(
"POST",
"/_matrix/client/unstable/rooms/%s/send_relation/%s/%s/%s%s"
% (self.room, original_id, relation_type, event_type, query),
content or {},
f"/_matrix/client/v3/rooms/{self.room}/send/{event_type}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f yeah!

content,
access_token=access_token,
)
return channel
Expand Down