oxutils 0.1.8__py3-none-any.whl → 0.1.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oxutils/__init__.py +2 -1
- oxutils/constants.py +4 -0
- oxutils/jwt/auth.py +150 -1
- oxutils/jwt/models.py +13 -0
- oxutils/logger/receivers.py +10 -6
- oxutils/models/base.py +102 -0
- oxutils/models/fields.py +79 -0
- oxutils/oxiliere/apps.py +6 -1
- oxutils/oxiliere/authorization.py +45 -0
- oxutils/oxiliere/caches.py +8 -7
- oxutils/oxiliere/checks.py +31 -0
- oxutils/oxiliere/constants.py +3 -0
- oxutils/oxiliere/context.py +18 -0
- oxutils/oxiliere/exceptions.py +16 -0
- oxutils/oxiliere/management/commands/grant_tenant_owners.py +19 -0
- oxutils/oxiliere/management/commands/init_oxiliere_system.py +20 -8
- oxutils/oxiliere/middleware.py +29 -13
- oxutils/oxiliere/models.py +130 -19
- oxutils/oxiliere/permissions.py +6 -5
- oxutils/oxiliere/schemas.py +13 -4
- oxutils/oxiliere/signals.py +5 -0
- oxutils/oxiliere/utils.py +18 -0
- oxutils/pagination/__init__.py +0 -0
- oxutils/pagination/cursor.py +367 -0
- oxutils/permissions/__init__.py +0 -0
- oxutils/permissions/actions.py +57 -0
- oxutils/permissions/admin.py +3 -0
- oxutils/permissions/apps.py +10 -0
- oxutils/permissions/caches.py +19 -0
- oxutils/permissions/checks.py +188 -0
- oxutils/permissions/constants.py +0 -0
- oxutils/permissions/controllers.py +344 -0
- oxutils/permissions/exceptions.py +60 -0
- oxutils/permissions/management/__init__.py +0 -0
- oxutils/permissions/management/commands/__init__.py +0 -0
- oxutils/permissions/management/commands/load_permission_preset.py +112 -0
- oxutils/permissions/migrations/0001_initial.py +112 -0
- oxutils/permissions/migrations/0002_alter_grant_role.py +19 -0
- oxutils/permissions/migrations/0003_alter_grant_options_alter_group_options_and_more.py +33 -0
- oxutils/permissions/migrations/__init__.py +0 -0
- oxutils/permissions/models.py +171 -0
- oxutils/permissions/perms.py +95 -0
- oxutils/permissions/queryset.py +92 -0
- oxutils/permissions/schemas.py +276 -0
- oxutils/permissions/services.py +663 -0
- oxutils/permissions/tests.py +3 -0
- oxutils/permissions/utils.py +628 -0
- oxutils/settings.py +1 -0
- oxutils/users/migrations/0002_alter_user_first_name_alter_user_last_name.py +23 -0
- oxutils/users/models.py +2 -0
- {oxutils-0.1.8.dist-info → oxutils-0.1.10.dist-info}/METADATA +1 -1
- {oxutils-0.1.8.dist-info → oxutils-0.1.10.dist-info}/RECORD +53 -19
- {oxutils-0.1.8.dist-info → oxutils-0.1.10.dist-info}/WHEEL +0 -0
oxutils/oxiliere/middleware.py
CHANGED
|
@@ -7,15 +7,21 @@ from django.utils.deprecation import MiddlewareMixin
|
|
|
7
7
|
|
|
8
8
|
from django_tenants.utils import (
|
|
9
9
|
get_public_schema_name,
|
|
10
|
-
get_public_schema_urlconf
|
|
10
|
+
get_public_schema_urlconf,
|
|
11
|
+
get_tenant_types,
|
|
12
|
+
has_multi_type_tenants,
|
|
11
13
|
)
|
|
12
14
|
from oxutils.settings import oxi_settings
|
|
13
15
|
from oxutils.constants import (
|
|
14
16
|
ORGANIZATION_HEADER_KEY,
|
|
15
17
|
ORGANIZATION_TOKEN_COOKIE_KEY
|
|
16
18
|
)
|
|
19
|
+
from oxutils.oxiliere.utils import is_system_tenant
|
|
17
20
|
from oxutils.jwt.models import TokenTenant
|
|
18
21
|
from oxutils.jwt.tokens import OrganizationAccessToken
|
|
22
|
+
from oxutils.oxiliere.context import set_current_tenant_schema_name
|
|
23
|
+
|
|
24
|
+
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
class TenantMainMiddleware(MiddlewareMixin):
|
|
@@ -45,9 +51,6 @@ class TenantMainMiddleware(MiddlewareMixin):
|
|
|
45
51
|
connection.set_schema_to_public()
|
|
46
52
|
|
|
47
53
|
oxi_id = self.get_org_id_from_request(request)
|
|
48
|
-
if not oxi_id:
|
|
49
|
-
from django.http import HttpResponseBadRequest
|
|
50
|
-
return HttpResponseBadRequest('Missing X-Organization-ID header')
|
|
51
54
|
|
|
52
55
|
# Try to get tenant from cookie token first
|
|
53
56
|
tenant_token = request.COOKIES.get(ORGANIZATION_TOKEN_COOKIE_KEY)
|
|
@@ -57,21 +60,34 @@ class TenantMainMiddleware(MiddlewareMixin):
|
|
|
57
60
|
if tenant_token:
|
|
58
61
|
tenant = TokenTenant.for_token(tenant_token)
|
|
59
62
|
# Verify the token's oxi_id matches the request
|
|
60
|
-
if tenant and tenant.oxi_id != oxi_id:
|
|
63
|
+
if not is_system_tenant(tenant) and tenant.oxi_id != oxi_id:
|
|
61
64
|
tenant = None
|
|
62
65
|
|
|
63
66
|
# If no valid token, fetch from database
|
|
64
67
|
if not tenant:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
if oxi_id: # fetch with oxi_id on tenant
|
|
69
|
+
tenant_model = connection.tenant_model
|
|
70
|
+
try:
|
|
71
|
+
tenant = self.get_tenant(tenant_model, oxi_id)
|
|
72
|
+
# Mark that we need to set the cookie in the response
|
|
73
|
+
request._should_set_tenant_cookie = True
|
|
74
|
+
except tenant_model.DoesNotExist:
|
|
75
|
+
default_tenant = self.no_tenant_found(request, oxi_id)
|
|
76
|
+
return default_tenant
|
|
77
|
+
else: # try to return the system tenant
|
|
78
|
+
try:
|
|
79
|
+
from oxutils.oxiliere.caches import get_system_tenant
|
|
80
|
+
tenant = get_system_tenant()
|
|
81
|
+
request._should_set_tenant_cookie = True
|
|
82
|
+
except Exception as e:
|
|
83
|
+
from django.http import HttpResponseBadRequest
|
|
84
|
+
return HttpResponseBadRequest('Missing X-Organization-ID header')
|
|
85
|
+
|
|
86
|
+
if tenant.is_deleted or not tenant.is_active:
|
|
87
|
+
return self.no_tenant_found(request, oxi_id)
|
|
73
88
|
|
|
74
89
|
request.tenant = tenant
|
|
90
|
+
set_current_tenant_schema_name(tenant.schema_name)
|
|
75
91
|
connection.set_tenant(request.tenant)
|
|
76
92
|
self.setup_url_routing(request)
|
|
77
93
|
|
oxutils/oxiliere/models.py
CHANGED
|
@@ -1,25 +1,44 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import uuid
|
|
3
|
+
import structlog
|
|
1
4
|
from django.db import models
|
|
5
|
+
from django.utils import timezone
|
|
6
|
+
from django.contrib.auth.models import AbstractBaseUser
|
|
2
7
|
from django.conf import settings
|
|
3
8
|
from django.utils.translation import gettext_lazy as _
|
|
4
9
|
from django_tenants.models import TenantMixin
|
|
5
10
|
from oxutils.models import (
|
|
6
|
-
TimestampMixin,
|
|
7
11
|
BaseModelMixin,
|
|
8
|
-
UUIDPrimaryKeyMixin,
|
|
9
12
|
)
|
|
10
13
|
from oxutils.oxiliere.enums import TenantStatus
|
|
14
|
+
from oxutils.oxiliere.exceptions import DeleteError
|
|
15
|
+
from oxutils.oxiliere.signals import (
|
|
16
|
+
tenant_user_removed,
|
|
17
|
+
tenant_user_added,
|
|
18
|
+
)
|
|
19
|
+
from oxutils.oxiliere.utils import (
|
|
20
|
+
is_system_tenant,
|
|
21
|
+
generate_schema_name,
|
|
22
|
+
)
|
|
11
23
|
|
|
24
|
+
logger = structlog.get_logger(__name__)
|
|
12
25
|
|
|
13
26
|
|
|
27
|
+
class TenantQuerySet(models.QuerySet):
|
|
28
|
+
def active(self):
|
|
29
|
+
return self.filter(is_deleted=False)
|
|
14
30
|
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
def deleted(self):
|
|
32
|
+
return self.filter(is_deleted=True)
|
|
17
33
|
|
|
34
|
+
class TenantManager(models.Manager):
|
|
35
|
+
def get_queryset(self):
|
|
36
|
+
return TenantQuerySet(self.model, using=self._db).active()
|
|
18
37
|
|
|
19
38
|
|
|
20
|
-
class BaseTenant(TenantMixin,
|
|
39
|
+
class BaseTenant(TenantMixin, BaseModelMixin):
|
|
21
40
|
name = models.CharField(max_length=100)
|
|
22
|
-
oxi_id = models.CharField(unique=True)
|
|
41
|
+
oxi_id = models.CharField(unique=True, max_length=25)
|
|
23
42
|
subscription_plan = models.CharField(max_length=255, null=True, blank=True)
|
|
24
43
|
subscription_status = models.CharField(max_length=255, null=True, blank=True)
|
|
25
44
|
subscription_end_date = models.DateTimeField(null=True, blank=True)
|
|
@@ -29,24 +48,126 @@ class BaseTenant(TenantMixin, UUIDPrimaryKeyMixin, TimestampMixin):
|
|
|
29
48
|
default=TenantStatus.ACTIVE
|
|
30
49
|
)
|
|
31
50
|
|
|
51
|
+
# soft delete
|
|
52
|
+
is_deleted = models.BooleanField(default=False)
|
|
53
|
+
deleted_at = models.DateTimeField(null=True, blank=True)
|
|
54
|
+
|
|
55
|
+
suffix = models.CharField(max_length=8, editable=False)
|
|
56
|
+
|
|
32
57
|
# default true, schema will be automatically created and synced when it is saved
|
|
33
58
|
auto_create_schema = True
|
|
59
|
+
# Schema will be automatically deleted when related tenant is deleted
|
|
60
|
+
auto_drop_schema = True
|
|
61
|
+
|
|
62
|
+
objects = models.Manager()
|
|
63
|
+
active = TenantManager()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def __str__(self):
|
|
67
|
+
return self.name
|
|
68
|
+
|
|
69
|
+
def save(self, *args, **kwargs):
|
|
70
|
+
if self._state.adding:
|
|
71
|
+
self.suffix = uuid.uuid4().hex[:8]
|
|
72
|
+
self.schema_name = generate_schema_name(self.oxi_id, self.suffix)
|
|
73
|
+
super().save(*args, **kwargs)
|
|
74
|
+
|
|
75
|
+
def delete(self, *args, force_drop: bool = False, **kwargs) -> None:
|
|
76
|
+
"""Override deleting of Tenant object.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
force_drop (bool): If True, forces the deletion of the object. Defaults to False.
|
|
80
|
+
*args: Variable length argument list.
|
|
81
|
+
**kwargs: Arbitrary keyword arguments.
|
|
82
|
+
"""
|
|
83
|
+
if force_drop:
|
|
84
|
+
super().delete(force_drop, *args, **kwargs)
|
|
85
|
+
else:
|
|
86
|
+
logger.warning("Tenant deletion is not allowed. Use delete_tenant to delete the tenant.")
|
|
87
|
+
raise DeleteError(_("Tenant deletion is not allowed. Use delete_tenant to delete the tenant."))
|
|
88
|
+
|
|
89
|
+
def delete_tenant(self) -> None:
|
|
90
|
+
"""Mark tenant for deletion."""
|
|
91
|
+
|
|
92
|
+
if self.is_deleted:
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# Prevent public tenant schema from being deleted
|
|
96
|
+
if is_system_tenant(self):
|
|
97
|
+
logger.warning("Cannot delete public tenant schema.")
|
|
98
|
+
raise ValueError(_("Cannot delete public tenant schema"))
|
|
99
|
+
|
|
100
|
+
time_string = str(int(time.time()))
|
|
101
|
+
new_id = f"{time_string}-deleted-{self.oxi_id}"
|
|
102
|
+
|
|
103
|
+
self.oxi_id = new_id
|
|
104
|
+
self.deleted_at = timezone.now()
|
|
105
|
+
self.is_deleted = True
|
|
106
|
+
self.is_active = False
|
|
107
|
+
self.status = TenantStatus.DELETED
|
|
108
|
+
|
|
109
|
+
self.save(update_fields=[
|
|
110
|
+
'oxi_id', 'deleted_at', 'is_deleted', 'is_active', 'status'
|
|
111
|
+
])
|
|
112
|
+
|
|
113
|
+
def restore(self):
|
|
114
|
+
if not self.is_deleted:
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
oxi_id = self.oxi_id.split("-deleted-")[1]
|
|
118
|
+
self.oxi_id = oxi_id
|
|
119
|
+
self.is_deleted = False
|
|
120
|
+
self.deleted_at = None
|
|
121
|
+
self.is_active = True
|
|
122
|
+
self.status = TenantStatus.ACTIVE
|
|
123
|
+
self.save(update_fields=["oxi_id", "is_deleted", "deleted_at", "is_active", "status"])
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def add_user(self, user: AbstractBaseUser, is_owner: bool = False, is_admin: bool = False):
|
|
127
|
+
"""Add user to tenant."""
|
|
128
|
+
|
|
129
|
+
if self.users.filter(user=user).exists():
|
|
130
|
+
logger.warning("User is already a member of this tenant.")
|
|
131
|
+
raise ValueError(_("User is already a member of this tenant."))
|
|
132
|
+
|
|
133
|
+
self.users.create(user=user, is_owner=is_owner, is_admin=is_admin)
|
|
134
|
+
tenant_user_added.send(sender=self.__class__, tenant=self, user=user)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def remove_user(self, user: AbstractBaseUser):
|
|
138
|
+
"""Remove user from tenant."""
|
|
139
|
+
|
|
140
|
+
if not self.users.filter(user=user).exists():
|
|
141
|
+
logger.warning("User is not a member of this tenant.")
|
|
142
|
+
raise ValueError("User is not a member of this tenant.")
|
|
143
|
+
|
|
144
|
+
self.users.filter(user=user).delete()
|
|
145
|
+
logger.info("User removed from tenant.")
|
|
146
|
+
tenant_user_removed.send(sender=self.__class__, tenant=self, user=user)
|
|
147
|
+
|
|
34
148
|
|
|
35
149
|
class Meta:
|
|
36
150
|
abstract = True
|
|
37
151
|
verbose_name = _('Tenant')
|
|
38
152
|
verbose_name_plural = _('Tenants')
|
|
39
153
|
indexes = [
|
|
40
|
-
models.Index(fields=['
|
|
154
|
+
models.Index(fields=['schema_name']),
|
|
155
|
+
models.Index(fields=['oxi_id']),
|
|
156
|
+
models.Index(fields=['is_deleted']),
|
|
157
|
+
models.Index(fields=['oxi_id', 'is_deleted'])
|
|
41
158
|
]
|
|
42
159
|
|
|
43
160
|
|
|
44
161
|
class BaseTenantUser(BaseModelMixin):
|
|
45
162
|
tenant = models.ForeignKey(
|
|
46
|
-
|
|
163
|
+
settings.TENANT_MODEL,
|
|
164
|
+
on_delete=models.CASCADE,
|
|
165
|
+
related_name='users'
|
|
47
166
|
)
|
|
48
167
|
user = models.ForeignKey(
|
|
49
|
-
settings.AUTH_USER_MODEL,
|
|
168
|
+
settings.AUTH_USER_MODEL,
|
|
169
|
+
on_delete=models.CASCADE,
|
|
170
|
+
related_name='tenants'
|
|
50
171
|
)
|
|
51
172
|
is_owner = models.BooleanField(default=False)
|
|
52
173
|
is_admin = models.BooleanField(default=False)
|
|
@@ -69,13 +190,3 @@ class BaseTenantUser(BaseModelMixin):
|
|
|
69
190
|
indexes = [
|
|
70
191
|
models.Index(fields=['tenant', 'user'])
|
|
71
192
|
]
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class Tenant(BaseTenant):
|
|
75
|
-
class Meta(BaseTenant.Meta):
|
|
76
|
-
abstract = not tenant_model == 'oxiliere.Tenant'
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class TenantUser(BaseTenantUser):
|
|
80
|
-
class Meta(BaseTenantUser.Meta):
|
|
81
|
-
abstract = not tenant_user_model == 'oxiliere.TenantUser'
|
oxutils/oxiliere/permissions.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from ninja_extra.permissions import BasePermission
|
|
2
|
-
from oxutils.oxiliere.
|
|
2
|
+
from oxutils.oxiliere.utils import get_tenant_user_model
|
|
3
3
|
from oxutils.constants import OXILIERE_SERVICE_TOKEN
|
|
4
4
|
from oxutils.jwt.tokens import OxilierServiceToken
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class TenantPermission(BasePermission):
|
|
8
9
|
"""
|
|
9
10
|
Vérifie que l'utilisateur a accès au tenant actuel.
|
|
@@ -17,7 +18,7 @@ class TenantPermission(BasePermission):
|
|
|
17
18
|
return False
|
|
18
19
|
|
|
19
20
|
# Vérifier que l'utilisateur a accès à ce tenant
|
|
20
|
-
return
|
|
21
|
+
return get_tenant_user_model().objects.filter(
|
|
21
22
|
tenant__pk=request.tenant.pk,
|
|
22
23
|
user__pk=request.user.pk
|
|
23
24
|
).exists()
|
|
@@ -34,7 +35,7 @@ class TenantOwnerPermission(BasePermission):
|
|
|
34
35
|
if not hasattr(request, 'tenant'):
|
|
35
36
|
return False
|
|
36
37
|
|
|
37
|
-
return
|
|
38
|
+
return get_tenant_user_model().objects.filter(
|
|
38
39
|
tenant__pk=request.tenant.pk,
|
|
39
40
|
user__pk=request.user.pk,
|
|
40
41
|
is_owner=True
|
|
@@ -52,7 +53,7 @@ class TenantAdminPermission(BasePermission):
|
|
|
52
53
|
if not hasattr(request, 'tenant'):
|
|
53
54
|
return False
|
|
54
55
|
|
|
55
|
-
return
|
|
56
|
+
return get_tenant_user_model().objects.filter(
|
|
56
57
|
tenant__pk=request.tenant.pk,
|
|
57
58
|
user__pk=request.user.pk,
|
|
58
59
|
is_admin=True
|
|
@@ -71,7 +72,7 @@ class TenantUserPermission(BasePermission):
|
|
|
71
72
|
if not hasattr(request, 'tenant'):
|
|
72
73
|
return False
|
|
73
74
|
|
|
74
|
-
return
|
|
75
|
+
return get_tenant_user_model().objects.filter(
|
|
75
76
|
tenant__pk=request.tenant.pk,
|
|
76
77
|
user__pk=request.user.pk
|
|
77
78
|
).exists()
|
oxutils/oxiliere/schemas.py
CHANGED
|
@@ -4,8 +4,10 @@ from ninja import Schema
|
|
|
4
4
|
from django.db import transaction
|
|
5
5
|
from django.contrib.auth import get_user_model
|
|
6
6
|
from django_tenants.utils import get_tenant_model
|
|
7
|
-
from oxutils.oxiliere.
|
|
8
|
-
|
|
7
|
+
from oxutils.oxiliere.utils import (
|
|
8
|
+
get_tenant_user_model,
|
|
9
|
+
)
|
|
10
|
+
from oxutils.oxiliere.authorization import grant_manager_access_to_owners
|
|
9
11
|
import structlog
|
|
10
12
|
|
|
11
13
|
logger = structlog.get_logger(__name__)
|
|
@@ -22,6 +24,8 @@ class TenantSchema(Schema):
|
|
|
22
24
|
|
|
23
25
|
class TenantOwnerSchema(Schema):
|
|
24
26
|
oxi_id: UUID
|
|
27
|
+
first_name: Optional[str] = None
|
|
28
|
+
last_name: Optional[str] = None
|
|
25
29
|
email: str
|
|
26
30
|
|
|
27
31
|
|
|
@@ -34,6 +38,7 @@ class CreateTenantSchema(Schema):
|
|
|
34
38
|
def create_tenant(self):
|
|
35
39
|
UserModel = get_user_model()
|
|
36
40
|
TenantModel = get_tenant_model()
|
|
41
|
+
TenantUserModel = get_tenant_user_model()
|
|
37
42
|
|
|
38
43
|
if TenantModel.objects.filter(oxi_id=self.tenant.oxi_id).exists():
|
|
39
44
|
logger.info("tenant_exists", oxi_id=self.tenant.oxi_id)
|
|
@@ -42,25 +47,29 @@ class CreateTenantSchema(Schema):
|
|
|
42
47
|
user, _ = UserModel.objects.get_or_create(
|
|
43
48
|
oxi_id=self.owner.oxi_id,
|
|
44
49
|
defaults={
|
|
50
|
+
'id': self.owner.oxi_id,
|
|
45
51
|
'email': self.owner.email,
|
|
52
|
+
'first_name': self.owner.first_name,
|
|
53
|
+
'last_name': self.owner.last_name
|
|
46
54
|
}
|
|
47
55
|
)
|
|
48
56
|
|
|
49
57
|
tenant = TenantModel.objects.create(
|
|
50
58
|
name=self.tenant.name,
|
|
51
|
-
schema_name=
|
|
59
|
+
schema_name=self.tenant.oxi_id,
|
|
52
60
|
oxi_id=self.tenant.oxi_id,
|
|
53
61
|
subscription_plan=self.tenant.subscription_plan,
|
|
54
62
|
subscription_status=self.tenant.subscription_status,
|
|
55
63
|
subscription_end_date=self.tenant.subscription_end_date,
|
|
56
64
|
)
|
|
57
65
|
|
|
58
|
-
|
|
66
|
+
TenantUserModel.objects.create(
|
|
59
67
|
tenant=tenant,
|
|
60
68
|
user=user,
|
|
61
69
|
is_owner=True,
|
|
62
70
|
is_admin=True,
|
|
63
71
|
)
|
|
64
72
|
|
|
73
|
+
grant_manager_access_to_owners(tenant)
|
|
65
74
|
logger.info("tenant_created", oxi_id=self.tenant.oxi_id)
|
|
66
75
|
return tenant
|
oxutils/oxiliere/utils.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from typing import Any
|
|
2
|
+
import uuid
|
|
2
3
|
from django.apps import apps
|
|
3
4
|
from django.conf import settings
|
|
5
|
+
from .constants import OXI_SYSTEM_TENANT
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
|
|
@@ -20,6 +22,15 @@ def get_tenant_model() -> Any:
|
|
|
20
22
|
def get_tenant_user_model() -> Any:
|
|
21
23
|
return get_model('TENANT_USER_MODEL')
|
|
22
24
|
|
|
25
|
+
def is_system_tenant(tenant: Any) -> bool:
|
|
26
|
+
return tenant.schema_name == get_system_tenant_schema_name()
|
|
27
|
+
|
|
28
|
+
def get_system_tenant_schema_name():
|
|
29
|
+
system_schema_name = oxid_to_schema_name(
|
|
30
|
+
getattr(settings, 'OXI_SYSTEM_TENANT', OXI_SYSTEM_TENANT)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return system_schema_name
|
|
23
34
|
|
|
24
35
|
def oxid_to_schema_name(oxid: str) -> str:
|
|
25
36
|
"""
|
|
@@ -58,6 +69,13 @@ def oxid_to_schema_name(oxid: str) -> str:
|
|
|
58
69
|
return schema_name
|
|
59
70
|
|
|
60
71
|
|
|
72
|
+
def generate_schema_name(oxi_id: str, suffix: str = None) -> str:
|
|
73
|
+
cleaned = oxid_to_schema_name(oxi_id)
|
|
74
|
+
if suffix:
|
|
75
|
+
return f"{cleaned}_{suffix}"
|
|
76
|
+
return f"{cleaned}_{uuid.uuid4().hex[:8]}"
|
|
77
|
+
|
|
78
|
+
|
|
61
79
|
def update_tenant_user(oxi_org_id: str, oxi_user_id: str, data: dict):
|
|
62
80
|
if not data or isinstance(data, dict) == False: return
|
|
63
81
|
if not oxi_org_id or not oxi_user_id: return
|
|
File without changes
|