Merge branch 'rei/msc4306_postcontent' into rei/threadsubs_all

This commit is contained in:
Olivier 'reivilibre
2025-09-03 14:57:30 +01:00
7 changed files with 49 additions and 6 deletions

View File

@@ -0,0 +1 @@
Update push rules for experimental [MSC4306: Thread Subscriptions](https://github.com/matrix-org/matrix-doc/issues/4306) to follow newer draft.

View File

@@ -289,10 +289,10 @@ pub const BASE_APPEND_CONTENT_RULES: &[PushRule] = &[PushRule {
default_enabled: true, default_enabled: true,
}]; }];
pub const BASE_APPEND_UNDERRIDE_RULES: &[PushRule] = &[ pub const BASE_APPEND_POSTCONTENT_RULES: &[PushRule] = &[
PushRule { PushRule {
rule_id: Cow::Borrowed("global/content/.io.element.msc4306.rule.unsubscribed_thread"), rule_id: Cow::Borrowed("global/postcontent/.io.element.msc4306.rule.unsubscribed_thread"),
priority_class: 1, priority_class: 6,
conditions: Cow::Borrowed(&[Condition::Known( conditions: Cow::Borrowed(&[Condition::Known(
KnownCondition::Msc4306ThreadSubscription { subscribed: false }, KnownCondition::Msc4306ThreadSubscription { subscribed: false },
)]), )]),
@@ -301,8 +301,8 @@ pub const BASE_APPEND_UNDERRIDE_RULES: &[PushRule] = &[
default_enabled: true, default_enabled: true,
}, },
PushRule { PushRule {
rule_id: Cow::Borrowed("global/content/.io.element.msc4306.rule.subscribed_thread"), rule_id: Cow::Borrowed("global/postcontent/.io.element.msc4306.rule.subscribed_thread"),
priority_class: 1, priority_class: 6,
conditions: Cow::Borrowed(&[Condition::Known( conditions: Cow::Borrowed(&[Condition::Known(
KnownCondition::Msc4306ThreadSubscription { subscribed: true }, KnownCondition::Msc4306ThreadSubscription { subscribed: true },
)]), )]),
@@ -310,6 +310,9 @@ pub const BASE_APPEND_UNDERRIDE_RULES: &[PushRule] = &[
default: true, default: true,
default_enabled: true, default_enabled: true,
}, },
];
pub const BASE_APPEND_UNDERRIDE_RULES: &[PushRule] = &[
PushRule { PushRule {
rule_id: Cow::Borrowed("global/underride/.m.rule.call"), rule_id: Cow::Borrowed("global/underride/.m.rule.call"),
priority_class: 1, priority_class: 1,
@@ -726,6 +729,7 @@ lazy_static! {
.iter() .iter()
.chain(BASE_APPEND_OVERRIDE_RULES.iter()) .chain(BASE_APPEND_OVERRIDE_RULES.iter())
.chain(BASE_APPEND_CONTENT_RULES.iter()) .chain(BASE_APPEND_CONTENT_RULES.iter())
.chain(BASE_APPEND_POSTCONTENT_RULES.iter())
.chain(BASE_APPEND_UNDERRIDE_RULES.iter()) .chain(BASE_APPEND_UNDERRIDE_RULES.iter())
.map(|rule| { (&*rule.rule_id, rule) }) .map(|rule| { (&*rule.rule_id, rule) })
.collect(); .collect();

View File

@@ -527,6 +527,7 @@ impl PushRules {
.chain(base_rules::BASE_APPEND_OVERRIDE_RULES.iter()) .chain(base_rules::BASE_APPEND_OVERRIDE_RULES.iter())
.chain(self.content.iter()) .chain(self.content.iter())
.chain(base_rules::BASE_APPEND_CONTENT_RULES.iter()) .chain(base_rules::BASE_APPEND_CONTENT_RULES.iter())
.chain(base_rules::BASE_APPEND_POSTCONTENT_RULES.iter())
.chain(self.room.iter()) .chain(self.room.iter())
.chain(self.sender.iter()) .chain(self.sender.iter())
.chain(self.underride.iter()) .chain(self.underride.iter())

View File

@@ -91,7 +91,7 @@ def _rule_to_template(rule: PushRule) -> Optional[Dict[str, Any]]:
unscoped_rule_id = _rule_id_from_namespaced(rule.rule_id) unscoped_rule_id = _rule_id_from_namespaced(rule.rule_id)
template_name = _priority_class_to_template_name(rule.priority_class) template_name = _priority_class_to_template_name(rule.priority_class)
if template_name in ["override", "underride"]: if template_name in ["override", "underride", "postcontent"]:
templaterule = {"conditions": rule.conditions, "actions": rule.actions} templaterule = {"conditions": rule.conditions, "actions": rule.actions}
elif template_name in ["sender", "room"]: elif template_name in ["sender", "room"]:
templaterule = {"actions": rule.actions} templaterule = {"actions": rule.actions}

View File

@@ -19,10 +19,14 @@
# #
# #
# Integer literals for push rule `kind`s
# This is used to store them in the database.
PRIORITY_CLASS_MAP = { PRIORITY_CLASS_MAP = {
"underride": 1, "underride": 1,
"sender": 2, "sender": 2,
"room": 3, "room": 3,
# MSC4306
"postcontent": 6,
"content": 4, "content": 4,
"override": 5, "override": 5,
} }

View File

@@ -19,9 +19,11 @@
# #
# #
from http import HTTPStatus
from typing import TYPE_CHECKING, List, Tuple, Union from typing import TYPE_CHECKING, List, Tuple, Union
from synapse.api.errors import ( from synapse.api.errors import (
Codes,
NotFoundError, NotFoundError,
StoreError, StoreError,
SynapseError, SynapseError,
@@ -239,6 +241,15 @@ def _rule_spec_from_path(path: List[str]) -> RuleSpec:
def _rule_tuple_from_request_object( def _rule_tuple_from_request_object(
rule_template: str, rule_id: str, req_obj: JsonDict rule_template: str, rule_id: str, req_obj: JsonDict
) -> Tuple[List[JsonDict], List[Union[str, JsonDict]]]: ) -> Tuple[List[JsonDict], List[Union[str, JsonDict]]]:
if rule_template == "postcontent":
# postcontent is from MSC4306, which says that clients
# cannot create their own postcontent rules right now.
raise SynapseError(
HTTPStatus.BAD_REQUEST,
"user-defined rules using `postcontent` are not accepted",
errcode=Codes.INVALID_PARAM,
)
if rule_template in ["override", "underride"]: if rule_template in ["override", "underride"]:
if "conditions" not in req_obj: if "conditions" not in req_obj:
raise InvalidRuleException("Missing 'conditions'") raise InvalidRuleException("Missing 'conditions'")

View File

@@ -18,6 +18,8 @@
# [This file includes modifications made by New Vector Limited] # [This file includes modifications made by New Vector Limited]
# #
# #
from http import HTTPStatus
import synapse import synapse
from synapse.api.errors import Codes from synapse.api.errors import Codes
from synapse.rest.client import login, push_rule, room from synapse.rest.client import login, push_rule, room
@@ -486,3 +488,23 @@ class PushRuleAttributesTestCase(HomeserverTestCase):
}, },
channel.json_body, channel.json_body,
) )
def test_no_user_defined_postcontent_rules(self) -> None:
"""
Tests that clients are not permitted to create MSC4306 `postcontent` rules.
"""
self.register_user("bob", "pass")
token = self.login("bob", "pass")
channel = self.make_request(
"PUT",
"/pushrules/global/postcontent/some.user.rule",
{},
access_token=token,
)
self.assertEqual(channel.code, HTTPStatus.BAD_REQUEST)
self.assertEqual(
Codes.INVALID_PARAM,
channel.json_body["errcode"],
)