Invoke auth handler when deleting a user via importer

plus some misc. tweaks i needed to cleanup some user accounts
This commit is contained in:
Lance Edgar 2021-10-14 14:17:58 -04:00
parent a8d820fe99
commit d98afd2c0f
4 changed files with 58 additions and 4 deletions

View file

@ -28,6 +28,8 @@ See also :doc:`rattail-manual:base/handlers/other/auth`.
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
import sqlalchemy_continuum as continuum
from rattail.app import GenericHandler from rattail.app import GenericHandler
@ -189,3 +191,39 @@ class AuthHandler(GenericHandler):
include_guest=include_guest, include_guest=include_guest,
include_authenticated=include_authenticated) include_authenticated=include_authenticated)
return permission in perms return permission in perms
def delete_user(self, user, **kwargs):
"""
Delete the given user account. Use with caution! As this
generally cannot be undone.
Default behavior here is of course to delete the account, but
it also must try to "remove" the user association from various
places, in particular the continuum transactions table.
Please note that this will leave certain record versions as
appearing to be "without an author".
"""
session = self.app.get_session(user)
# disassociate user from transactions
self.remove_user_from_continuum_transactions(user)
# finally, delete the user outright
session.delete(user)
return True
def remove_user_from_continuum_transactions(self, user):
"""
Remove the given user from all Continuum transactions.
"""
session = self.app.get_session(user)
model = self.model
# remove the user from any continuum transactions
# nb. we can use "any" model class here, to obtain Transaction
Transaction = continuum.transaction_class(model.User)
transactions = session.query(Transaction)\
.filter(Transaction.user_id == user.uuid)\
.all()
for txn in transactions:
txn.user_id = None

View file

@ -543,6 +543,15 @@ class UserImporter(ToRattail):
auth.set_user_password(user, data['plain_password']) auth.set_user_password(user, data['plain_password'])
return user return user
def delete_object(self, user):
"""
Override this to invoke the auth handler for user deletion,
since it may have extra smarts.
"""
auth = self.app.get_auth_handler()
auth.delete_user(user)
return True
class AdminUserImporter(UserImporter): class AdminUserImporter(UserImporter):
""" """

View file

@ -349,15 +349,17 @@ class GlobalRoleImporter(RoleImporter):
for new_user in new_users: for new_user in new_users:
if new_user not in old_users: if new_user not in old_users:
user = self.session.query(model.User).get(new_user) user = self.session.query(model.User).get(new_user)
user.roles.append(role) if user:
changed = True user.roles.append(role)
changed = True
# remove some users # remove some users
for old_user in old_users: for old_user in old_users:
if old_user not in new_users: if old_user not in new_users:
user = self.session.query(model.User).get(old_user) user = self.session.query(model.User).get(old_user)
user.roles.remove(role) if user:
changed = True user.roles.remove(role)
changed = True
if changed: if changed:
# also record a change to the role, for datasync. # also record a change to the role, for datasync.

View file

@ -314,6 +314,7 @@ class PeopleHandler(GenericHandler):
F('last_name'), F('last_name'),
F('display_name'), F('display_name'),
F('usernames', additive=True), F('usernames', additive=True),
F('employee_uuid'),
F('member_uuids', additive=True), F('member_uuids', additive=True),
] ]
@ -328,6 +329,7 @@ class PeopleHandler(GenericHandler):
'last_name': person.last_name, 'last_name': person.last_name,
'display_name': person.display_name, 'display_name': person.display_name,
'usernames': [u.username for u in person.users], 'usernames': [u.username for u in person.users],
'employee_uuid': person.employee.uuid if person.employee else None,
'member_uuids': [m.uuid for m in person.members], 'member_uuids': [m.uuid for m in person.members],
} }
@ -379,6 +381,9 @@ class PeopleHandler(GenericHandler):
merge happen. merge happen.
:returns: String indicating reason not to merge, or ``None``. :returns: String indicating reason not to merge, or ``None``.
""" """
if removing.employee and keeping.employee:
if removing.employee is not keeping.employee:
return "Cannot merge 2 people who are distinct employees"
def perform_merge(self, removing, keeping, **kwargs): def perform_merge(self, removing, keeping, **kwargs):
""" """