✨(backend) process reconciliation requests as transactions
Process each reconciliation requests individually as a transaction, with the bulk updates/deletes made for each requests, to avoid interference between requests and unwanted states
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
from django.contrib import admin, messages
|
||||
from django.contrib.auth import admin as auth_admin
|
||||
from django.db import transaction
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
@@ -119,39 +120,13 @@ def process_reconciliation(_modeladmin, _request, queryset):
|
||||
Admin action to process selected user reconciliations.
|
||||
The action will process only entries that are ready and have both emails checked.
|
||||
|
||||
Its action is threefold:
|
||||
- Transfer document accesses from inactive to active user, updating roles as needed.
|
||||
- Activate the active user and deactivate the inactive user.
|
||||
"""
|
||||
processable_entries = queryset.filter(
|
||||
status="ready", active_email_checked=True, inactive_email_checked=True
|
||||
)
|
||||
|
||||
# Prepare the bulk operations
|
||||
updated_documentaccess = []
|
||||
removed_documentaccess = []
|
||||
update_users_active_status = []
|
||||
|
||||
for entry in processable_entries:
|
||||
new_updated_documentaccess, new_removed_documentaccess = (
|
||||
entry.process_documentaccess_reconciliation()
|
||||
)
|
||||
updated_documentaccess += new_updated_documentaccess
|
||||
removed_documentaccess += new_removed_documentaccess
|
||||
|
||||
entry.active_user.is_active = True
|
||||
entry.inactive_user.is_active = False
|
||||
update_users_active_status.append(entry.active_user)
|
||||
update_users_active_status.append(entry.inactive_user)
|
||||
|
||||
# Actually perform the bulk operations
|
||||
models.DocumentAccess.objects.bulk_update(updated_documentaccess, ["user", "role"])
|
||||
|
||||
if removed_documentaccess:
|
||||
ids_to_delete = [rd.id for rd in removed_documentaccess]
|
||||
models.DocumentAccess.objects.filter(id__in=ids_to_delete).delete()
|
||||
|
||||
models.User.objects.bulk_update(update_users_active_status, ["is_active"])
|
||||
entry.process_reconciliation_request()
|
||||
|
||||
|
||||
@admin.register(models.UserReconciliation)
|
||||
|
||||
@@ -378,9 +378,44 @@ class UserReconciliation(BaseModel):
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def process_documentaccess_reconciliation(self):
|
||||
@transaction.atomic
|
||||
def process_reconciliation_request(self):
|
||||
"""
|
||||
Process the reconciliation by transferring document accesses from the inactive user
|
||||
Process the reconciliation request as a transaction.
|
||||
|
||||
Its action is threefold:
|
||||
- Transfer document accesses from inactive to active user, updating roles as needed.
|
||||
- Activate the active user and deactivate the inactive user.
|
||||
- Update the reconciliation entry itself.
|
||||
"""
|
||||
|
||||
# Prepare the data to perform the reconciliation on
|
||||
updated_accesses, removed_accesses = (
|
||||
self.prepare_documentaccess_reconciliation()
|
||||
)
|
||||
self.active_user.is_active = True
|
||||
self.inactive_user.is_active = False
|
||||
|
||||
# Actually perform the bulk operations
|
||||
DocumentAccess.objects.bulk_update(updated_accesses, ["user", "role"])
|
||||
|
||||
if removed_accesses:
|
||||
ids_to_delete = [rd.id for rd in removed_accesses]
|
||||
DocumentAccess.objects.filter(id__in=ids_to_delete).delete()
|
||||
|
||||
User.objects.bulk_update([self.active_user, self.inactive_user], ["is_active"])
|
||||
|
||||
# Wrap up the reconciliation entry
|
||||
self.logs += f"""Requested update for {len(updated_accesses)} DocumentAccess items
|
||||
and deletion for {len(removed_accesses)} DocumentAccess items.\n"""
|
||||
self.status = "done"
|
||||
self.save()
|
||||
|
||||
self.send_reconciliation_done_email()
|
||||
|
||||
def prepare_documentaccess_reconciliation(self):
|
||||
"""
|
||||
Prepare the reconciliation by transferring document accesses from the inactive user
|
||||
to the active user.
|
||||
"""
|
||||
updated_accesses = []
|
||||
@@ -408,13 +443,6 @@ class UserReconciliation(BaseModel):
|
||||
entry.user = self.active_user
|
||||
updated_accesses.append(entry)
|
||||
|
||||
self.logs += f"""Requested update for {len(updated_accesses)} DocumentAccess items
|
||||
and deletion for {len(removed_accesses)} DocumentAccess items.\n"""
|
||||
self.status = "done"
|
||||
self.send_reconciliation_done_email()
|
||||
|
||||
self.save()
|
||||
|
||||
return updated_accesses, removed_accesses
|
||||
|
||||
def send_reconciliation_confirm_email(
|
||||
|
||||
Reference in New Issue
Block a user