Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Transfer user's push rules on room upgrade #4838

Merged
merged 12 commits into from
Mar 12, 2019
1 change: 1 addition & 0 deletions changelog.d/4838.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Transfer a user's notification settings (push rules) on room upgrade.
4 changes: 4 additions & 0 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ def _local_membership_update(
self.copy_room_tags_and_direct_to_room(
predecessor["room_id"], room_id, user_id,
)
# Move over old push rules
self.store.move_push_rules_from_room_to_room_for_user(
predecessor["room_id"], room_id, user_id,
)
elif event.membership == Membership.LEAVE:
if prev_member_event_id:
prev_member_event = yield self.store.get_event(prev_member_event_id)
Expand Down
57 changes: 57 additions & 0 deletions synapse/storage/push_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,63 @@ def bulk_get_push_rules(self, user_ids):

defer.returnValue(results)

@defer.inlineCallbacks
def move_push_rule_from_room_to_room(
self, new_room_id, user_id, rule,
):
"""Move a single push rule from one room to another for a specific user.

Args:
new_room_id (str): ID of the new room.
user_id (str): ID of user the push rule belongs to.
rule (Dict): A push rule.
"""
# Create new rule id
rule_id_scope = '/'.join(rule["rule_id"].split('/')[:-1])
new_rule_id = rule_id_scope + "/" + new_room_id

# Change room id in each condition
for condition in rule["conditions"]:
if condition.get("key") == "room_id":
condition["pattern"] = new_room_id

# Add the rule for the new room
yield self.add_push_rule(
user_id=user_id,
rule_id=new_rule_id,
priority_class=rule["priority_class"],
conditions=rule["conditions"],
actions=rule["actions"],
)

# Delete push rule for the old room
yield self.delete_push_rule(user_id, rule["rule_id"])

@defer.inlineCallbacks
def move_push_rules_from_room_to_room_for_user(
self, old_room_id, new_room_id, user_id,
):
"""Move all of the push rules from one room to another for a specific
user.

Args:
old_room_id (str): ID of the old room.
new_room_id (str): ID of the new room.
user_id (str): ID of user to copy push rules for.
"""
# Retrieve push rules for this user
user_push_rules = yield self.get_push_rules_for_user(user_id)

# Get rules relating to the old room, move them to the new room, then
# delete them from the old room
for rule in user_push_rules:
for condition in rule["conditions"]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conditions is apparently optional:

Suggested change
for condition in rule["conditions"]:
for condition in rule.get("conditions", []):

if condition.get("key") == "room_id":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we probably need to worry about what happens if somebody makes a rule that has two conditions that match: I suspect your code will blow up.

an easy fix might be:

conditions = rule.get("conditions", [])
if any((c.get("key") == "room_id" and c.get("pattern") == old_room_id) for c in conditions):
    # ... move

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works and is very pythonic, thanks.

if condition.get("pattern") == old_room_id:
self.move_push_rule_from_room_to_room(
new_room_id, user_id, rule,
)

@defer.inlineCallbacks
def bulk_get_push_rules_for_room(self, event, context):
state_group = context.state_group
Expand Down