Initial support for MSC3931: Room version push rule feature flags (#14520)

* Add support for MSC3931: Room Version Supports push rule condition

* Create experimental flag for future work, and use it to gate MSC3931

* Changelog entry
This commit is contained in:
Travis Ralston 2022-11-28 16:29:53 -07:00 committed by GitHub
parent 8f10c8b054
commit 3da6450327
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 76 additions and 1 deletions

View file

@ -0,0 +1 @@
Add unstable support for an Extensible Events room version (`org.matrix.msc1767.10`) via [MSC1767](https://github.com/matrix-org/matrix-spec-proposals/pull/1767), [MSC3931](https://github.com/matrix-org/matrix-spec-proposals/pull/3931), [MSC3932](https://github.com/matrix-org/matrix-spec-proposals/pull/3932), and [MSC3933](https://github.com/matrix-org/matrix-spec-proposals/pull/3933).

View file

@ -29,6 +29,10 @@ use super::{
lazy_static! { lazy_static! {
/// Used to parse the `is` clause in the room member count condition. /// Used to parse the `is` clause in the room member count condition.
static ref INEQUALITY_EXPR: Regex = Regex::new(r"^([=<>]*)([0-9]+)$").expect("valid regex"); static ref INEQUALITY_EXPR: Regex = Regex::new(r"^([=<>]*)([0-9]+)$").expect("valid regex");
/// Used to determine which MSC3931 room version feature flags are actually known to
/// the push evaluator.
static ref KNOWN_RVER_FLAGS: Vec<String> = vec![];
} }
/// Allows running a set of push rules against a particular event. /// Allows running a set of push rules against a particular event.
@ -57,6 +61,13 @@ pub struct PushRuleEvaluator {
/// If msc3664, push rules for related events, is enabled. /// If msc3664, push rules for related events, is enabled.
related_event_match_enabled: bool, related_event_match_enabled: bool,
/// If MSC3931 is applicable, the feature flags for the room version.
room_version_feature_flags: Vec<String>,
/// If MSC3931 (room version feature flags) is enabled. Usually controlled by the same
/// flag as MSC1767 (extensible events core).
msc3931_enabled: bool,
} }
#[pymethods] #[pymethods]
@ -70,6 +81,8 @@ impl PushRuleEvaluator {
notification_power_levels: BTreeMap<String, i64>, notification_power_levels: BTreeMap<String, i64>,
related_events_flattened: BTreeMap<String, BTreeMap<String, String>>, related_events_flattened: BTreeMap<String, BTreeMap<String, String>>,
related_event_match_enabled: bool, related_event_match_enabled: bool,
room_version_feature_flags: Vec<String>,
msc3931_enabled: bool,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let body = flattened_keys let body = flattened_keys
.get("content.body") .get("content.body")
@ -84,6 +97,8 @@ impl PushRuleEvaluator {
sender_power_level, sender_power_level,
related_events_flattened, related_events_flattened,
related_event_match_enabled, related_event_match_enabled,
room_version_feature_flags,
msc3931_enabled,
}) })
} }
@ -204,6 +219,15 @@ impl PushRuleEvaluator {
false false
} }
} }
KnownCondition::RoomVersionSupports { feature } => {
if !self.msc3931_enabled {
false
} else {
let flag = feature.to_string();
KNOWN_RVER_FLAGS.contains(&flag)
&& self.room_version_feature_flags.contains(&flag)
}
}
}; };
Ok(result) Ok(result)
@ -362,6 +386,8 @@ fn push_rule_evaluator() {
BTreeMap::new(), BTreeMap::new(),
BTreeMap::new(), BTreeMap::new(),
true, true,
vec![],
true,
) )
.unwrap(); .unwrap();

View file

