diff --git a/synapse/config/server.py b/synapse/config/server.py
index 848587d232..9f15ed109e 100644
--- a/synapse/config/server.py
+++ b/synapse/config/server.py
@@ -530,6 +530,21 @@ class ServerConfig(Config):
"request_token_inhibit_3pid_errors", False,
)
+ # List of users trialing the new experimental default push rules. This setting is
+ # not included in the sample configuration file on purpose as it's a temporary
+ # hack, so that some users can trial the new defaults without impacting every
+ # user on the homeserver.
+ users_new_default_push_rules = (
+ config.get("users_new_default_push_rules") or []
+ ) # type: list
+ if not isinstance(users_new_default_push_rules, list):
+ raise ConfigError("'users_new_default_push_rules' must be a list")
+
+ # Turn the list into a set to improve lookup speed.
+ self.users_new_default_push_rules = set(
+ users_new_default_push_rules
+ ) # type: set
+
def has_tls_listener(self) -> bool:
return any(listener.tls for listener in self.listeners)
diff --git a/synapse/push/baserules.py b/synapse/push/baserules.py
index 286374d0b5..8047873ff1 100644
--- a/synapse/push/baserules.py
+++ b/synapse/push/baserules.py
@@ -19,11 +19,13 @@ import copy
from synapse.push.rulekinds import PRIORITY_CLASS_INVERSE_MAP, PRIORITY_CLASS_MAP
-def list_with_base_rules(rawrules):
+def list_with_base_rules(rawrules, use_new_defaults=False):
"""Combine the list of rules set by the user with the default push rules
Args:
rawrules(list): The rules the user has modified or set.
+ use_new_defaults(bool): Whether to use the new experimental default rules when
+ appending or prepending default rules.
Returns:
A new list with the rules set by the user combined with the defaults.
@@ -43,7 +45,9 @@ def list_with_base_rules(rawrules):
ruleslist.extend(
make_base_prepend_rules(
- PRIORITY_CLASS_INVERSE_MAP[current_prio_class], modified_base_rules
+ PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
+ modified_base_rules,
+ use_new_defaults,
)
)
@@ -54,6 +58,7 @@ def list_with_base_rules(rawrules):
make_base_append_rules(
PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
modified_base_rules,
+ use_new_defaults,
)
)
current_prio_class -= 1
@@ -62,6 +67,7 @@ def list_with_base_rules(rawrules):
make_base_prepend_rules(
PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
modified_base_rules,
+ use_new_defaults,
)
)
@@ -70,27 +76,39 @@ def list_with_base_rules(rawrules):
while current_prio_class > 0:
ruleslist.extend(
make_base_append_rules(
- PRIORITY_CLASS_INVERSE_MAP[current_prio_class], modified_base_rules
+ PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
+ modified_base_rules,
+ use_new_defaults,
)
)
current_prio_class -= 1
if current_prio_class > 0:
ruleslist.extend(
make_base_prepend_rules(
- PRIORITY_CLASS_INVERSE_MAP[current_prio_class], modified_base_rules
+ PRIORITY_CLASS_INVERSE_MAP[current_prio_class],
+ modified_base_rules,
+ use_new_defaults,
)
)
return ruleslist
-def make_base_append_rules(kind, modified_base_rules):
+def make_base_append_rules(kind, modified_base_rules, use_new_defaults=False):
rules = []
if kind == "override":
- rules = BASE_APPEND_OVERRIDE_RULES
+ rules = (
+ NEW_APPEND_OVERRIDE_RULES
+ if use_new_defaults
+ else BASE_APPEND_OVERRIDE_RULES
+ )
elif kind == "underride":
- rules = BASE_APPEND_UNDERRIDE_RULES
+ rules = (
+ NEW_APPEND_UNDERRIDE_RULES
+ if use_new_defaults
+ else BASE_APPEND_UNDERRIDE_RULES
+ )
elif kind == "content":
rules = BASE_APPEND_CONTENT_RULES
@@ -105,7 +123,7 @@ def make_base_append_rules(kind, modified_base_rules):
return rules
-def make_base_prepend_rules(kind, modified_base_rules):
+def make_base_prepend_rules(kind, modified_base_rules, use_new_defaults=False):
rules = []
if kind == "override":
@@ -270,6 +288,135 @@ BASE_APPEND_OVERRIDE_RULES = [
]
+NEW_APPEND_OVERRIDE_RULES = [
+ {
+ "rule_id": "global/override/.m.rule.encrypted",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "type",
+ "pattern": "m.room.encrypted",
+ "_id": "_encrypted",
+ }
+ ],
+ "actions": ["notify"],
+ },
+ {
+ "rule_id": "global/override/.m.rule.suppress_notices",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "type",
+ "pattern": "m.room.message",
+ "_id": "_suppress_notices_type",
+ },
+ {
+ "kind": "event_match",
+ "key": "content.msgtype",
+ "pattern": "m.notice",
+ "_id": "_suppress_notices",
+ },
+ ],
+ "actions": [],
+ },
+ {
+ "rule_id": "global/underride/.m.rule.suppress_edits",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "m.relates_to.m.rel_type",
+ "pattern": "m.replace",
+ "_id": "_suppress_edits",
+ }
+ ],
+ "actions": [],
+ },
+ {
+ "rule_id": "global/override/.m.rule.invite_for_me",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "type",
+ "pattern": "m.room.member",
+ "_id": "_member",
+ },
+ {
+ "kind": "event_match",
+ "key": "content.membership",
+ "pattern": "invite",
+ "_id": "_invite_member",
+ },
+ {"kind": "event_match", "key": "state_key", "pattern_type": "user_id"},
+ ],
+ "actions": ["notify", {"set_tweak": "sound", "value": "default"}],
+ },
+ {
+ "rule_id": "global/override/.m.rule.contains_display_name",
+ "conditions": [{"kind": "contains_display_name"}],
+ "actions": [
+ "notify",
+ {"set_tweak": "sound", "value": "default"},
+ {"set_tweak": "highlight"},
+ ],
+ },
+ {
+ "rule_id": "global/override/.m.rule.tombstone",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "type",
+ "pattern": "m.room.tombstone",
+ "_id": "_tombstone",
+ },
+ {
+ "kind": "event_match",
+ "key": "state_key",
+ "pattern": "",
+ "_id": "_tombstone_statekey",
+ },
+ ],
+ "actions": [
+ "notify",
+ {"set_tweak": "sound", "value": "default"},
+ {"set_tweak": "highlight"},
+ ],
+ },
+ {
+ "rule_id": "global/override/.m.rule.roomnotif",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "content.body",
+ "pattern": "@room",
+ "_id": "_roomnotif_content",
+ },
+ {
+ "kind": "sender_notification_permission",
+ "key": "room",
+ "_id": "_roomnotif_pl",
+ },
+ ],
+ "actions": [
+ "notify",
+ {"set_tweak": "highlight"},
+ {"set_tweak": "sound", "value": "default"},
+ ],
+ },
+ {
+ "rule_id": "global/override/.m.rule.call",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "type",
+ "pattern": "m.call.invite",
+ "_id": "_call",
+ }
+ ],
+ "actions": ["notify", {"set_tweak": "sound", "value": "ring"}],
+ },
+]
+
+
BASE_APPEND_UNDERRIDE_RULES = [
{
"rule_id": "global/underride/.m.rule.call",
@@ -354,6 +501,36 @@ BASE_APPEND_UNDERRIDE_RULES = [
]
+NEW_APPEND_UNDERRIDE_RULES = [
+ {
+ "rule_id": "global/underride/.m.rule.room_one_to_one",
+ "conditions": [
+ {"kind": "room_member_count", "is": "2", "_id": "member_count"},
+ {
+ "kind": "event_match",
+ "key": "content.body",
+ "pattern": "*",
+ "_id": "body",
+ },
+ ],
+ "actions": ["notify", {"set_tweak": "sound", "value": "default"}],
+ },
+ {
+ "rule_id": "global/underride/.m.rule.message",
+ "conditions": [
+ {
+ "kind": "event_match",
+ "key": "content.body",
+ "pattern": "*",
+ "_id": "body",
+ },
+ ],
+ "actions": ["notify"],
+ "enabled": False,
+ },
+]
+
+
BASE_RULE_IDS = set()
for r in BASE_APPEND_CONTENT_RULES:
@@ -375,3 +552,26 @@ for r in BASE_APPEND_UNDERRIDE_RULES:
r["priority_class"] = PRIORITY_CLASS_MAP["underride"]
r["default"] = True
BASE_RULE_IDS.add(r["rule_id"])
+
+
+NEW_RULE_IDS = set()
+
+for r in BASE_APPEND_CONTENT_RULES:
+ r["priority_class"] = PRIORITY_CLASS_MAP["content"]
+ r["default"] = True
+ NEW_RULE_IDS.add(r["rule_id"])
+
+for r in BASE_PREPEND_OVERRIDE_RULES:
+ r["priority_class"] = PRIORITY_CLASS_MAP["override"]
+ r["default"] = True
+ NEW_RULE_IDS.add(r["rule_id"])
+
+for r in NEW_APPEND_OVERRIDE_RULES:
+ r["priority_class"] = PRIORITY_CLASS_MAP["override"]
+ r["default"] = True
+ NEW_RULE_IDS.add(r["rule_id"])
+
+for r in NEW_APPEND_UNDERRIDE_RULES:
+ r["priority_class"] = PRIORITY_CLASS_MAP["underride"]
+ r["default"] = True
+ NEW_RULE_IDS.add(r["rule_id"])
diff --git a/synapse/rest/client/v1/push_rule.py b/synapse/rest/client/v1/push_rule.py
index 9fd4908136..00831879f3 100644
--- a/synapse/rest/client/v1/push_rule.py
+++ b/synapse/rest/client/v1/push_rule.py
@@ -25,7 +25,7 @@ from synapse.http.servlet import (
parse_json_value_from_request,
parse_string,
)
-from synapse.push.baserules import BASE_RULE_IDS
+from synapse.push.baserules import BASE_RULE_IDS, NEW_RULE_IDS
from synapse.push.clientformat import format_push_rules_for_user
from synapse.push.rulekinds import PRIORITY_CLASS_MAP
from synapse.rest.client.v2_alpha._base import client_patterns
@@ -45,6 +45,8 @@ class PushRuleRestServlet(RestServlet):
self.notifier = hs.get_notifier()
self._is_worker = hs.config.worker_app is not None
+ self._users_new_default_push_rules = hs.config.users_new_default_push_rules
+
async def on_PUT(self, request, path):
if self._is_worker:
raise Exception("Cannot handle PUT /push_rules on worker")
@@ -179,7 +181,12 @@ class PushRuleRestServlet(RestServlet):
rule_id = spec["rule_id"]
is_default_rule = rule_id.startswith(".")
if is_default_rule:
- if namespaced_rule_id not in BASE_RULE_IDS:
+ if user_id in self._users_new_default_push_rules:
+ rule_ids = NEW_RULE_IDS
+ else:
+ rule_ids = BASE_RULE_IDS
+
+ if namespaced_rule_id not in rule_ids:
raise SynapseError(404, "Unknown rule %r" % (namespaced_rule_id,))
return self.store.set_push_rule_actions(
user_id, namespaced_rule_id, actions, is_default_rule
diff --git a/synapse/storage/databases/main/push_rule.py b/synapse/storage/databases/main/push_rule.py
index 264521635f..19a0211a03 100644
--- a/synapse/storage/databases/main/push_rule.py
+++ b/synapse/storage/databases/main/push_rule.py
@@ -38,7 +38,7 @@ from synapse.util.caches.stream_change_cache import StreamChangeCache
logger = logging.getLogger(__name__)
-def _load_rules(rawrules, enabled_map):
+def _load_rules(rawrules, enabled_map, use_new_defaults=False):
ruleslist = []
for rawrule in rawrules:
rule = dict(rawrule)
@@ -48,7 +48,7 @@ def _load_rules(rawrules, enabled_map):
ruleslist.append(rule)
# We're going to be mutating this a lot, so do a deep copy
- rules = list(list_with_base_rules(ruleslist))
+ rules = list(list_with_base_rules(ruleslist, use_new_defaults))
for i, rule in enumerate(rules):
rule_id = rule["rule_id"]
@@ -104,6 +104,8 @@ class PushRulesWorkerStore(
prefilled_cache=push_rules_prefill,
)
+ self._users_new_default_push_rules = hs.config.users_new_default_push_rules
+
@abc.abstractmethod
def get_max_push_rules_stream_id(self):
"""Get the position of the push rules stream.
@@ -133,7 +135,9 @@ class PushRulesWorkerStore(
enabled_map = yield self.get_push_rules_enabled_for_user(user_id)
- rules = _load_rules(rows, enabled_map)
+ use_new_defaults = user_id in self._users_new_default_push_rules
+
+ rules = _load_rules(rows, enabled_map, use_new_defaults)
return rules
@@ -193,7 +197,11 @@ class PushRulesWorkerStore(
enabled_map_by_user = yield self.bulk_get_push_rules_enabled(user_ids)
for user_id, rules in results.items():
- results[user_id] = _load_rules(rules, enabled_map_by_user.get(user_id, {}))
+ use_new_defaults = user_id in self._users_new_default_push_rules
+
+ results[user_id] = _load_rules(
+ rules, enabled_map_by_user.get(user_id, {}), use_new_defaults,
+ )
return results
|