Skip to content
Snippets Groups Projects
Commit 2df41aa1 authored by David Baker's avatar David Baker
Browse files

Server default rules now of all kinds rather than all being at lowest prio.

parent f90782a6
No related branches found
No related tags found
No related merge requests found
...@@ -77,15 +77,15 @@ class Pusher(object): ...@@ -77,15 +77,15 @@ class Pusher(object):
if ev['state_key'] != self.user_name: if ev['state_key'] != self.user_name:
defer.returnValue(['dont_notify']) defer.returnValue(['dont_notify'])
rules = yield self.store.get_push_rules_for_user_name(self.user_name) rawrules = yield self.store.get_push_rules_for_user_name(self.user_name)
for r in rules: for r in rawrules:
r['conditions'] = json.loads(r['conditions']) r['conditions'] = json.loads(r['conditions'])
r['actions'] = json.loads(r['actions']) r['actions'] = json.loads(r['actions'])
user_name_localpart = UserID.from_string(self.user_name).localpart user = UserID.from_string(self.user_name)
rules.extend(baserules.make_base_rules(user_name_localpart)) rules = baserules.list_with_base_rules(rawrules, user)
# get *our* member event for display name matching # get *our* member event for display name matching
member_events_for_room = yield self.store.get_current_state( member_events_for_room = yield self.store.get_current_state(
......
def make_base_rules(user_name): from synapse.push.rulekinds import PRIORITY_CLASS_MAP, PRIORITY_CLASS_INVERSE_MAP
rules = [
def list_with_base_rules(rawrules, user_name):
ruleslist = []
# shove the server default rules for each kind onto the end of each
current_prio_class = 1
for r in rawrules:
if r['priority_class'] > current_prio_class:
while current_prio_class < r['priority_class']:
ruleslist.extend(make_base_rules(
user_name,
PRIORITY_CLASS_INVERSE_MAP[current_prio_class])
)
current_prio_class += 1
ruleslist.append(r)
while current_prio_class <= PRIORITY_CLASS_INVERSE_MAP.keys()[-1]:
ruleslist.extend(make_base_rules(
user_name,
PRIORITY_CLASS_INVERSE_MAP[current_prio_class])
)
current_prio_class += 1
return ruleslist
def make_base_rules(user, kind):
rules = []
if kind == 'override':
rules = make_base_override_rules()
elif kind == 'content':
rules = make_base_content_rules(user)
for r in rules:
r['priority_class'] = PRIORITY_CLASS_MAP[kind]
return rules
def make_base_content_rules(user):
return [
{ {
'conditions': [ 'conditions': [
{ {
'kind': 'event_match', 'kind': 'event_match',
'key': 'content.body', 'key': 'content.body',
'pattern': '*%s*' % (user_name,), # Matrix ID match 'pattern': user.localpart, # Matrix ID match
} }
], ],
'actions': [ 'actions': [
'notify', 'notify',
{ {
'set_sound': 'default' 'set_tweak': 'sound',
'value': 'default',
} }
] ]
}, },
]
def make_base_override_rules():
return [
{ {
'conditions': [ 'conditions': [
{ {
...@@ -24,7 +72,8 @@ def make_base_rules(user_name): ...@@ -24,7 +72,8 @@ def make_base_rules(user_name):
'actions': [ 'actions': [
'notify', 'notify',
{ {
'set_sound': 'default' 'set_tweak': 'sound',
'value': 'default'
} }
] ]
}, },
...@@ -44,6 +93,3 @@ def make_base_rules(user_name): ...@@ -44,6 +93,3 @@ def make_base_rules(user_name):
] ]
} }
] ]
for r in rules:
r['priority_class'] = 0
return rules
\ No newline at end of file
PRIORITY_CLASS_MAP = {
'underride': 1,
'sender': 2,
'room': 3,
'content': 4,
'override': 5,
}
PRIORITY_CLASS_INVERSE_MAP = {v: k for k, v in PRIORITY_CLASS_MAP.items()}
...@@ -20,21 +20,13 @@ from synapse.api.errors import SynapseError, Codes, UnrecognizedRequestError, No ...@@ -20,21 +20,13 @@ from synapse.api.errors import SynapseError, Codes, UnrecognizedRequestError, No
from .base import ClientV1RestServlet, client_path_pattern from .base import ClientV1RestServlet, client_path_pattern
from synapse.storage.push_rule import InconsistentRuleException, RuleNotFoundException from synapse.storage.push_rule import InconsistentRuleException, RuleNotFoundException
import synapse.push.baserules as baserules import synapse.push.baserules as baserules
from synapse.push.rulekinds import PRIORITY_CLASS_MAP, PRIORITY_CLASS_INVERSE_MAP
import json import json
class PushRuleRestServlet(ClientV1RestServlet): class PushRuleRestServlet(ClientV1RestServlet):
PATTERN = client_path_pattern("/pushrules/.*$") PATTERN = client_path_pattern("/pushrules/.*$")
PRIORITY_CLASS_MAP = {
'default': 0,
'underride': 1,
'sender': 2,
'room': 3,
'content': 4,
'override': 5,
}
PRIORITY_CLASS_INVERSE_MAP = {v: k for k, v in PRIORITY_CLASS_MAP.items()}
SLIGHTLY_PEDANTIC_TRAILING_SLASH_ERROR = ( SLIGHTLY_PEDANTIC_TRAILING_SLASH_ERROR = (
"Unrecognised request: You probably wanted a trailing slash") "Unrecognised request: You probably wanted a trailing slash")
...@@ -48,11 +40,8 @@ class PushRuleRestServlet(ClientV1RestServlet): ...@@ -48,11 +40,8 @@ class PushRuleRestServlet(ClientV1RestServlet):
user, _ = yield self.auth.get_user_by_req(request) user, _ = yield self.auth.get_user_by_req(request)
if spec['template'] == 'default': if '/' in spec['rule_id'] or '\\' in spec['rule_id']:
raise SynapseError(403, "The default rules are immutable.") raise SynapseError(400, "rule_id may not contain slashes")
if not spec['rule_id'].isalnum():
raise SynapseError(400, "rule_id may only contain alphanumeric characters")
content = _parse_json(request) content = _parse_json(request)
...@@ -121,21 +110,23 @@ class PushRuleRestServlet(ClientV1RestServlet): ...@@ -121,21 +110,23 @@ class PushRuleRestServlet(ClientV1RestServlet):
# to send which means doing unnecessary work sometimes but is # to send which means doing unnecessary work sometimes but is
# is probably not going to make a whole lot of difference # is probably not going to make a whole lot of difference
rawrules = yield self.hs.get_datastore().get_push_rules_for_user_name(user.to_string()) rawrules = yield self.hs.get_datastore().get_push_rules_for_user_name(user.to_string())
for r in rawrules: for r in rawrules:
r["conditions"] = json.loads(r["conditions"]) r["conditions"] = json.loads(r["conditions"])
r["actions"] = json.loads(r["actions"]) r["actions"] = json.loads(r["actions"])
rawrules.extend(baserules.make_base_rules(user.to_string()))
ruleslist = baserules.list_with_base_rules(rawrules, user)
rules = {'global': {}, 'device': {}} rules = {'global': {}, 'device': {}}
rules['global'] = _add_empty_priority_class_arrays(rules['global']) rules['global'] = _add_empty_priority_class_arrays(rules['global'])
for r in rawrules: for r in ruleslist:
rulearray = None rulearray = None
template_name = _priority_class_to_template_name(r['priority_class']) template_name = _priority_class_to_template_name(r['priority_class'])
if r['priority_class'] > PushRuleRestServlet.PRIORITY_CLASS_MAP['override']: if r['priority_class'] > PRIORITY_CLASS_MAP['override']:
# per-device rule # per-device rule
profile_tag = _profile_tag_from_conditions(r["conditions"]) profile_tag = _profile_tag_from_conditions(r["conditions"])
r = _strip_device_condition(r) r = _strip_device_condition(r)
...@@ -290,7 +281,7 @@ def _rule_tuple_from_request_object(rule_template, rule_id, req_obj, device=None ...@@ -290,7 +281,7 @@ def _rule_tuple_from_request_object(rule_template, rule_id, req_obj, device=None
def _add_empty_priority_class_arrays(d): def _add_empty_priority_class_arrays(d):
for pc in PushRuleRestServlet.PRIORITY_CLASS_MAP.keys(): for pc in PRIORITY_CLASS_MAP.keys():
d[pc] = [] d[pc] = []
return d return d
...@@ -332,46 +323,48 @@ def _filter_ruleset_with_path(ruleset, path): ...@@ -332,46 +323,48 @@ def _filter_ruleset_with_path(ruleset, path):
def _priority_class_from_spec(spec): def _priority_class_from_spec(spec):
if spec['template'] not in PushRuleRestServlet.PRIORITY_CLASS_MAP.keys(): if spec['template'] not in PRIORITY_CLASS_MAP.keys():
raise InvalidRuleException("Unknown template: %s" % (spec['kind'])) raise InvalidRuleException("Unknown template: %s" % (spec['kind']))
pc = PushRuleRestServlet.PRIORITY_CLASS_MAP[spec['template']] pc = PRIORITY_CLASS_MAP[spec['template']]
if spec['scope'] == 'device': if spec['scope'] == 'device':
pc += len(PushRuleRestServlet.PRIORITY_CLASS_MAP) pc += len(PRIORITY_CLASS_MAP)
return pc return pc
def _priority_class_to_template_name(pc): def _priority_class_to_template_name(pc):
if pc > PushRuleRestServlet.PRIORITY_CLASS_MAP['override']: if pc > PRIORITY_CLASS_MAP['override']:
# per-device # per-device
prio_class_index = pc - len(PushRuleRestServlet.PRIORITY_CLASS_MAP) prio_class_index = pc - len(PushRuleRestServlet.PRIORITY_CLASS_MAP)
return PushRuleRestServlet.PRIORITY_CLASS_INVERSE_MAP[prio_class_index] return PRIORITY_CLASS_INVERSE_MAP[prio_class_index]
else: else:
return PushRuleRestServlet.PRIORITY_CLASS_INVERSE_MAP[pc] return PRIORITY_CLASS_INVERSE_MAP[pc]
def _rule_to_template(rule): def _rule_to_template(rule):
unscoped_rule_id = _rule_id_from_namespaced(rule['rule_id']) unscoped_rule_id = None
if 'rule_id' in rule:
_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 ['default']: if template_name in ['override', 'underride']:
return {k: rule[k] for k in ["conditions", "actions"]} templaterule = {k: rule[k] for k in ["conditions", "actions"]}
elif template_name in ['override', 'underride']:
ret = {k: rule[k] for k in ["conditions", "actions"]}
ret['rule_id'] = unscoped_rule_id
return ret
elif template_name in ["sender", "room"]: elif template_name in ["sender", "room"]:
return {'rule_id': unscoped_rule_id, 'actions': rule['actions']} templaterule = {'actions': rule['actions']}
unscoped_rule_id = rule['conditions'][0]['pattern']
elif template_name == 'content': elif template_name == 'content':
if len(rule["conditions"]) != 1: if len(rule["conditions"]) != 1:
return None return None
thecond = rule["conditions"][0] thecond = rule["conditions"][0]
if "pattern" not in thecond: if "pattern" not in thecond:
return None return None
ret = {'rule_id': unscoped_rule_id, 'actions': rule['actions']} templaterule = {'actions': rule['actions']}
ret["pattern"] = thecond["pattern"] templaterule["pattern"] = thecond["pattern"]
return ret
if unscoped_rule_id:
templaterule['rule_id'] = unscoped_rule_id
return templaterule
def _strip_device_condition(rule): def _strip_device_condition(rule):
...@@ -385,12 +378,12 @@ def _namespaced_rule_id_from_spec(spec): ...@@ -385,12 +378,12 @@ def _namespaced_rule_id_from_spec(spec):
if spec['scope'] == 'global': if spec['scope'] == 'global':
scope = 'global' scope = 'global'
else: else:
scope = 'device.%s' % (spec['profile_tag']) scope = 'device/%s' % (spec['profile_tag'])
return "%s.%s.%s" % (scope, spec['template'], spec['rule_id']) return "%s/%s/%s" % (scope, spec['template'], spec['rule_id'])
def _rule_id_from_namespaced(in_rule_id, spec): def _rule_id_from_namespaced(in_rule_id):
return in_rule_id.split('.')[-1] return in_rule_id.split('/')[-1]
class InvalidRuleException(Exception): class InvalidRuleException(Exception):
pass pass
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment