Add DAO function to archive a user

For a user to be able to be archived, each service that they are a
member of must have at least one other user who is active and who has
the 'manage-settings' permission.

To archive a user we remove them from all their services and
organisations, remove all permissions that they have and change some of
their details:
- email_address will start with '_archived_<date>'
- the current_session_id is changed (to sign them out of their current
session)
- mobile_number is removed (so we also need to switch their auth type to
email_auth)
- password is changed to a random password
- state is changed to 'inactive'

If any of the steps fail, we rollback all changes.
This commit is contained in:
Katie Smith
2019-05-21 15:53:48 +01:00
parent 844f22bcd0
commit bef24408d0
5 changed files with 182 additions and 6 deletions

View File

@@ -38,6 +38,10 @@ class PermissionDAO(DAOClass):
query = self.Meta.model.query.filter_by(user=user, service=service)
query.delete()
def remove_user_service_permissions_for_all_services(self, user):
query = self.Meta.model.query.filter_by(user=user)
query.delete()
def set_user_service_permission(self, user, service, permissions, _commit=False, replace=False):
try:
if replace:
@@ -59,5 +63,9 @@ class PermissionDAO(DAOClass):
return self.Meta.model.query.filter_by(user_id=user_id)\
.join(Permission.service).filter_by(active=True).all()
def get_permissions_by_user_id_and_service_id(self, user_id, service_id):
return self.Meta.model.query.filter_by(user_id=user_id)\
.join(Permission.service).filter_by(active=True, id=service_id).all()
permission_dao = PermissionDAO()

View File

@@ -17,6 +17,10 @@ def dao_get_active_service_users(service_id):
return query.all()
def dao_get_service_users_by_user_id(user_id):
return ServiceUser.query.filter_by(user_id=user_id).all()
@transactional
def dao_update_service_user(service_user):
db.session.add(service_user)

View File

@@ -1,11 +1,16 @@
from random import (SystemRandom)
from datetime import (datetime, timedelta)
import uuid
from sqlalchemy import func
from sqlalchemy.orm import joinedload
from app import db
from app.models import (User, VerifyCode)
from app.dao.permissions_dao import permission_dao
from app.dao.service_user_dao import dao_get_service_users_by_user_id
from app.dao.dao_utils import transactional
from app.errors import InvalidRequest
from app.models import (EMAIL_AUTH_TYPE, User, VerifyCode)
from app.utils import escape_special_characters
@@ -135,3 +140,49 @@ def get_user_and_accounts(user_id):
joinedload('organisations.services'),
joinedload('services.organisation'),
).one()
@transactional
def dao_archive_user(user):
if not user_can_be_archived(user):
msg = "User cant be removed from a service - check all services have another team member with manage_settings"
raise InvalidRequest(msg, 400)
permission_dao.remove_user_service_permissions_for_all_services(user)
service_users = dao_get_service_users_by_user_id(user.id)
for service_user in service_users:
db.session.delete(service_user)
user.organisations = []
user.auth_type = EMAIL_AUTH_TYPE
user.email_address = get_archived_email_address(user.email_address)
user.mobile_number = None
user.password = str(uuid.uuid4())
# Changing the current_session_id signs the user out
user.current_session_id = '00000000-0000-0000-0000-000000000000'
user.state = 'inactive'
db.session.add(user)
def user_can_be_archived(user):
active_services = [x for x in user.services if x.active]
for service in active_services:
other_active_users = [x for x in service.users if x.state == 'active' and x != user]
if not other_active_users:
return False
if not any('manage_settings' in user.get_permissions(service.id) for user in other_active_users):
# no-one else has manage settings
return False
return True
def get_archived_email_address(email_address):
date = datetime.utcnow().strftime("%Y-%m-%d")
return '_archived_{}_{}'.format(date, email_address)

View File

@@ -137,8 +137,14 @@ class User(db.Model):
def check_password(self, password):
return check_hash(password, self._password)
def get_permissions(self):
def get_permissions(self, service_id=None):
from app.dao.permissions_dao import permission_dao
if service_id:
return [
x.permission for x in permission_dao.get_permissions_by_user_id_and_service_id(self.id, service_id)
]
retval = {}
for x in permission_dao.get_permissions_by_user_id(self.id):
service_id = str(x.service_id)