@ -277,6 +277,10 @@ pub enum KnownCondition {
SenderNotificationPermission { SenderNotificationPermission {
key: Cow<'static, str>, key: Cow<'static, str>,
}, },
#[serde(rename = "org.matrix.msc3931.room_version_supports")]
RoomVersionSupports {
feature: Cow<'static, str>,
},
} }
impl IntoPy<PyObject> for Condition { impl IntoPy<PyObject> for Condition {
@ -491,6 +495,18 @@ fn test_deserialize_unstable_msc3664_condition() {
)); ));
} }
#[test]
fn test_deserialize_unstable_msc3931_condition() {
let json =
r#"{"kind":"org.matrix.msc3931.room_version_supports","feature":"org.example.feature"}"#;
let condition: Condition = serde_json::from_str(json).unwrap();
assert!(matches!(
condition,
Condition::Known(KnownCondition::RoomVersionSupports { feature: _ })
));
}
#[test] #[test]
fn test_deserialize_custom_condition() { fn test_deserialize_custom_condition() {
let json = r#"{"kind":"custom_tag"}"#; let json = r#"{"kind":"custom_tag"}"#;

View file

@ -41,6 +41,8 @@ class PushRuleEvaluator:
notification_power_levels: Mapping[str, int], notification_power_levels: Mapping[str, int],
related_events_flattened: Mapping[str, Mapping[str, str]], related_events_flattened: Mapping[str, Mapping[str, str]],
related_event_match_enabled: bool, related_event_match_enabled: bool,
room_version_feature_flags: list[str],
msc3931_enabled: bool,
): ... ): ...
def run( def run(
self, self,

View file

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from typing import Callable, Dict, Optional from typing import Callable, Dict, List, Optional
import attr import attr
@ -91,6 +91,12 @@ class RoomVersion:
msc3787_knock_restricted_join_rule: bool msc3787_knock_restricted_join_rule: bool
# MSC3667: Enforce integer power levels # MSC3667: Enforce integer power levels
msc3667_int_only_power_levels: bool msc3667_int_only_power_levels: bool
# MSC3931: Adds a push rule condition for "room version feature flags", making
# some push rules room version dependent. Note that adding a flag to this list
# is not enough to mark it "supported": the push rule evaluator also needs to
# support the flag. Unknown flags are ignored by the evaluator, making conditions
# fail if used.
msc3931_push_features: List[str]
class RoomVersions: class RoomVersions:
@ -111,6 +117,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V2 = RoomVersion( V2 = RoomVersion(
"2", "2",
@ -129,6 +136,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V3 = RoomVersion( V3 = RoomVersion(
"3", "3",
@ -147,6 +155,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V4 = RoomVersion( V4 = RoomVersion(
"4", "4",
@ -165,6 +174,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V5 = RoomVersion( V5 = RoomVersion(
"5", "5",
@ -183,6 +193,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V6 = RoomVersion( V6 = RoomVersion(
"6", "6",
@ -201,6 +212,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
MSC2176 = RoomVersion( MSC2176 = RoomVersion(
"org.matrix.msc2176", "org.matrix.msc2176",
@ -219,6 +231,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V7 = RoomVersion( V7 = RoomVersion(
"7", "7",
@ -237,6 +250,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V8 = RoomVersion( V8 = RoomVersion(
"8", "8",
@ -255,6 +269,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V9 = RoomVersion( V9 = RoomVersion(
"9", "9",
@ -273,6 +288,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
MSC3787 = RoomVersion( MSC3787 = RoomVersion(
"org.matrix.msc3787", "org.matrix.msc3787",
@ -291,6 +307,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=True, msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )
V10 = RoomVersion( V10 = RoomVersion(
"10", "10",
@ -309,6 +326,7 @@ class RoomVersions:
msc2716_redactions=False, msc2716_redactions=False,
msc3787_knock_restricted_join_rule=True, msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=True, msc3667_int_only_power_levels=True,
msc3931_push_features=[],
) )
MSC2716v4 = RoomVersion( MSC2716v4 = RoomVersion(
"org.matrix.msc2716v4", "org.matrix.msc2716v4",
@ -327,6 +345,7 @@ class RoomVersions:
msc2716_redactions=True, msc2716_redactions=True,
msc3787_knock_restricted_join_rule=False, msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False, msc3667_int_only_power_levels=False,
msc3931_push_features=[],
) )

View file

@ -128,3 +128,6 @@ class ExperimentalConfig(Config):
# MSC3912: Relation-based redactions. # MSC3912: Relation-based redactions.
self.msc3912_enabled: bool = experimental.get("msc3912_enabled", False) self.msc3912_enabled: bool = experimental.get("msc3912_enabled", False)
# MSC1767 and friends: Extensible Events
self.msc1767_enabled: bool = experimental.get("msc1767_enabled", False)

View file

@ -338,6 +338,10 @@ class BulkPushRuleEvaluator:
for user_id, level in notification_levels.items(): for user_id, level in notification_levels.items():
notification_levels[user_id] = int(level) notification_levels[user_id] = int(level)
room_version_features = event.room_version.msc3931_push_features
if not room_version_features:
room_version_features = []
evaluator = PushRuleEvaluator( evaluator = PushRuleEvaluator(
_flatten_dict(event), _flatten_dict(event),
room_member_count, room_member_count,
@ -345,6 +349,8 @@ class BulkPushRuleEvaluator:
notification_levels, notification_levels,
related_events, related_events,
self._related_event_match_enabled, self._related_event_match_enabled,
room_version_features,
self.hs.config.experimental.msc1767_enabled, # MSC3931 flag
) )
users = rules_by_user.keys() users = rules_by_user.keys()

View file

@ -62,6 +62,8 @@ class PushRuleEvaluatorTestCase(unittest.TestCase):
power_levels.get("notifications", {}), power_levels.get("notifications", {}),
{} if related_events is None else related_events, {} if related_events is None else related_events,
True, True,
event.room_version.msc3931_push_features,
True,
) )
def test_display_name(self) -> None: def test_display_name(self) -> None: