From 72547dcc5fb9c147e681496a662d0f16e8b78487 Mon Sep 17 00:00:00 2001 From: scur-iolus Date: Fri, 31 Jan 2025 11:21:58 +0100 Subject: [PATCH] fix: ensure transactional integrity in tenant and user operations --- tenant_users/tenants/models.py | 8 +++++++- tenant_users/tenants/tasks.py | 2 +- tenant_users/tenants/utils.py | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tenant_users/tenants/models.py b/tenant_users/tenants/models.py index ffbe62ae..550e8349 100644 --- a/tenant_users/tenants/models.py +++ b/tenant_users/tenants/models.py @@ -3,7 +3,7 @@ from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.models import AbstractBaseUser, BaseUserManager -from django.db import connection, models +from django.db import connection, models, transaction from django.dispatch import Signal from django.utils.translation import gettext_lazy as _ from django_tenants.models import TenantMixin @@ -98,6 +98,7 @@ def delete(self, *args, force_drop: bool = False, **kwargs): raise DeleteError(TENANT_DELETE_ERROR_MESSAGE) @schema_required + @transaction.atomic def add_user(self, user_obj, *, is_superuser: bool = False, is_staff: bool = False): """Add user to tenant. @@ -129,6 +130,7 @@ def add_user(self, user_obj, *, is_superuser: bool = False, is_staff: bool = Fal ) @schema_required + @transaction.atomic def remove_user(self, user_obj): """Remove user from tenant.""" # Test that user is already in the tenant @@ -161,6 +163,7 @@ def remove_user(self, user_obj): tenant=self, ) + @transaction.atomic def delete_tenant(self): """Mark tenant for deletion. @@ -204,6 +207,7 @@ def delete_tenant(self): self.remove_user(old_owner) @schema_required + @transaction.atomic def transfer_ownership(self, new_owner): old_owner = self.owner @@ -236,6 +240,7 @@ class Meta: class UserProfileManager(BaseUserManager): + @transaction.atomic def _create_user( self, email, @@ -332,6 +337,7 @@ def create_superuser(self, password, email=None, **extra_fields): **extra_fields, ) + @transaction.atomic def delete_user(self, user_obj): # Check to make sure we don't try to delete the public tenant owner # that would be bad.... diff --git a/tenant_users/tenants/tasks.py b/tenant_users/tenants/tasks.py index e5b1e274..1587195e 100644 --- a/tenant_users/tenants/tasks.py +++ b/tenant_users/tenants/tasks.py @@ -22,7 +22,7 @@ DomainModel = get_tenant_domain_model() -@transaction.atomic() +@transaction.atomic def provision_tenant( # noqa: PLR0913 tenant_name: str, tenant_slug: str, diff --git a/tenant_users/tenants/utils.py b/tenant_users/tenants/utils.py index 943058d4..dcb750fd 100644 --- a/tenant_users/tenants/utils.py +++ b/tenant_users/tenants/utils.py @@ -1,7 +1,7 @@ from typing import Optional from django.contrib.auth import get_user_model -from django.db import connection +from django.db import connection, transaction from django_tenants.utils import ( get_multi_type_database_field_name, get_public_schema_name, @@ -32,6 +32,7 @@ def get_current_tenant(): return tenant +@transaction.atomic def create_public_tenant( domain_url, owner_email,