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

Part user from rooms on account deactivate #3201

Merged
merged 8 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 79 additions & 2 deletions synapse/handlers/deactivate_account.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Copyright 2017 New Vector Ltd
# Copyright 2017, 2018 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -12,9 +12,11 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from twisted.internet import defer
from twisted.internet import defer, reactor

from ._base import BaseHandler
from synapse.types import UserID, create_requester
from synapse.util.logcontext import run_in_background

import logging

Expand All @@ -27,6 +29,14 @@ def __init__(self, hs):
super(DeactivateAccountHandler, self).__init__(hs)
self._auth_handler = hs.get_auth_handler()
self._device_handler = hs.get_device_handler()
self._room_member_handler = hs.get_room_member_handler()

# Flag that indicates whether the process to part users from rooms is running
self._user_parter_running = False

# Start the user parter loop so it can resume parting users from rooms where
# it left off (if it has work left to do).
reactor.callWhenRunning(self._start_user_parting)

@defer.inlineCallbacks
def deactivate_account(self, user_id):
Expand All @@ -50,3 +60,70 @@ def deactivate_account(self, user_id):

yield self.store.user_delete_threepids(user_id)
yield self.store.user_set_password_hash(user_id, None)

# Add the user to a table of users penpding deactivation (ie.
# removal from all the rooms they're a member of)
yield self.store.add_user_pending_deactivation(user_id)

# Now start the process that goes through that list and
# parts users from rooms (if it isn't already running)
self._start_user_parting()

def _start_user_parting(self):
"""
Start the process that goes through the table of users
pending deactivation, if it isn't already running.

Returns:
None
"""
if not self._user_parter_running:
run_in_background(self._user_parter_loop)

@defer.inlineCallbacks
def _user_parter_loop(self):
"""Loop that parts deactivated users from rooms

Returns:
None
"""
self._user_parter_running = True
logger.info("Starting user parter")
try:
while True:
user_id = yield self.store.get_user_pending_deactivation()
if user_id is None:
break
logger.info("User parter parting %r", user_id)
yield self._part_user(user_id)
yield self.store.del_user_pending_deactivation(user_id)
logger.info("User parter finished parting %r", user_id)
logger.info("User parter finished: stopping")
finally:
self._user_parter_running = False

@defer.inlineCallbacks
def _part_user(self, user_id):
"""Causes the given user_id to leave all the rooms they're joined to

Returns:
None
"""
user = UserID.from_string(user_id)

rooms_for_user = yield self.store.get_rooms_for_user(user_id)
for room_id in rooms_for_user:
logger.info("User parter parting %r from %r", user_id, room_id)
try:
yield self._room_member_handler.update_membership(
create_requester(user),
user,
room_id,
"leave",
ratelimit=False,
)
except Exception:
logger.exception(
"Failed to part user %r from room %r: ignoring and continuing",
user_id, room_id,
)
39 changes: 39 additions & 0 deletions synapse/storage/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,3 +526,42 @@ def insert(txn):
except self.database_engine.module.IntegrityError:
ret = yield self.get_3pid_guest_access_token(medium, address)
defer.returnValue(ret)

def add_user_pending_deactivation(self, user_id):
"""
Adds a user to the table of users who need to be parted from all the rooms they're
in
"""
return self._simple_insert(
"users_pending_deactivation",
values={
"user_id": user_id,
},
desc="add_user_pending_deactivation",
)

def del_user_pending_deactivation(self, user_id):
"""
Removes the given user to the table of users who need to be parted from all the
rooms they're in, effectively marking that user as fully deactivated.
"""
return self._simple_delete_one(
"users_pending_deactivation",
keyvalues={
"user_id": user_id,
},
desc="del_user_pending_deactivation",
)

def get_user_pending_deactivation(self):
"""
Gets one user from the table of users waiting to be parted from all the rooms
they're in.
"""
return self._simple_select_one_onecol(
"users_pending_deactivation",
keyvalues={},
retcol="user_id",
allow_none=True,
desc="get_users_pending_deactivation",
)
25 changes: 25 additions & 0 deletions synapse/storage/schema/delta/48/deactivated_users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Copyright 2018 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* Store any accounts that have been requested to be deactivated.
* We part the account from all the rooms its in when its
* deactivated. This can take some time and synapse may be restarted
* before it completes, so store the user IDs here until the process
* is complete.
*/
CREATE TABLE users_pending_deactivation (
user_id TEXT NOT NULL
);