Bundle relations of relations into the `/relations` result. (#11284)
Per updates to MSC2675 which now states that bundled aggregations should be included from the `/relations` endpoint.pull/11467/head
parent
7ff22d6da4
commit
379f2650cf
|
@ -0,0 +1 @@
|
|||
When returning relation events from the `/relations` API, bundle any relations of those relations into the result, per updates to [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675).
|
|
@ -435,6 +435,14 @@ class EventClientSerializer:
|
|||
serialized_event: The serialized event which may be modified.
|
||||
|
||||
"""
|
||||
# Do not bundle relations for an event which represents an edit or an
|
||||
# annotation. It does not make sense for them to have related events.
|
||||
relates_to = event.content.get("m.relates_to")
|
||||
if isinstance(relates_to, (dict, frozendict)):
|
||||
relation_type = relates_to.get("rel_type")
|
||||
if relation_type in (RelationTypes.ANNOTATION, RelationTypes.REPLACE):
|
||||
return
|
||||
|
||||
event_id = event.event_id
|
||||
|
||||
# The bundled relations to include.
|
||||
|
|
|
@ -230,12 +230,9 @@ class RelationPaginationServlet(RestServlet):
|
|||
original_event = await self._event_serializer.serialize_event(
|
||||
event, now, bundle_relations=False
|
||||
)
|
||||
# Similarly, we don't allow relations to be applied to relations, so we
|
||||
# return the original relations without any aggregations on top of them
|
||||
# here.
|
||||
serialized_events = await self._event_serializer.serialize_events(
|
||||
events, now, bundle_relations=False
|
||||
)
|
||||
# The relations returned for the requested event do include their
|
||||
# bundled relations.
|
||||
serialized_events = await self._event_serializer.serialize_events(events, now)
|
||||
|
||||
return_value = pagination_chunk.to_dict()
|
||||
return_value["chunk"] = serialized_events
|
||||
|
|
|
@ -526,6 +526,74 @@ class RelationsTestCase(unittest.HomeserverTestCase):
|
|||
},
|
||||
)
|
||||
|
||||
def test_aggregation_get_event_for_annotation(self):
|
||||
"""Test that annotations do not get bundled relations included
|
||||
when directly requested.
|
||||
"""
|
||||
channel = self._send_relation(RelationTypes.ANNOTATION, "m.reaction", "a")
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
annotation_id = channel.json_body["event_id"]
|
||||
|
||||
# Annotate the annotation.
|
||||
channel = self._send_relation(
|
||||
RelationTypes.ANNOTATION, "m.reaction", "a", parent_id=annotation_id
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
f"/rooms/{self.room}/event/{annotation_id}",
|
||||
access_token=self.user_token,
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
self.assertIsNone(channel.json_body["unsigned"].get("m.relations"))
|
||||
|
||||
def test_aggregation_get_event_for_thread(self):
|
||||
"""Test that threads get bundled relations included when directly requested."""
|
||||
channel = self._send_relation(RelationTypes.THREAD, "m.room.test")
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
thread_id = channel.json_body["event_id"]
|
||||
|
||||
# Annotate the annotation.
|
||||
channel = self._send_relation(
|
||||
RelationTypes.ANNOTATION, "m.reaction", "a", parent_id=thread_id
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
f"/rooms/{self.room}/event/{thread_id}",
|
||||
access_token=self.user_token,
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
self.assertEquals(
|
||||
channel.json_body["unsigned"].get("m.relations"),
|
||||
{
|
||||
RelationTypes.ANNOTATION: {
|
||||
"chunk": [{"count": 1, "key": "a", "type": "m.reaction"}]
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
# It should also be included when the entire thread is requested.
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
f"/_matrix/client/unstable/rooms/{self.room}/relations/{self.parent_id}?limit=1",
|
||||
access_token=self.user_token,
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
self.assertEqual(len(channel.json_body["chunk"]), 1)
|
||||
|
||||
thread_message = channel.json_body["chunk"][0]
|
||||
self.assertEquals(
|
||||
thread_message["unsigned"].get("m.relations"),
|
||||
{
|
||||
RelationTypes.ANNOTATION: {
|
||||
"chunk": [{"count": 1, "key": "a", "type": "m.reaction"}]
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
def test_edit(self):
|
||||
"""Test that a simple edit works."""
|
||||
|
||||
|
@ -672,6 +740,56 @@ class RelationsTestCase(unittest.HomeserverTestCase):
|
|||
{"event_id": edit_event_id, "sender": self.user_id}, m_replace_dict
|
||||
)
|
||||
|
||||
def test_edit_edit(self):
|
||||
"""Test that an edit cannot be edited."""
|
||||
new_body = {"msgtype": "m.text", "body": "Initial edit"}
|
||||
channel = self._send_relation(
|
||||
RelationTypes.REPLACE,
|
||||
"m.room.message",
|
||||
content={
|
||||
"msgtype": "m.text",
|
||||
"body": "Wibble",
|
||||
"m.new_content": new_body,
|
||||
},
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
edit_event_id = channel.json_body["event_id"]
|
||||
|
||||
# Edit the edit event.
|
||||
channel = self._send_relation(
|
||||
RelationTypes.REPLACE,
|
||||
"m.room.message",
|
||||
content={
|
||||
"msgtype": "m.text",
|
||||
"body": "foo",
|
||||
"m.new_content": {"msgtype": "m.text", "body": "Ignored edit"},
|
||||
},
|
||||
parent_id=edit_event_id,
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
|
||||
# Request the original event.
|
||||
channel = self.make_request(
|
||||
"GET",
|
||||
"/rooms/%s/event/%s" % (self.room, self.parent_id),
|
||||
access_token=self.user_token,
|
||||
)
|
||||
self.assertEquals(200, channel.code, channel.json_body)
|
||||
# The edit to the edit should be ignored.
|
||||
self.assertEquals(channel.json_body["content"], new_body)
|
||||
|
||||
# The relations information should not include the edit to the edit.
|
||||
relations_dict = channel.json_body["unsigned"].get("m.relations")
|
||||
self.assertIn(RelationTypes.REPLACE, relations_dict)
|
||||
|
||||
m_replace_dict = relations_dict[RelationTypes.REPLACE]
|
||||
for key in ["event_id", "sender", "origin_server_ts"]:
|
||||
self.assertIn(key, m_replace_dict)
|
||||
|
||||
self.assert_dict(
|
||||
{"event_id": edit_event_id, "sender": self.user_id}, m_replace_dict
|
||||
)
|
||||
|
||||
def test_relations_redaction_redacts_edits(self):
|
||||
"""Test that edits of an event are redacted when the original event
|
||||
is redacted.
|
||||
|
|
Loading…
Reference in New Issue