Edits/annotations should not have any bundled aggregations calculated. (#12633)
Fixes a regression frompull/12725/head8b309adb43
(#11660) andb65acead42
(#11752) where events which themselves were an edit or an annotation could have bundled aggregations calculated, which is not allowed.
parent
ddc8bba00f
commit
f90d381c7b
|
@ -0,0 +1 @@
|
||||||
|
Fix a bug introduced in Synapse v1.53.0 where bundled aggregations for annotations/edits were incorrectly calculated.
|
|
@ -364,21 +364,29 @@ class RelationsHandler:
|
||||||
The results may include additional events which are related to the
|
The results may include additional events which are related to the
|
||||||
requested events.
|
requested events.
|
||||||
"""
|
"""
|
||||||
# De-duplicate events by ID to handle the same event requested multiple times.
|
# De-duplicated events by ID to handle the same event requested multiple times.
|
||||||
#
|
events_by_id = {}
|
||||||
# State events do not get bundled aggregations.
|
|
||||||
events_by_id = {
|
|
||||||
event.event_id: event for event in events if not event.is_state()
|
|
||||||
}
|
|
||||||
|
|
||||||
# A map of event ID to the relation in that event, if there is one.
|
# A map of event ID to the relation in that event, if there is one.
|
||||||
relations_by_id: Dict[str, str] = {}
|
relations_by_id: Dict[str, str] = {}
|
||||||
for event_id, event in events_by_id.items():
|
for event in events:
|
||||||
|
# State events do not get bundled aggregations.
|
||||||
|
if event.is_state():
|
||||||
|
continue
|
||||||
|
|
||||||
relates_to = event.content.get("m.relates_to")
|
relates_to = event.content.get("m.relates_to")
|
||||||
|
relation_type = None
|
||||||
if isinstance(relates_to, collections.abc.Mapping):
|
if isinstance(relates_to, collections.abc.Mapping):
|
||||||
relation_type = relates_to.get("rel_type")
|
relation_type = relates_to.get("rel_type")
|
||||||
if isinstance(relation_type, str):
|
# An event which is a replacement (ie edit) or annotation (ie,
|
||||||
relations_by_id[event_id] = relation_type
|
# reaction) may not have any other event related to it.
|
||||||
|
if relation_type in (RelationTypes.ANNOTATION, RelationTypes.REPLACE):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# The event should get bundled aggregations.
|
||||||
|
events_by_id[event.event_id] = event
|
||||||
|
# Track the event's relation information for later.
|
||||||
|
if isinstance(relation_type, str):
|
||||||
|
relations_by_id[event.event_id] = relation_type
|
||||||
|
|
||||||
# event ID -> bundled aggregation in non-serialized form.
|
# event ID -> bundled aggregation in non-serialized form.
|
||||||
results: Dict[str, BundledAggregations] = {}
|
results: Dict[str, BundledAggregations] = {}
|
||||||
|
@ -413,16 +421,6 @@ class RelationsHandler:
|
||||||
|
|
||||||
# Fetch other relations per event.
|
# Fetch other relations per event.
|
||||||
for event in events_by_id.values():
|
for event in events_by_id.values():
|
||||||
# An event which is a replacement (ie edit) or annotation (ie, reaction)
|
|
||||||
# may not have any other event related to it.
|
|
||||||
#
|
|
||||||
# XXX This is buggy, see https://github.com/matrix-org/synapse/issues/12566
|
|
||||||
if relations_by_id.get(event.event_id) in (
|
|
||||||
RelationTypes.ANNOTATION,
|
|
||||||
RelationTypes.REPLACE,
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Fetch any annotations (ie, reactions) to bundle with this event.
|
# Fetch any annotations (ie, reactions) to bundle with this event.
|
||||||
annotations = await self.get_annotations_for_event(
|
annotations = await self.get_annotations_for_event(
|
||||||
event.event_id, event.room_id, ignored_users=ignored_users
|
event.event_id, event.room_id, ignored_users=ignored_users
|
||||||
|
|
|
@ -620,6 +620,19 @@ class RelationsTestCase(BaseRelationsTestCase):
|
||||||
{"event_id": edit_event_id, "sender": self.user_id}, m_replace_dict
|
{"event_id": edit_event_id, "sender": self.user_id}, m_replace_dict
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Directly requesting the edit should not have the edit to the edit applied.
|
||||||
|
channel = self.make_request(
|
||||||
|
"GET",
|
||||||
|
f"/rooms/{self.room}/event/{edit_event_id}",
|
||||||
|
access_token=self.user_token,
|
||||||
|
)
|
||||||
|
self.assertEqual(200, channel.code, channel.json_body)
|
||||||
|
self.assertEqual("Wibble", channel.json_body["content"]["body"])
|
||||||
|
self.assertIn("m.new_content", channel.json_body["content"])
|
||||||
|
|
||||||
|
# The relations information should not include the edit to the edit.
|
||||||
|
self.assertNotIn("m.relations", channel.json_body["unsigned"])
|
||||||
|
|
||||||
def test_unknown_relations(self) -> None:
|
def test_unknown_relations(self) -> None:
|
||||||
"""Unknown relations should be accepted."""
|
"""Unknown relations should be accepted."""
|
||||||
channel = self._send_relation("m.relation.test", "m.room.test")
|
channel = self._send_relation("m.relation.test", "m.room.test")
|
||||||
|
@ -984,6 +997,24 @@ class BundledAggregationsTestCase(BaseRelationsTestCase):
|
||||||
|
|
||||||
self._test_bundled_aggregations(RelationTypes.ANNOTATION, assert_annotations, 7)
|
self._test_bundled_aggregations(RelationTypes.ANNOTATION, assert_annotations, 7)
|
||||||
|
|
||||||
|
def test_annotation_to_annotation(self) -> None:
|
||||||
|
"""Any relation to an annotation should be ignored."""
|
||||||
|
channel = self._send_relation(RelationTypes.ANNOTATION, "m.reaction", "a")
|
||||||
|
event_id = channel.json_body["event_id"]
|
||||||
|
self._send_relation(
|
||||||
|
RelationTypes.ANNOTATION, "m.reaction", "b", parent_id=event_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Fetch the initial annotation event to see if it has bundled aggregations.
|
||||||
|
channel = self.make_request(
|
||||||
|
"GET",
|
||||||
|
f"/_matrix/client/v3/rooms/{self.room}/event/{event_id}",
|
||||||
|
access_token=self.user_token,
|
||||||
|
)
|
||||||
|
self.assertEquals(200, channel.code, channel.json_body)
|
||||||
|
# The first annotationt should not have any bundled aggregations.
|
||||||
|
self.assertNotIn("m.relations", channel.json_body["unsigned"])
|
||||||
|
|
||||||
def test_reference(self) -> None:
|
def test_reference(self) -> None:
|
||||||
"""
|
"""
|
||||||
Test that references get correctly bundled.
|
Test that references get correctly bundled.
|
||||||
|
|
Loading…
Reference in New Issue