Files
centurion_erp/app/access/models/tenancy_abstract.py

248 lines
6.0 KiB
Python

# import django
import logging
from django.core.exceptions import (
ValidationError,
)
from django.db import models
# from rest_framework.reverse import reverse
from access.models.tenant import Tenant
# from core import exceptions as centurion_exceptions
# from core.mixin.history_save import SaveHistory
class TenancyManager(
models.Manager
):
"""Multi-Tennant Object Manager
This manager specifically caters for the multi-tenancy features of Centurion ERP.
"""
def get_queryset(self):
""" Fetch the data
When the model contains the user data, the query is filtered to their
and the globally defined Tenancy only.
Returns:
(queryset): **super user**: return unfiltered data.
(queryset): **not super user**: return data from the stored unique organizations.
"""
# user = None # When CenturionUser in use
# if hasattr(self.model, 'context'):
# user = self.model.context['user']
# if user:
# tencies = user.get_tenancies(int_list = True)
# if len(tenancies) > 0 and not request.user.is_superuser:
# if hasattr(self.model, 'organization'):
# return super().get_queryset().select_related('organization').filter(
# models.Q(organization__in = tenancies)
# )
# return super().get_queryset().select_related('organization').filter(
# models.Q(organization__in = tenancies)
# )
request = None
if hasattr(self.model, 'context'):
request = self.model.context['request']
if request is not None:
tenancies: list(str()) = []
if request.app_settings.global_organization:
tenancies += [ request.app_settings.global_organization.id ]
if request.user.is_authenticated:
for team in request.tenancy._user_teams:
if team.organization.id in tenancies:
continue
tenancies += [ team.organization.id ]
if len(tenancies) > 0 and not request.user.is_superuser:
if hasattr(self.model, 'organization'):
return super().get_queryset().select_related('organization').filter(
models.Q(organization__in = tenancies)
)
return super().get_queryset().select_related('organization').filter(
models.Q(organization__in = tenancies)
)
return super().get_queryset().select_related('organization')
class TenancyObjectOld:
kb_model_name: str = None
"""Model name to use for KB article linking
This value is derived from `<model>._meta.model_name`. This value should
only be used when there is model inheritence.
"""
_log: logging.Logger = None
def get_log(self):
if self._log is None:
self._log = logging.getLogger('centurion.' + self._meta.app_label)
return self._log
page_layout: list = None
note_basename: str = None
"""URL BaseName for the notes endpoint.
Don't specify the `app_namespace`, use property `app_namespace` above.
"""
def get_page_layout(self):
""" FEtch the page layout"""
return self.page_layout
def get_app_namespace(self) -> str:
"""Fetch the Application namespace if specified.
Returns:
str: Application namespace suffixed with colin `:`
None: No application namespace found.
"""
app_namespace = ''
if self.app_namespace:
app_namespace = self.app_namespace + ':'
return str(app_namespace)
def get_url_kwargs_notes(self) -> dict:
"""Fetch the URL kwargs for model notes
Returns:
dict: notes kwargs required for generating the URL with `reverse`
"""
return {
'model_id': self.id
}
class TenancyAbstractModel(
# TenancyObjectOld,
# models.Model,
):
""" Tenancy Model Abstract class.
This class is for inclusion within **every** model within Centurion ERP.
Provides the required fields, functions and methods for multi tennant objects.
Unless otherwise stated, **no** object within this class may be overridden.
Raises:
ValidationError: User failed to supply organization
"""
objects = TenancyManager()
""" Multi-Tenanant Objects """
class Meta:
abstract = True
def validatate_organization_exists(self):
"""Ensure that the user did provide an organization
Raises:
ValidationError: User failed to supply organization.
"""
if not self:
raise ValidationError(
code = 'required',
message = 'You must provide an organization'
)
id = models.AutoField(
blank=False,
help_text = 'ID of the item',
primary_key=True,
unique=True,
verbose_name = 'ID'
)
organization = models.ForeignKey(
Tenant,
blank = False,
help_text = 'Tenant this belongs to',
null = False,
on_delete = models.CASCADE,
related_name = '+',
validators = [
validatate_organization_exists
],
verbose_name = 'Tenant'
)
is_global = models.BooleanField(
blank = False,
default = False,
help_text = 'Is this a global object?',
null = False,
verbose_name = 'Global Object'
)
model_notes = models.TextField(
blank = True,
default = None, # ToDo: Remove this field
help_text = 'Tid bits of information',
null = True,
verbose_name = 'Notes',
)
def get_tenant(self) -> Tenant:
""" Return the models Tenancy
This model can be safely over-ridden as long as it returns the models
tenancy
"""
return self.organization