diff --git a/synapse/api/constants.py b/synapse/api/constants.py
index 6f9239d21c..0f224b34cd 100644
--- a/synapse/api/constants.py
+++ b/synapse/api/constants.py
@@ -233,6 +233,9 @@ class EventContentFields:
# The authorising user for joining a restricted room.
AUTHORISING_USER: Final = "join_authorised_via_users_server"
+ # Use for mentioning users.
+ MSC3952_MENTIONS: Final = "org.matrix.msc3952.mentions"
+
# an unspecced field added to to-device messages to identify them uniquely-ish
TO_DEVICE_MSGID: Final = "org.matrix.msgid"
diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index 2590c88cde..d2d0270ddd 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.py
@@ -168,3 +168,8 @@ class ExperimentalConfig(Config):
# MSC3925: do not replace events with their edits
self.msc3925_inhibit_edit = experimental.get("msc3925_inhibit_edit", False)
+
+ # MSC3952: Intentional mentions
+ self.msc3952_intentional_mentions = experimental.get(
+ "msc3952_intentional_mentions", False
+ )
diff --git a/synapse/push/bulk_push_rule_evaluator.py b/synapse/push/bulk_push_rule_evaluator.py
index f27ba64d53..deaec19564 100644
--- a/synapse/push/bulk_push_rule_evaluator.py
+++ b/synapse/push/bulk_push_rule_evaluator.py
@@ -22,13 +22,20 @@ from typing import (
List,
Mapping,
Optional,
+ Set,
Tuple,
Union,
)
from prometheus_client import Counter
-from synapse.api.constants import MAIN_TIMELINE, EventTypes, Membership, RelationTypes
+from synapse.api.constants import (
+ MAIN_TIMELINE,
+ EventContentFields,
+ EventTypes,
+ Membership,
+ RelationTypes,
+)
from synapse.api.room_versions import PushRuleRoomFlag, RoomVersion
from synapse.event_auth import auth_types_for_event, get_user_power_level
from synapse.events import EventBase, relation_from_event
@@ -342,8 +349,24 @@ class BulkPushRuleEvaluator:
for user_id, level in notification_levels.items():
notification_levels[user_id] = int(level)
+ # Pull out any user and room mentions.
+ mentions = event.content.get(EventContentFields.MSC3952_MENTIONS)
+ user_mentions: Set[str] = set()
+ room_mention = False
+ if isinstance(mentions, dict):
+ # Remove out any non-string items and convert to a set.
+ user_mentions_raw = mentions.get("user_ids")
+ if isinstance(user_mentions_raw, list):
+ user_mentions = set(
+ filter(lambda item: isinstance(item, str), user_mentions_raw)
+ )
+ # Room mention is only true if the value is exactly true.
+ room_mention = mentions.get("room") is True
+
evaluator = PushRuleEvaluator(
_flatten_dict(event, room_version=event.room_version),
+ user_mentions,
+ room_mention,
room_member_count,
sender_power_level,
notification_levels,
diff --git a/synapse/storage/databases/main/push_rule.py b/synapse/storage/databases/main/push_rule.py
index 14ca167b34..466a1145b7 100644
--- a/synapse/storage/databases/main/push_rule.py
+++ b/synapse/storage/databases/main/push_rule.py
@@ -89,6 +89,7 @@ def _load_rules(
msc1767_enabled=experimental_config.msc1767_enabled,
msc3664_enabled=experimental_config.msc3664_enabled,
msc3381_polls_enabled=experimental_config.msc3381_polls_enabled,
+ msc3952_intentional_mentions=experimental_config.msc3952_intentional_mentions,
)
return filtered_rules
|