-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Consolidate logic for parsing relations. #12693
Changes from 2 commits
e50674f
f9d63aa
1ff43dd
c5ea31a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Consolidate parsing of relation information from events. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1060,20 +1060,11 @@ async def _validate_event_relation(self, event: EventBase) -> None: | |
| SynapseError if the event is invalid. | ||
| """ | ||
|
|
||
| relation = event.content.get("m.relates_to") | ||
| relation = event.relation() | ||
| if not relation: | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This didn't properly handle non-dict |
||
| return | ||
|
|
||
| relation_type = relation.get("rel_type") | ||
| if not relation_type: | ||
| return | ||
|
|
||
| # Ensure the parent is real. | ||
| relates_to = relation.get("event_id") | ||
| if not relates_to: | ||
| return | ||
|
Comment on lines
-1067
to
-1074
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This didn't properly ignore non-string fields. |
||
|
|
||
| parent_event = await self.store.get_event(relates_to, allow_none=True) | ||
| parent_event = await self.store.get_event(relation.parent_id, allow_none=True) | ||
| if parent_event: | ||
| # And in the same room. | ||
| if parent_event.room_id != event.room_id: | ||
|
|
@@ -1082,28 +1073,31 @@ async def _validate_event_relation(self, event: EventBase) -> None: | |
| else: | ||
| # There must be some reason that the client knows the event exists, | ||
| # see if there are existing relations. If so, assume everything is fine. | ||
| if not await self.store.event_is_target_of_relation(relates_to): | ||
| if not await self.store.event_is_target_of_relation(relation.parent_id): | ||
| # Otherwise, the client can't know about the parent event! | ||
| raise SynapseError(400, "Can't send relation to unknown event") | ||
|
|
||
| # If this event is an annotation then we check that that the sender | ||
| # can't annotate the same way twice (e.g. stops users from liking an | ||
| # event multiple times). | ||
| if relation_type == RelationTypes.ANNOTATION: | ||
| aggregation_key = relation["key"] | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would raise a 500 on a missing key, now it will 400. |
||
| if relation.rel_type == RelationTypes.ANNOTATION: | ||
| aggregation_key = relation.aggregation_key | ||
|
|
||
| if aggregation_key is None: | ||
| raise SynapseError(400, "Missing aggregation key") | ||
|
|
||
| if len(aggregation_key) > 500: | ||
| raise SynapseError(400, "Aggregation key is too long") | ||
|
|
||
| already_exists = await self.store.has_user_annotated_event( | ||
| relates_to, event.type, aggregation_key, event.sender | ||
| relation.parent_id, event.type, aggregation_key, event.sender | ||
| ) | ||
| if already_exists: | ||
| raise SynapseError(400, "Can't send same reaction twice") | ||
|
|
||
| # Don't attempt to start a thread if the parent event is a relation. | ||
| elif relation_type == RelationTypes.THREAD: | ||
| if await self.store.event_includes_relation(relates_to): | ||
| elif relation.rel_type == RelationTypes.THREAD: | ||
| if await self.store.event_includes_relation(relation.parent_id): | ||
| raise SynapseError( | ||
| 400, "Cannot start threads from an event with a relation" | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -78,8 +78,8 @@ def _should_count_as_unread(event: EventBase, context: EventContext) -> bool: | |
| return False | ||
|
|
||
| # Exclude edits. | ||
| relates_to = event.content.get("m.relates_to", {}) | ||
| if relates_to.get("rel_type") == RelationTypes.REPLACE: | ||
|
Comment on lines
-81
to
-82
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This didn't properly handle a non-dict |
||
| relates_to = event.relation() | ||
| if relates_to and relates_to.rel_type == RelationTypes.REPLACE: | ||
| return False | ||
|
|
||
| # Mark events that have a non-empty string body as unread. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1807,52 +1807,45 @@ def _handle_event_relations( | |
| txn: The current database transaction. | ||
| event: The event which might have relations. | ||
| """ | ||
| relation = event.content.get("m.relates_to") | ||
| relation = event.relation() | ||
| if not relation: | ||
| # No relations | ||
| # No relation, nothing to do. | ||
| return | ||
|
|
||
| # Relations must have a type and parent event ID. | ||
| rel_type = relation.get("rel_type") | ||
| if not isinstance(rel_type, str): | ||
| return | ||
|
|
||
| parent_id = relation.get("event_id") | ||
| if not isinstance(parent_id, str): | ||
| return | ||
|
|
||
| # Annotations have a key field. | ||
| aggregation_key = None | ||
| if rel_type == RelationTypes.ANNOTATION: | ||
| aggregation_key = relation.get("key") | ||
|
Comment on lines
-1824
to
-1827
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't properly handle non-string keys.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, even after this change it would allow for invalid keys (but just set them to null). I'm unsure if that's "OK" or not. (It seems better than trying to persist a dictionary or other odd data types though!) |
||
|
|
||
| self.db_pool.simple_insert_txn( | ||
| txn, | ||
| table="event_relations", | ||
| values={ | ||
| "event_id": event.event_id, | ||
| "relates_to_id": parent_id, | ||
| "relation_type": rel_type, | ||
| "aggregation_key": aggregation_key, | ||
| "relates_to_id": relation.parent_id, | ||
| "relation_type": relation.rel_type, | ||
| "aggregation_key": relation.aggregation_key, | ||
| }, | ||
| ) | ||
|
|
||
| txn.call_after(self.store.get_relations_for_event.invalidate, (parent_id,)) | ||
| txn.call_after( | ||
| self.store.get_aggregation_groups_for_event.invalidate, (parent_id,) | ||
| self.store.get_relations_for_event.invalidate, (relation.parent_id,) | ||
| ) | ||
| txn.call_after( | ||
| self.store.get_aggregation_groups_for_event.invalidate, | ||
| (relation.parent_id,), | ||
| ) | ||
|
|
||
| if rel_type == RelationTypes.REPLACE: | ||
| txn.call_after(self.store.get_applicable_edit.invalidate, (parent_id,)) | ||
| if relation.rel_type == RelationTypes.REPLACE: | ||
| txn.call_after( | ||
| self.store.get_applicable_edit.invalidate, (relation.parent_id,) | ||
| ) | ||
|
|
||
| if rel_type == RelationTypes.THREAD: | ||
| txn.call_after(self.store.get_thread_summary.invalidate, (parent_id,)) | ||
| if relation.rel_type == RelationTypes.THREAD: | ||
| txn.call_after( | ||
| self.store.get_thread_summary.invalidate, (relation.parent_id,) | ||
| ) | ||
| # It should be safe to only invalidate the cache if the user has not | ||
| # previously participated in the thread, but that's difficult (and | ||
| # potentially error-prone) so it is always invalidated. | ||
| txn.call_after( | ||
| self.store.get_thread_participated.invalidate, | ||
| (parent_id, event.sender), | ||
| (relation.parent_id, event.sender), | ||
| ) | ||
|
|
||
| def _handle_insertion_event( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.