diff --git a/changelog.d/14094.removal b/changelog.d/14094.removal
new file mode 100644
index 0000000000..6ef03b1a0f
--- /dev/null
+++ b/changelog.d/14094.removal
@@ -0,0 +1 @@
+Remove the experimental implementation of [MSC3772](https://github.com/matrix-org/matrix-spec-proposals/pull/3772).
diff --git a/rust/src/push/base_rules.rs b/rust/src/push/base_rules.rs
index 2a09cf99ae..63240cacfc 100644
--- a/rust/src/push/base_rules.rs
+++ b/rust/src/push/base_rules.rs
@@ -258,19 +258,6 @@ pub const BASE_APPEND_UNDERRIDE_RULES: &[PushRule] = &[
default_enabled: true,
},
PushRule {
- rule_id: Cow::Borrowed("global/underride/.org.matrix.msc3772.thread_reply"),
- priority_class: 1,
- conditions: Cow::Borrowed(&[Condition::Known(KnownCondition::RelationMatch {
- rel_type: Cow::Borrowed("m.thread"),
- event_type_pattern: None,
- sender: None,
- sender_type: Some(Cow::Borrowed("user_id")),
- })]),
- actions: Cow::Borrowed(&[Action::Notify, HIGHLIGHT_FALSE_ACTION]),
- default: true,
- default_enabled: true,
- },
- PushRule {
rule_id: Cow::Borrowed("global/underride/.m.rule.message"),
priority_class: 1,
conditions: Cow::Borrowed(&[Condition::Known(KnownCondition::EventMatch(
diff --git a/rust/src/push/evaluator.rs b/rust/src/push/evaluator.rs
index efe88ec76e..0365dd01dc 100644
--- a/rust/src/push/evaluator.rs
+++ b/rust/src/push/evaluator.rs
@@ -12,10 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::{
- borrow::Cow,
- collections::{BTreeMap, BTreeSet},
-};
+use std::collections::BTreeMap;
use anyhow::{Context, Error};
use lazy_static::lazy_static;
@@ -49,13 +46,6 @@ pub struct PushRuleEvaluator {
/// The `notifications` section of the current power levels in the room.
notification_power_levels: BTreeMap<String, i64>,
- /// The relations related to the event as a mapping from relation type to
- /// set of sender/event type 2-tuples.
- relations: BTreeMap<String, BTreeSet<(String, String)>>,
-
- /// Is running "relation" conditions enabled?
- relation_match_enabled: bool,
-
/// The power level of the sender of the event, or None if event is an
/// outlier.
sender_power_level: Option<i64>,
@@ -70,8 +60,6 @@ impl PushRuleEvaluator {
room_member_count: u64,
sender_power_level: Option<i64>,
notification_power_levels: BTreeMap<String, i64>,
- relations: BTreeMap<String, BTreeSet<(String, String)>>,
- relation_match_enabled: bool,
) -> Result<Self, Error> {
let body = flattened_keys
.get("content.body")
@@ -83,8 +71,6 @@ impl PushRuleEvaluator {
body,
room_member_count,
notification_power_levels,
- relations,
- relation_match_enabled,
sender_power_level,
})
}
@@ -203,89 +189,11 @@ impl PushRuleEvaluator {
false
}
}
- KnownCondition::RelationMatch {
- rel_type,
- event_type_pattern,
- sender,
- sender_type,
- } => {
- self.match_relations(rel_type, sender, sender_type, user_id, event_type_pattern)?
- }
};
Ok(result)
}
- /// Evaluates a relation condition.
- fn match_relations(
- &self,
- rel_type: &str,
- sender: &Option<Cow<str>>,
- sender_type: &Option<Cow<str>>,
- user_id: Option<&str>,
- event_type_pattern: &Option<Cow<str>>,
- ) -> Result<bool, Error> {
- // First check if relation matching is enabled...
- if !self.relation_match_enabled {
- return Ok(false);
- }
-
- // ... and if there are any relations to match against.
- let relations = if let Some(relations) = self.relations.get(rel_type) {
- relations
- } else {
- return Ok(false);
- };
-
- // Extract the sender pattern from the condition
- let sender_pattern = if let Some(sender) = sender {
- Some(sender.as_ref())
- } else if let Some(sender_type) = sender_type {
- if sender_type == "user_id" {
- if let Some(user_id) = user_id {
- Some(user_id)
- } else {
- return Ok(false);
- }
- } else {
- warn!("Unrecognized sender_type: {sender_type}");
- return Ok(false);
- }
- } else {
- None
- };
-
- let mut sender_compiled_pattern = if let Some(pattern) = sender_pattern {
- Some(get_glob_matcher(pattern, GlobMatchType::Whole)?)
- } else {
- None
- };
-
- let mut type_compiled_pattern = if let Some(pattern) = event_type_pattern {
- Some(get_glob_matcher(pattern, GlobMatchType::Whole)?)
- } else {
- None
- };
-
- for (relation_sender, event_type) in relations {
- if let Some(pattern) = &mut sender_compiled_pattern {
- if !pattern.is_match(relation_sender)? {
- continue;
- }
- }
-
- if let Some(pattern) = &mut type_compiled_pattern {
- if !pattern.is_match(event_type)? {
- continue;
- }
- }
-
- return Ok(true);
- }
-
- Ok(false)
- }
-
/// Evaluates a `event_match` condition.
fn match_event_match(
&self,
@@ -359,15 +267,8 @@ impl PushRuleEvaluator {
fn push_rule_evaluator() {
let mut flattened_keys = BTreeMap::new();
flattened_keys.insert("content.body".to_string(), "foo bar bob hello".to_string());
- let evaluator = PushRuleEvaluator::py_new(
- flattened_keys,
- 10,
- Some(0),
- BTreeMap::new(),
- BTreeMap::new(),
- true,
- )
- .unwrap();
+ let evaluator =
+ PushRuleEvaluator::py_new(flattened_keys, 10, Some(0), BTreeMap::new()).unwrap();
let result = evaluator.run(&FilteredPushRules::default(), None, Some("bob"));
assert_eq!(result.len(), 3);
diff --git a/rust/src/push/mod.rs b/rust/src/push/mod.rs
index 208b9c0d73..0dabfab8b8 100644
--- a/rust/src/push/mod.rs
+++ b/rust/src/push/mod.rs
@@ -275,16 +275,6 @@ pub enum KnownCondition {
SenderNotificationPermission {
key: Cow<'static, str>,
},
- #[serde(rename = "org.matrix.msc3772.relation_match")]
- RelationMatch {
- rel_type: Cow<'static, str>,
- #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
- event_type_pattern: Option<Cow<'static, str>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- sender: Option<Cow<'static, str>>,
- #[serde(skip_serializing_if = "Option::is_none")]
- sender_type: Option<Cow<'static, str>>,
- },
}
impl IntoPy<PyObject> for Condition {
@@ -401,21 +391,15 @@ impl PushRules {
pub struct FilteredPushRules {
push_rules: PushRules,
enabled_map: BTreeMap<String, bool>,
- msc3772_enabled: bool,
}
#[pymethods]
impl FilteredPushRules {
#[new]
- pub fn py_new(
- push_rules: PushRules,
- enabled_map: BTreeMap<String, bool>,
- msc3772_enabled: bool,
- ) -> Self {
+ pub fn py_new(push_rules: PushRules, enabled_map: BTreeMap<String, bool>) -> Self {
Self {
push_rules,
enabled_map,
- msc3772_enabled,
}
}
@@ -430,25 +414,13 @@ impl FilteredPushRules {
/// Iterates over all the rules and their enabled state, including base
/// rules, in the order they should be executed in.
fn iter(&self) -> impl Iterator<Item = (&PushRule, bool)> {
- self.push_rules
- .iter()
- .filter(|rule| {
- // Ignore disabled experimental push rules
- if !self.msc3772_enabled
- && rule.rule_id == "global/underride/.org.matrix.msc3772.thread_reply"
- {
- return false;
- }
-
- true
- })
- .map(|r| {
- let enabled = *self
- .enabled_map
- .get(&*r.rule_id)
- .unwrap_or(&r.default_enabled);
- (r, enabled)
- })
+ self.push_rules.iter().map(|r| {
+ let enabled = *self
+ .enabled_map
+ .get(&*r.rule_id)
+ .unwrap_or(&r.default_enabled);
+ (r, enabled)
+ })
}
}
diff --git a/stubs/synapse/synapse_rust/push.pyi b/stubs/synapse/synapse_rust/push.pyi
index 5900e61450..f2a61df660 100644
--- a/stubs/synapse/synapse_rust/push.pyi
+++ b/stubs/synapse/synapse_rust/push.pyi
@@ -25,9 +25,7 @@ class PushRules:
def rules(self) -> Collection[PushRule]: ...
class FilteredPushRules:
- def __init__(
- self, push_rules: PushRules, enabled_map: Dict[str, bool], msc3772_enabled: bool
- ): ...
+ def __init__(self, push_rules: PushRules, enabled_map: Dict[str, bool]): ...
def rules(self) -> Collection[Tuple[PushRule, bool]]: ...
def get_base_rule_ids() -> Collection[str]: ...
@@ -39,8 +37,6 @@ class PushRuleEvaluator:
room_member_count: int,
sender_power_level: Optional[int],
notification_power_levels: Mapping[str, int],
- relations: Mapping[str, Set[Tuple[str, str]]],
- relation_match_enabled: bool,
): ...
def run(
self,
diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index e00cb7096c..f44655516e 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.py
@@ -95,8 +95,6 @@ class ExperimentalConfig(Config):
# MSC2815 (allow room moderators to view redacted event content)
self.msc2815_enabled: bool = experimental.get("msc2815_enabled", False)
- # MSC3772: A push rule for mutual relations.
- self.msc3772_enabled: bool = experimental.get("msc3772_enabled", False)
# MSC3773: Thread notifications
self.msc3773_enabled: bool = experimental.get("msc3773_enabled", False)
diff --git a/synapse/push/bulk_push_rule_evaluator.py b/synapse/push/bulk_push_rule_evaluator.py
index eced182fd5..8d94aeaa32 100644
--- a/synapse/push/bulk_push_rule_evaluator.py
+++ b/synapse/push/bulk_push_rule_evaluator.py
@@ -13,18 +13,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import itertools
import logging
from typing import (
TYPE_CHECKING,
Any,
Collection,
Dict,
- Iterable,
List,
Mapping,
Optional,
- Set,
Tuple,
Union,
)
@@ -38,7 +35,7 @@ from synapse.events.snapshot import EventContext
from synapse.state import POWER_KEY
from synapse.storage.databases.main.roommember import EventIdMembership
from synapse.storage.state import StateFilter
-from synapse.synapse_rust.push import FilteredPushRules, PushRule, PushRuleEvaluator
+from synapse.synapse_rust.push import FilteredPushRules, PushRuleEvaluator
from synapse.util.caches import register_cache
from synapse.util.metrics import measure_func
from synapse.visibility import filter_event_for_clients_with_state
@@ -117,9 +114,6 @@ class BulkPushRuleEvaluator:
resizable=False,
)
- # Whether to support MSC3772 is supported.
- self._relations_match_enabled = self.hs.config.experimental.msc3772_enabled
-
async def _get_rules_for_event(
self,
event: EventBase,
@@ -200,51 +194,6 @@ class BulkPushRuleEvaluator:
return pl_event.content if pl_event else {}, sender_level
- async def _get_mutual_relations(
- self, parent_id: str, rules: Iterable[Tuple[PushRule, bool]]
- ) -> Dict[str, Set[Tuple[str, str]]]:
- """
- Fetch event metadata for events which related to the same event as the given event.
-
- If the given event has no relation information, returns an empty dictionary.
-
- Args:
- parent_id: The event ID which is targeted by relations.
- rules: The push rules which will be processed for this event.
-
- Returns:
- A dictionary of relation type to:
- A set of tuples of:
- The sender
- The event type
- """
-
- # If the experimental feature is not enabled, skip fetching relations.
- if not self._relations_match_enabled:
- return {}
-
- # Pre-filter to figure out which relation types are interesting.
- rel_types = set()
- for rule, enabled in rules:
- if not enabled:
- continue
-
- for condition in rule.conditions:
- if condition["kind"] != "org.matrix.msc3772.relation_match":
- continue
-
- # rel_type is required.
- rel_type = condition.get("rel_type")
- if rel_type:
- rel_types.add(rel_type)
-
- # If no valid rules were found, no mutual relations.
- if not rel_types:
- return {}
-
- # If any valid rules were found, fetch the mutual relations.
- return await self.store.get_mutual_event_relations(parent_id, rel_types)
-
@measure_func("action_for_event_by_user")
async def action_for_event_by_user(
self, event: EventBase, context: EventContext
@@ -276,16 +225,11 @@ class BulkPushRuleEvaluator:
sender_power_level,
) = await self._get_power_levels_and_sender_level(event, context)
+ # Find the event's thread ID.
relation = relation_from_event(event)
- # If the event does not have a relation, then cannot have any mutual
- # relations or thread ID.
- relations = {}
+ # If the event does not have a relation, then it cannot have a thread ID.
thread_id = MAIN_TIMELINE
if relation:
- relations = await self._get_mutual_relations(
- relation.parent_id,
- itertools.chain(*(r.rules() for r in rules_by_user.values())),
- )
# Recursively attempt to find the thread this event relates to.
if relation.rel_type == RelationTypes.THREAD:
thread_id = relation.parent_id
@@ -306,8 +250,6 @@ class BulkPushRuleEvaluator:
room_member_count,
sender_power_level,
notification_levels,
- relations,
- self._relations_match_enabled,
)
users = rules_by_user.keys()
diff --git a/synapse/storage/databases/main/cache.py b/synapse/storage/databases/main/cache.py
index 3b8ed1f7ee..a9f25a5904 100644
--- a/synapse/storage/databases/main/cache.py
+++ b/synapse/storage/databases/main/cache.py
@@ -259,9 +259,6 @@ class CacheInvalidationWorkerStore(SQLBaseStore):
self._attempt_to_invalidate_cache("get_applicable_edit", (relates_to,))
self._attempt_to_invalidate_cache("get_thread_summary", (relates_to,))
self._attempt_to_invalidate_cache("get_thread_participated", (relates_to,))
- self._attempt_to_invalidate_cache(
- "get_mutual_event_relations_for_rel_type", (relates_to,)
- )
async def invalidate_cache_and_stream(
self, cache_name: str, keys: Tuple[Any, ...]
diff --git a/synapse/storage/databases/main/events.py b/synapse/storage/databases/main/events.py
index 3e15827986..060fe71454 100644
--- a/synapse/storage/databases/main/events.py
+++ b/synapse/storage/databases/main/events.py
@@ -2024,11 +2024,6 @@ class PersistEventsStore:
self.store._invalidate_cache_and_stream(
txn, self.store.get_thread_participated, (redacted_relates_to,)
)
- self.store._invalidate_cache_and_stream(
- txn,
- self.store.get_mutual_event_relations_for_rel_type,
- (redacted_relates_to,),
- )
self.db_pool.simple_delete_txn(
txn, table="event_relations", keyvalues={"event_id": redacted_event_id}
diff --git a/synapse/storage/databases/main/push_rule.py b/synapse/storage/databases/main/push_rule.py
index 8295322b0e..51416b2236 100644
--- a/synapse/storage/databases/main/push_rule.py
+++ b/synapse/storage/databases/main/push_rule.py
@@ -29,7 +29,6 @@ from typing import (
)
from synapse.api.errors import StoreError
-from synapse.config.homeserver import ExperimentalConfig
from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker
from synapse.storage._base import SQLBaseStore
from synapse.storage.database import (
@@ -63,9 +62,7 @@ logger = logging.getLogger(__name__)
def _load_rules(
- rawrules: List[JsonDict],
- enabled_map: Dict[str, bool],
- experimental_config: ExperimentalConfig,
+ rawrules: List[JsonDict], enabled_map: Dict[str, bool]
) -> FilteredPushRules:
"""Take the DB rows returned from the DB and convert them into a full
`FilteredPushRules` object.
@@ -83,9 +80,7 @@ def _load_rules(
push_rules = PushRules(ruleslist)
- filtered_rules = FilteredPushRules(
- push_rules, enabled_map, msc3772_enabled=experimental_config.msc3772_enabled
- )
+ filtered_rules = FilteredPushRules(push_rules, enabled_map)
return filtered_rules
@@ -165,7 +160,7 @@ class PushRulesWorkerStore(
enabled_map = await self.get_push_rules_enabled_for_user(user_id)
- return _load_rules(rows, enabled_map, self.hs.config.experimental)
+ return _load_rules(rows, enabled_map)
async def get_push_rules_enabled_for_user(self, user_id: str) -> Dict[str, bool]:
results = await self.db_pool.simple_select_list(
@@ -224,9 +219,7 @@ class PushRulesWorkerStore(
results: Dict[str, FilteredPushRules] = {}
for user_id, rules in raw_rules.items():
- results[user_id] = _load_rules(
- rules, enabled_map_by_user.get(user_id, {}), self.hs.config.experimental
- )
+ results[user_id] = _load_rules(rules, enabled_map_by_user.get(user_id, {}))
return results
diff --git a/synapse/storage/databases/main/relations.py b/synapse/storage/databases/main/relations.py
index 116abef9de..6b7eec4bf2 100644
--- a/synapse/storage/databases/main/relations.py
+++ b/synapse/storage/databases/main/relations.py
@@ -776,59 +776,6 @@ class RelationsWorkerStore(SQLBaseStore):
"get_if_user_has_annotated_event", _get_if_user_has_annotated_event
)
- @cached(iterable=True)
- async def get_mutual_event_relations_for_rel_type(
- self, event_id: str, relation_type: str
- ) -> Set[Tuple[str, str]]:
- raise NotImplementedError()
-
- @cachedList(
- cached_method_name="get_mutual_event_relations_for_rel_type",
- list_name="relation_types",
- )
- async def get_mutual_event_relations(
- self, event_id: str, relation_types: Collection[str]
- ) -> Dict[str, Set[Tuple[str, str]]]:
- """
- Fetch event metadata for events which related to the same event as the given event.
-
- If the given event has no relation information, returns an empty dictionary.
-
- Args:
- event_id: The event ID which is targeted by relations.
- relation_types: The relation types to check for mutual relations.
-
- Returns:
- A dictionary of relation type to:
- A set of tuples of:
- The sender
- The event type
- """
- rel_type_sql, rel_type_args = make_in_list_sql_clause(
- self.database_engine, "relation_type", relation_types
- )
-
- sql = f"""
- SELECT DISTINCT relation_type, sender, type FROM event_relations
- INNER JOIN events USING (event_id)
- WHERE relates_to_id = ? AND {rel_type_sql}
- """
-
- def _get_event_relations(
- txn: LoggingTransaction,
- ) -> Dict[str, Set[Tuple[str, str]]]:
- txn.execute(sql, [event_id] + rel_type_args)
- result: Dict[str, Set[Tuple[str, str]]] = {
- rel_type: set() for rel_type in relation_types
- }
- for rel_type, sender, type in txn.fetchall():
- result[rel_type].add((sender, type))
- return result
-
- return await self.db_pool.runInteraction(
- "get_event_relations", _get_event_relations
- )
-
@cached()
async def get_thread_id(self, event_id: str) -> Optional[str]:
"""
diff --git a/tests/push/test_push_rule_evaluator.py b/tests/push/test_push_rule_evaluator.py
index 8804f0e0d3..decf619466 100644
--- a/tests/push/test_push_rule_evaluator.py
+++ b/tests/push/test_push_rule_evaluator.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from typing import Dict, Optional, Set, Tuple, Union
+from typing import Dict, Optional, Union
import frozendict
@@ -38,12 +38,7 @@ from tests.test_utils.event_injection import create_event, inject_member_event
class PushRuleEvaluatorTestCase(unittest.TestCase):
- def _get_evaluator(
- self,
- content: JsonDict,
- relations: Optional[Dict[str, Set[Tuple[str, str]]]] = None,
- relations_match_enabled: bool = False,
- ) -> PushRuleEvaluator:
+ def _get_evaluator(self, content: JsonDict) -> PushRuleEvaluator:
event = FrozenEvent(
{
"event_id": "$event_id",
@@ -63,8 +58,6 @@ class PushRuleEvaluatorTestCase(unittest.TestCase):
room_member_count,
sender_power_level,
power_levels.get("notifications", {}),
- relations or {},
- relations_match_enabled,
)
def test_display_name(self) -> None:
@@ -299,71 +292,6 @@ class PushRuleEvaluatorTestCase(unittest.TestCase):
{"sound": "default", "highlight": True},
)
- def test_relation_match(self) -> None:
- """Test the relation_match push rule kind."""
-
- # Check if the experimental feature is disabled.
- evaluator = self._get_evaluator(
- {}, {"m.annotation": {("@user:test", "m.reaction")}}
- )
-
- # A push rule evaluator with the experimental rule enabled.
- evaluator = self._get_evaluator(
- {}, {"m.annotation": {("@user:test", "m.reaction")}}, True
- )
-
- # Check just relation type.
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "rel_type": "m.annotation",
- }
- self.assertTrue(evaluator.matches(condition, "@user:test", "foo"))
-
- # Check relation type and sender.
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "rel_type": "m.annotation",
- "sender": "@user:test",
- }
- self.assertTrue(evaluator.matches(condition, "@user:test", "foo"))
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "rel_type": "m.annotation",
- "sender": "@other:test",
- }
- self.assertFalse(evaluator.matches(condition, "@user:test", "foo"))
-
- # Check relation type and event type.
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "rel_type": "m.annotation",
- "type": "m.reaction",
- }
- self.assertTrue(evaluator.matches(condition, "@user:test", "foo"))
-
- # Check just sender, this fails since rel_type is required.
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "sender": "@user:test",
- }
- self.assertFalse(evaluator.matches(condition, "@user:test", "foo"))
-
- # Check sender glob.
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "rel_type": "m.annotation",
- "sender": "@*:test",
- }
- self.assertTrue(evaluator.matches(condition, "@user:test", "foo"))
-
- # Check event type glob.
- condition = {
- "kind": "org.matrix.msc3772.relation_match",
- "rel_type": "m.annotation",
- "event_type": "*.reaction",
- }
- self.assertTrue(evaluator.matches(condition, "@user:test", "foo"))
-
class TestBulkPushRuleEvaluator(unittest.HomeserverTestCase):
"""Tests for the bulk push rule evaluator"""
|