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

Commit 379f265

Browse files
authored
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.
1 parent 7ff22d6 commit 379f265

File tree

4 files changed

+130
-6
lines changed

4 files changed

+130
-6
lines changed

changelog.d/11284.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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).

synapse/events/utils.py

+8
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,14 @@ async def _injected_bundled_relations(
435435
serialized_event: The serialized event which may be modified.
436436
437437
"""
438+
# Do not bundle relations for an event which represents an edit or an
439+
# annotation. It does not make sense for them to have related events.
440+
relates_to = event.content.get("m.relates_to")
441+
if isinstance(relates_to, (dict, frozendict)):
442+
relation_type = relates_to.get("rel_type")
443+
if relation_type in (RelationTypes.ANNOTATION, RelationTypes.REPLACE):
444+
return
445+
438446
event_id = event.event_id
439447

440448
# The bundled relations to include.

synapse/rest/client/relations.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,9 @@ async def on_GET(
230230
original_event = await self._event_serializer.serialize_event(
231231
event, now, bundle_relations=False
232232
)
233-
# Similarly, we don't allow relations to be applied to relations, so we
234-
# return the original relations without any aggregations on top of them
235-
# here.
236-
serialized_events = await self._event_serializer.serialize_events(
237-
events, now, bundle_relations=False
238-
)
233+
# The relations returned for the requested event do include their
234+
# bundled relations.
235+
serialized_events = await self._event_serializer.serialize_events(events, now)
239236

240237
return_value = pagination_chunk.to_dict()
241238
return_value["chunk"] = serialized_events

tests/rest/client/test_relations.py

+118
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,74 @@ def test_aggregation_get_event(self):
526526
},
527527
)
528528

529+
def test_aggregation_get_event_for_annotation(self):
530+
"""Test that annotations do not get bundled relations included
531+
when directly requested.
532+
"""
533+
channel = self._send_relation(RelationTypes.ANNOTATION, "m.reaction", "a")
534+
self.assertEquals(200, channel.code, channel.json_body)
535+
annotation_id = channel.json_body["event_id"]
536+
537+
# Annotate the annotation.
538+
channel = self._send_relation(
539+
RelationTypes.ANNOTATION, "m.reaction", "a", parent_id=annotation_id
540+
)
541+
self.assertEquals(200, channel.code, channel.json_body)
542+
543+
channel = self.make_request(
544+
"GET",
545+
f"/rooms/{self.room}/event/{annotation_id}",
546+
access_token=self.user_token,
547+
)
548+
self.assertEquals(200, channel.code, channel.json_body)
549+
self.assertIsNone(channel.json_body["unsigned"].get("m.relations"))
550+
551+
def test_aggregation_get_event_for_thread(self):
552+
"""Test that threads get bundled relations included when directly requested."""
553+
channel = self._send_relation(RelationTypes.THREAD, "m.room.test")
554+
self.assertEquals(200, channel.code, channel.json_body)
555+
thread_id = channel.json_body["event_id"]
556+
557+
# Annotate the annotation.
558+
channel = self._send_relation(
559+
RelationTypes.ANNOTATION, "m.reaction", "a", parent_id=thread_id
560+
)
561+
self.assertEquals(200, channel.code, channel.json_body)
562+
563+
channel = self.make_request(
564+
"GET",
565+
f"/rooms/{self.room}/event/{thread_id}",
566+
access_token=self.user_token,
567+
)
568+
self.assertEquals(200, channel.code, channel.json_body)
569+
self.assertEquals(
570+
channel.json_body["unsigned"].get("m.relations"),
571+
{
572+
RelationTypes.ANNOTATION: {
573+
"chunk": [{"count": 1, "key": "a", "type": "m.reaction"}]
574+
},
575+
},
576+
)
577+
578+
# It should also be included when the entire thread is requested.
579+
channel = self.make_request(
580+
"GET",
581+
f"/_matrix/client/unstable/rooms/{self.room}/relations/{self.parent_id}?limit=1",
582+
access_token=self.user_token,
583+
)
584+
self.assertEquals(200, channel.code, channel.json_body)
585+
self.assertEqual(len(channel.json_body["chunk"]), 1)
586+
587+
thread_message = channel.json_body["chunk"][0]
588+
self.assertEquals(
589+
thread_message["unsigned"].get("m.relations"),
590+
{
591+
RelationTypes.ANNOTATION: {
592+
"chunk": [{"count": 1, "key": "a", "type": "m.reaction"}]
593+
},
594+
},
595+
)
596+
529597
def test_edit(self):
530598
"""Test that a simple edit works."""
531599

@@ -672,6 +740,56 @@ def test_edit_reply(self):
672740
{"event_id": edit_event_id, "sender": self.user_id}, m_replace_dict
673741
)
674742

743+
def test_edit_edit(self):
744+
"""Test that an edit cannot be edited."""
745+
new_body = {"msgtype": "m.text", "body": "Initial edit"}
746+
channel = self._send_relation(
747+
RelationTypes.REPLACE,
748+
"m.room.message",
749+
content={
750+
"msgtype": "m.text",
751+
"body": "Wibble",
752+
"m.new_content": new_body,
753+
},
754+
)
755+
self.assertEquals(200, channel.code, channel.json_body)
756+
edit_event_id = channel.json_body["event_id"]
757+
758+
# Edit the edit event.
759+
channel = self._send_relation(
760+
RelationTypes.REPLACE,
761+
"m.room.message",
762+
content={
763+
"msgtype": "m.text",
764+
"body": "foo",
765+
"m.new_content": {"msgtype": "m.text", "body": "Ignored edit"},
766+
},
767+
parent_id=edit_event_id,
768+
)
769+
self.assertEquals(200, channel.code, channel.json_body)
770+
771+
# Request the original event.
772+
channel = self.make_request(
773+
"GET",
774+
"/rooms/%s/event/%s" % (self.room, self.parent_id),
775+
access_token=self.user_token,
776+
)
777+
self.assertEquals(200, channel.code, channel.json_body)
778+
# The edit to the edit should be ignored.
779+
self.assertEquals(channel.json_body["content"], new_body)
780+
781+
# The relations information should not include the edit to the edit.
782+
relations_dict = channel.json_body["unsigned"].get("m.relations")
783+
self.assertIn(RelationTypes.REPLACE, relations_dict)
784+
785+
m_replace_dict = relations_dict[RelationTypes.REPLACE]
786+
for key in ["event_id", "sender", "origin_server_ts"]:
787+
self.assertIn(key, m_replace_dict)
788+
789+
self.assert_dict(
790+
{"event_id": edit_event_id, "sender": self.user_id}, m_replace_dict
791+
)
792+
675793
def test_relations_redaction_redacts_edits(self):
676794
"""Test that edits of an event are redacted when the original event
677795
is redacted.

0 commit comments

Comments
 (0)