Compare commits

..

2 Commits

Author SHA1 Message Date
4fb94bdd6d build: bump version 1.17.0 -> 1.17.1 2025-06-02 00:05:20 +00:00
Jon
e2582373ad fix(base): Add python metrics to prometheus exporter
ref: #436
2025-06-02 08:25:37 +09:30
503 changed files with 1235 additions and 2295 deletions

View File

@ -17,5 +17,5 @@ commitizen:
prerelease_offset: 1
tag_format: $version
update_changelog_on_bump: false
version: 1.17.0
version: 1.17.1
version_scheme: semver

View File

@ -1,3 +1,9 @@
## 1.17.1 (2025-06-02)
### Fixes
- **base**: Add python metrics to prometheus exporter
## 1.17.0 (2025-05-16)
### feat

View File

@ -1,5 +1,6 @@
from django.db import models
from django.utils.timezone import now
from django.template.defaultfilters import slugify
class AutoCreatedField(models.DateTimeField):
"""

View File

@ -1,7 +1,7 @@
from django import forms
from django.db.models import Q
from django.conf import settings
from app import settings
from access.models.tenant import Tenant as Organization

View File

@ -7,7 +7,7 @@ from .team_users import TeamUsersForm, TeamUsers
from access.models.team import Team
from access.functions import permissions
from django.conf import settings
from app import settings
from core.forms.common import CommonModelForm

View File

@ -1,6 +1,6 @@
from django.db.models import Q
from django.conf import settings
from app import settings
from access.models.team_user import TeamUsers

View File

@ -1,5 +1,10 @@
import django
from django.contrib.auth.middleware import (
AuthenticationMiddleware,
SimpleLazyObject,
partial,
)
from django.contrib.auth.models import Group
from django.utils.deprecation import MiddlewareMixin

View File

@ -1,30 +0,0 @@
# Generated by Django 5.1.9 on 2025-05-17 17:50
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('access', '0010_company_alter_entity_entity_type_alter_person_dob_and_more'),
('core', '0026_rename_manufacturerhistory_manufactureraudithistory'),
]
operations = [
migrations.RenameModel(
old_name='EntityHistory',
new_name='EntityAuditHistory',
),
migrations.RenameModel(
old_name='OrganizationHistory',
new_name='OrganizationAuditHistory',
),
migrations.RenameModel(
old_name='RoleHistory',
new_name='RoleAuditHistory',
),
migrations.RenameModel(
old_name='TeamHistory',
new_name='TeamAuditHistory',
),
]

View File

@ -1,5 +1,5 @@
from django.contrib.auth.mixins import AccessMixin
from django.contrib.auth.mixins import AccessMixin, PermissionRequiredMixin
from django.contrib.auth.models import Group
from django.core.exceptions import PermissionDenied
from django.utils.functional import cached_property

View File

@ -1,8 +1,10 @@
import django
from django.contrib.auth.models import Group
from django.db import models
from access.models.tenant import Tenant as Organization
from access.models.team import Team
User = django.contrib.auth.get_user_model()

View File

@ -1,5 +1,8 @@
import traceback
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import exceptions
from rest_framework.permissions import DjangoObjectPermissions
from access.models.tenancy import Tenant, TenancyObject

View File

@ -1,4 +1,4 @@
from . import contact # pylint: disable=W0611:unused-import
from . import company_base # pylint: disable=W0611:unused-import
from . import person # pylint: disable=W0611:unused-import
from . import role # pylint: disable=W0611:unused-import
from . import contact
from . import company_base
from . import person
from . import role

View File

@ -5,6 +5,8 @@ from rest_framework.reverse import reverse
from access.fields import AutoCreatedField, AutoLastModifiedField
from access.models.tenancy import TenancyObject
from core.lib.feature_not_used import FeatureNotUsed
class Entity(
@ -105,6 +107,7 @@ class Entity(
):
return related_object.name
break
return ''
@ -235,12 +238,12 @@ class Entity(
def save_history(self, before: dict, after: dict) -> bool:
from access.models.entity_history import EntityAuditHistory
from access.models.entity_history import EntityHistory
history = super().save_history(
before = before,
after = after,
history_model = EntityAuditHistory
history_model = EntityHistory
)
return history

View File

@ -4,9 +4,11 @@ from access.models.entity import Entity
from core.models.model_history import ModelHistory
from devops.models.feature_flag import FeatureFlag
class EntityAuditHistory(
class EntityHistory(
ModelHistory
):

View File

@ -1 +1 @@
from .tenant import Tenant as Organization # pylint: disable=W0611:unused-import
from .tenant import Tenant as Organization

View File

@ -6,7 +6,7 @@ from access.models.tenant import Tenant
class OrganizationAuditHistory(
class OrganizationHistory(
ModelHistory
):

View File

@ -130,45 +130,14 @@ class Role(
]
_permissions: list[ Permission ] = None
_permissions_int: list[ int ] = None
def get_permissions(self, as_int_list = False ):
if self._permissions is None:
permissions = []
permissions_int = []
for permission in self.permissions:
if permission in _permissions:
continue
permissions += [ permission ]
permissions_int += [ permission.id ]
self._permissions = permissions
self._permissions_int = permissions_int
if as_int_list:
return self._permissions_int
return self._permissions_int
def save_history(self, before: dict, after: dict) -> bool:
from access.models.role_history import RoleAuditHistory
from access.models.role_history import RoleHistory
history = super().save_history(
before = before,
after = after,
history_model = RoleAuditHistory
history_model = RoleHistory
)
return history

View File

@ -6,7 +6,7 @@ from access.models.role import Role
class RoleAuditHistory(
class RoleHistory(
ModelHistory
):

View File

@ -179,12 +179,12 @@ class Team(Group, TenancyObject):
def save_history(self, before: dict, after: dict) -> bool:
from access.models.team_history import TeamAuditHistory
from access.models.team_history import TeamHistory
history = super().save_history(
before = before,
after = after,
history_model = TeamAuditHistory
history_model = TeamHistory
)

View File

@ -6,7 +6,7 @@ from access.models.team import Team
class TeamAuditHistory(
class TeamHistory(
ModelHistory
):

View File

@ -1,3 +1,4 @@
import django
import logging
from django.db import models
@ -51,10 +52,6 @@ class TenancyManager(models.Manager):
user_organizations: list(str()) = []
has_tenant_field = False
if hasattr(self.model, 'organization'):
has_tenant_field = True
if request:
@ -73,53 +70,31 @@ class TenancyManager(models.Manager):
if team.organization.id not in user_organizations:
# if not user_organizations:
if not user_organizations:
# self.user_organizations = []
self.user_organizations = []
user_organizations += [ team.organization.id ]
# if len(user_organizations) > 0 and not user.is_superuser and self.model.is_global is not None:
if len(user_organizations) > 0 and not user.is_superuser:
if getattr(self.model, 'is_global', False) is True:
if has_tenant_field:
return super().get_queryset().select_related('organization').filter(
models.Q(organization__in=user_organizations)
|
models.Q(is_global = True)
)
else:
return super().get_queryset().filter(
models.Q(organization__in=user_organizations)
|
models.Q(is_global = True)
)
return super().get_queryset().filter(
models.Q(organization__in=user_organizations)
|
models.Q(is_global = True)
)
else:
if has_tenant_field:
return super().get_queryset().filter(
models.Q(organization__in=user_organizations)
)
return super().get_queryset().select_related('organization').filter(
models.Q(organization__in=user_organizations)
)
else:
return super().get_queryset().filter(
models.Q(organization__in=user_organizations)
)
if has_tenant_field:
return super().get_queryset().select_related('organization')
else:
return super().get_queryset().select_related('organization')
return super().get_queryset()
@ -311,7 +286,7 @@ class TenancyObject(SaveHistory):
if(
not getattr(self, 'organization', None)
and self._meta.model_name !='appsettingsaudithistory' # App Settings for
and self._meta.model_name !='appsettingshistory' # App Settings for
):
raise centurion_exceptions.ValidationError(

View File

@ -1,247 +0,0 @@
# 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

View File

@ -145,12 +145,12 @@ class Tenant(SaveHistory):
def save_history(self, before: dict, after: dict) -> bool:
from access.models.organization_history import OrganizationAuditHistory
from access.models.organization_history import OrganizationHistory
history = super().save_history(
before = before,
after = after,
history_model = OrganizationAuditHistory
history_model = OrganizationHistory
)

View File

@ -1,195 +0,0 @@
from django.contrib.auth.models import Permission, User
from django.core.exceptions import PermissionDenied
from access.models.tenant import Tenant
class CenturionUser(
User,
):
"""Centurion User
A Multi-Tenant User wirh permission Checking.
ToDo:
- Add to Roles user field `related_name = roles`
- Add to Roles group field `related_name = roles`
# - have group lookup prefetch related roles__permissions
- have user lookup prefetch related roles__permissions and groups__roles__permissions
Args:
User (Model): Django Base User
"""
_tenancies: list[Tenant] = None
_tenancies_int: list[int] = None
_permissions: list[Permission] = None
_permissions_by_tenancy: dict[ str, list[ Permission ] ] = None
"""Permissions by Tenancy
`{ 'tenancy_{id}': [ Permission ] }`
"""
# EMAIL_FIELD = 'email' # Update contact email field name so it's different to the user model.
# REQUIRED_FIELDS = [
# EMAIL_FIELD,
# 'f_name',
# 'l_name',
# ]
class Meta:
abstract = False
proxy = True # User will be linked to Employee/Customer entity via related_name from the entity.
# ToDo: refactory Employee/Customer to inherit from a new model. entity_user
verbose_name = 'Centurion User'
verbose_name_plural = 'Centurion Users'
def get_full_name(self) -> str:
return f'{self.entity_user.f_name} {self.entity_user.l_name}'
def get_group_permissions(self, tenancy: bool = True) -> dict[ str, list[ Permission ] ] | list[ Permission ]:
""" Get the Users Permissions
Args:
tenancy (bool, optional): Return permission in list. Defaults to True.
Returns:
dict[ str, list[ Permission ] ]: Permissions listed by tenancy
list[ Permission ]: All Permissions
"""
for group in self.groups:
for role in group.roles:
pass
# role.get_permissions()
def get_permissions(self, tenancy: bool = True) -> dict[ str, list[ Permission ] ] | list[ Permission ]:
""" Get the Users Permissions
Args:
tenancy (bool, optional): Return permission in list. Defaults to True.
Returns:
dict[ str, list[ Permission ] ]: Permissions listed by tenancy
list[ Permission ]: All Permissions
"""
# also get group permissions. self.get_group_permissions()
for role in self.roles:
pass
# role.get_permissions()
# also populate `self._tenancies` and `self._tenancies_int`
def get_short_name() -> str:
return self.entity_user.f_name
def get_tenancies(self, int_list = False) -> list[ Tenant ] | list[ int ]:
"""Get the Tenancies the user is in.
Args:
int_list (bool, optional): Return Tenancy list as int values. Defaults to False.
Returns:
list[ Tenant ] | list[ int ]: All Tenancies the user is in.
"""
if self._tenancies is None:
if self._permissions is None:
self.get_permissions
tenancies: list = []
tenancies_int: list = []
for role in self.roles:
if role.organization in tenancies:
continue
tenancies += [ role.organization ]
tenancies_int += [ role.organization.id ]
self._tenancies = tenancies
self._tenancies_int = tenancies_int
if as_int_list:
return self._tenancies_int
return self._tenancies
def has_module_perms(self, app_label): # is this needed?
# if has app_label in perms
raise PermissionDenied
def has_perm(self, permission: Permission, obj = None, tenancy: Tenant = None) -> bool:
if(
obj is None
and tenancy is None
):
raise ValueError('Both obj and tenancy cant be None')
if tenancy is None:
tenancy = obj.organization
# if self.has_tenancy_permission(perm, tenancy):
# for tenancy, permissions in self.get_permissions().items()
if tenancy is None:
raise ValueError('tenancy cant be None')
permissions = self.get_permissions()
if f'tenancy_{tenancy.id}' not in permissions:
raise PermissionDenied
for tenancy, permissions in self.get_permissions().items():
if(
tenancy == f'tenancy_{tenancy.id}'
and perm in permissions
):
return True
raise PermissionDenied
def has_perms(self, permission_list: list[ Permission ], obj = None, tenancy: Tenant = None):
for perm in perm_list:
self.has_perm( perm, obj )
return True

View File

@ -4,7 +4,7 @@ from rest_framework import serializers
from access.models.tenant import Tenant
from centurion.serializers.user import UserBaseSerializer
from app.serializers.user import UserBaseSerializer
from core import fields as centurion_field

View File

@ -1,6 +1,13 @@
from rest_framework import serializers
from access.models.organization_notes import OrganizationNotes
from api.serializers import common
from app.serializers.user import UserBaseSerializer
from core.serializers.model_notes import (
ModelNotes,
ModelNoteBaseSerializer,
ModelNoteModelSerializer,
ModelNoteViewSerializer

View File

@ -9,7 +9,7 @@ from access.serializers.organization import TenantBaseSerializer
from api.serializers import common
from centurion.serializers.permission import PermissionBaseSerializer
from app.serializers.permission import PermissionBaseSerializer

View File

@ -1,6 +1,13 @@
from rest_framework import serializers
from access.models.role_notes import RoleNotes
from api.serializers import common
from app.serializers.user import UserBaseSerializer
from core.serializers.model_notes import (
ModelNotes,
ModelNoteBaseSerializer,
ModelNoteModelSerializer,
ModelNoteViewSerializer

View File

@ -1,6 +1,13 @@
from rest_framework import serializers
from access.models.team_notes import TeamNotes
from api.serializers import common
from app.serializers.user import UserBaseSerializer
from core.serializers.model_notes import (
ModelNotes,
ModelNoteBaseSerializer,
ModelNoteModelSerializer,
ModelNoteViewSerializer

View File

@ -1,10 +1,12 @@
from rest_framework.reverse import reverse
from rest_framework import serializers
from access.models.team_user import TeamUsers
from api.serializers import common
from centurion.serializers.user import UserBaseSerializer
from app.serializers.user import UserBaseSerializer

View File

@ -9,7 +9,7 @@ from api.serializers import common
from access.functions.permissions import permission_queryset
from access.serializers.organization import TenantBaseSerializer
from centurion.serializers.permission import PermissionBaseSerializer
from app.serializers.permission import Permission, PermissionBaseSerializer
from core import fields as centurion_field

View File

@ -1,6 +1,6 @@
from django.test import TestCase
from access.models.entity_history import Entity, EntityAuditHistory
from access.models.entity_history import Entity, EntityHistory
from core.tests.abstract.test_functional_history import HistoryEntriesCommon
@ -12,7 +12,7 @@ class HistoryTestCases(
field_name = 'model_notes'
history_model = EntityAuditHistory
history_model = EntityHistory
kwargs_create_obj: dict = {}
@ -43,7 +43,7 @@ class HistoryTestCases(
class EntityAuditHistoryInheritedCases(
class EntityHistoryInheritedCases(
HistoryTestCases,
):
@ -70,7 +70,7 @@ class EntityAuditHistoryInheritedCases(
class EntityAuditHistoryTest(
class EntityHistoryTest(
HistoryTestCases,
TestCase,
):

View File

@ -1,6 +1,6 @@
from django.test import TestCase
from access.models.organization_history import Tenant as Organization, OrganizationAuditHistory
from access.models.organization_history import Tenant as Organization, OrganizationHistory
from core.tests.abstract.test_functional_history import HistoryEntriesCommon
@ -13,7 +13,7 @@ class History(
model = Organization
history_model = OrganizationAuditHistory
history_model = OrganizationHistory
@classmethod

View File

@ -2,13 +2,13 @@ from django.test import TestCase
from access.models.person import Person
from access.tests.functional.entity.test_functional_entity_history import (
EntityAuditHistoryInheritedCases
EntityHistoryInheritedCases
)
class PersonTestCases(
EntityAuditHistoryInheritedCases,
EntityHistoryInheritedCases,
):
field_name = 'model_notes'

View File

@ -1,6 +1,6 @@
from django.test import TestCase
from access.models.role_history import Role, RoleAuditHistory
from access.models.role_history import Role, RoleHistory
from core.tests.abstract.test_functional_history import HistoryEntriesCommon
@ -10,7 +10,7 @@ class HistoryTestCases(
HistoryEntriesCommon,
):
history_model = RoleAuditHistory
history_model = RoleHistory
kwargs_create_obj: dict = {}
@ -41,7 +41,7 @@ class HistoryTestCases(
class RoleAuditHistoryTest(
class RoleHistoryTest(
HistoryTestCases,
TestCase,
):

View File

@ -1,6 +1,6 @@
from django.test import TestCase
from access.models.team_history import Team, TeamAuditHistory
from access.models.team_history import Team, TeamHistory
from core.tests.abstract.test_functional_history import HistoryEntriesCommon
@ -13,7 +13,7 @@ class History(
model = Team
history_model = TeamAuditHistory
history_model = TeamHistory
@classmethod

View File

@ -1,7 +1,7 @@
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from access.models.entity_history import Entity, EntityAuditHistory
from access.models.entity_history import Entity, EntityHistory
from core.tests.abstract.test_unit_model_history_api_v2 import PrimaryModelHistoryAPI
@ -20,7 +20,7 @@ class ModelHistoryAPITestCases(
kwargs_create_audit_object: dict = {}
model = EntityAuditHistory
model = EntityHistory
@classmethod
def setUpTestData(self):

View File

@ -4,7 +4,7 @@ from django.db import models
from access.models.entity import Entity
from centurion.tests.unit.test_unit_models import (
from app.tests.unit.test_unit_models import (
PyTestTenancyObjectInheritedCases,
)

View File

@ -15,7 +15,7 @@ from access.models.team import Team
from access.models.team_user import TeamUsers
from access.tests.abstract.model_permissions_organization_manager import OrganizationManagerModelPermissionChange, OrganizationManagerModelPermissionView
from centurion.tests.abstract.model_permissions import ModelPermissionsView, ModelPermissionsChange
from app.tests.abstract.model_permissions import ModelPermissionsView, ModelPermissionsChange
User = django.contrib.auth.get_user_model()

View File

@ -4,7 +4,7 @@ import requests
from django.test import TestCase
from centurion.tests.abstract.models import ModelDisplay, ModelIndex
from app.tests.abstract.models import ModelDisplay, ModelIndex

View File

@ -3,7 +3,7 @@ from django.test import TestCase
from core.tests.abstract.test_unit_model_history_api_v2 import PrimaryModelHistoryAPI
from access.models.organization_history import Tenant as Organization, OrganizationAuditHistory
from access.models.organization_history import Tenant as Organization, OrganizationHistory
@ -14,7 +14,7 @@ class ModelHistoryAPI(
audit_model = Organization
model = OrganizationAuditHistory
model = OrganizationHistory
@classmethod
def setUpTestData(self):

View File

@ -1,7 +1,7 @@
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from access.models.role_history import Role, RoleAuditHistory
from access.models.role_history import Role, RoleHistory
from core.tests.abstract.test_unit_model_history_api_v2 import PrimaryModelHistoryAPI
@ -51,7 +51,7 @@ class ModelHistoryAPITestCases(
class RoleAuditHistoryAPITest(
class RoleHistoryAPITest(
ModelHistoryAPITestCases,
TestCase,
):
@ -60,7 +60,7 @@ class RoleAuditHistoryAPITest(
kwargs_create_audit_object: dict = {}
model = RoleAuditHistory
model = RoleHistory
@classmethod
def setUpTestData(self):

View File

@ -2,7 +2,7 @@ from django.test import TestCase
from access.models.role import Role
from centurion.tests.unit.test_unit_models import (
from app.tests.unit.test_unit_models import (
TenancyObjectInheritedCases
)

View File

@ -14,7 +14,7 @@ from access.models.team import Team
from access.models.team_user import TeamUsers
from access.tests.abstract.model_permissions_organization_manager import OrganizationManagerModelPermissions
from centurion.tests.abstract.model_permissions import ModelPermissions
from app.tests.abstract.model_permissions import ModelPermissions
User = django.contrib.auth.get_user_model()

View File

@ -4,7 +4,7 @@ import requests
from django.test import TestCase
from centurion.tests.abstract.models import ModelAdd, ModelDelete, ModelDisplay
from app.tests.abstract.models import ModelAdd, ModelDelete, ModelDisplay

View File

@ -3,7 +3,7 @@ from django.test import TestCase
from core.tests.abstract.test_unit_model_history_api_v2 import PrimaryModelHistoryAPI
from access.models.team_history import Team, TeamAuditHistory
from access.models.team_history import Team, TeamHistory
@ -14,7 +14,7 @@ class ModelHistoryAPI(
audit_model = Team
model = TeamAuditHistory
model = TeamHistory
@classmethod
def setUpTestData(self):

View File

@ -4,7 +4,7 @@ from django.test import TestCase
from access.models.team import Team
from centurion.tests.unit.test_unit_models import (
from app.tests.unit.test_unit_models import (
TenancyObjectInheritedCases
)

View File

@ -15,7 +15,7 @@ from access.models.team_user import TeamUsers
from access.tests.abstract.model_permissions_organization_manager import OrganizationManagerModelPermissionAdd, OrganizationManagerModelPermissionDelete
from centurion.tests.abstract.model_permissions import ModelPermissionsAdd, ModelPermissionsChange, ModelPermissionsDelete
from app.tests.abstract.model_permissions import ModelPermissionsAdd, ModelPermissionsChange, ModelPermissionsDelete
User = django.contrib.auth.get_user_model()

View File

@ -4,7 +4,7 @@ import requests
from django.test import TestCase
from centurion.tests.abstract.models import AddView, DeleteView
from app.tests.abstract.models import AddView, DeleteView

View File

@ -5,7 +5,7 @@ from access.models.tenant import Tenant as Organization
from access.models.team import Team
from access.models.team_user import TeamUsers
from centurion.tests.unit.test_unit_models import NonTenancyObjectInheritedCases
from app.tests.unit.test_unit_models import NonTenancyObjectInheritedCases
User = django.contrib.auth.get_user_model()

View File

@ -617,7 +617,7 @@ class TenancyObjectInheritedCases(
"""Test Cases for models that inherit from
**Note:** dont use these test cases use
`centurion.tests.unit.test_unit_models.TenancyObjectInheritedCases` instead
`app.tests.unit.test_unit_models.TenancyObjectInheritedCases` instead
access.models.tenancy.TenancyObject"""

View File

@ -1,5 +1,6 @@
from django.urls import path
from . import views
from .views import team, organization, user
app_name = "Access"

View File

@ -13,7 +13,7 @@ from drf_spectacular.utils import (
from rest_framework.reverse import reverse
# THis import only exists so that the migrations can be created
from access.models.entity_history import EntityAuditHistory # pylint: disable=W0611:unused-import
from access.models.entity_history import EntityHistory # pylint: disable=W0611:unused-import
from access.models.entity import (
Entity,
)

View File

@ -1,8 +1,8 @@
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse
# THis import only exists so that the migrations can be created
from access.models.organization_history import OrganizationAuditHistory # pylint: disable=W0611:unused-import
from access.serializers.organization import ( # pylint: disable=W0611:unused-import
from access.models.organization_history import OrganizationHistory # pylint: disable=W0611:unused-import
from access.serializers.organization import (
Tenant,
TenantModelSerializer,
TenantViewSerializer

View File

@ -1,7 +1,7 @@
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse
# THis import only exists so that the migrations can be created
from access.models.role_history import RoleAuditHistory # pylint: disable=W0611:unused-import
from access.models.role_history import RoleHistory # pylint: disable=W0611:unused-import
from access.serializers.role import (
Role,
ModelSerializer,

View File

@ -2,8 +2,8 @@ from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiPara
from access.models.tenant import Tenant as Organization
# THis import only exists so that the migrations can be created
from access.models.team_history import TeamAuditHistory # pylint: disable=W0611:unused-import
from access.serializers.teams import ( # pylint: disable=W0611:unused-import
from access.models.team_history import TeamHistory # pylint: disable=W0611:unused-import
from access.serializers.teams import (
Team,
TeamModelSerializer,
TeamViewSerializer

View File

@ -2,7 +2,7 @@ from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiPara
from access.models.team import Team
from access.serializers.team_user import ( # pylint: disable=W0611:unused-import
from access.serializers.team_user import (
TeamUsers,
TeamUserModelSerializer,
TeamUserViewSerializer

View File

@ -1,18 +0,0 @@
# Generated by Django 5.1.9 on 2025-05-17 13:24
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounting', '0001_initial'),
('core', '0025_alter_modelhistory_action_alter_modelhistory_after_and_more'),
]
operations = [
migrations.RenameModel(
old_name='AssetBaseHistory',
new_name='AssetBaseAuditHistory',
),
]

View File

@ -1 +1 @@
from .asset_base_history import AssetBaseAuditHistory # pylint: disable=W0611:unused-import
from .asset_base_history import AssetBaseHistory

View File

@ -6,6 +6,8 @@ from rest_framework.reverse import reverse
from access.fields import AutoCreatedField, AutoLastModifiedField
from access.models.tenancy import TenancyObject
from core.lib.feature_not_used import FeatureNotUsed
class AssetBase(
@ -255,6 +257,7 @@ class AssetBase(
):
return related_object.name
break
return ''
@ -353,12 +356,12 @@ class AssetBase(
def save_history(self, before: dict, after: dict) -> bool:
from accounting.models.asset_base_history import AssetBaseAuditHistory
from accounting.models.asset_base_history import AssetBaseHistory
history = super().save_history(
before = before,
after = after,
history_model = AssetBaseAuditHistory
history_model = AssetBaseHistory
)

View File

@ -6,7 +6,7 @@ from core.models.model_history import ModelHistory
class AssetBaseAuditHistory(
class AssetBaseHistory(
ModelHistory
):

View File

@ -1,6 +1,6 @@
from django.test import TestCase
from accounting.models.asset_base_history import AssetBase, AssetBaseAuditHistory
from accounting.models.asset_base_history import AssetBase, AssetBaseHistory
from core.tests.abstract.test_functional_history import HistoryEntriesCommon
@ -13,7 +13,7 @@ class History(
model = AssetBase
history_model = AssetBaseAuditHistory
history_model = AssetBaseHistory
@classmethod

View File

@ -4,7 +4,7 @@ from django.db import models
from accounting.models.asset_base import AssetBase
from centurion.tests.unit.test_unit_models import (
from app.tests.unit.test_unit_models import (
PyTestTenancyObjectInheritedCases,
)

View File

@ -3,7 +3,7 @@ from django import forms
from api.models.tokens import AuthToken
from django.conf import settings
from app import settings
from core.forms.common import CommonModelForm

View File

@ -1 +1 @@
from . import tokens # pylint: disable=W0611:unused-import
from . import tokens

View File

@ -35,7 +35,7 @@ class AuthToken(models.Model):
def validate_note_no_token(self, note, token, raise_exception = True) -> bool:
""" Ensure plaintext token cant be saved to notes field.
called from centurion.settings.views.user_settings.TokenAdd.form_valid()
called from app.settings.views.user_settings.TokenAdd.form_valid()
Args:
note (Field): _Note field_

View File

@ -3,8 +3,11 @@ import re
from django.conf import settings
from django.utils.encoding import force_str
from django.contrib.auth.models import ContentType, Permission
from rest_framework import serializers
from rest_framework_json_api.metadata import JSONAPIMetadata
from rest_framework.request import clone_request
from rest_framework.reverse import reverse
from rest_framework.utils.field_mapping import ClassLookupDict
@ -12,7 +15,7 @@ from rest_framework_json_api.utils import get_related_resource_type
from access.models.tenant import Tenant
from centurion.serializers.user import User, UserBaseSerializer
from app.serializers.user import User, UserBaseSerializer
from core import fields as centurion_field
from core.fields.badge import BadgeField

View File

@ -1,4 +1,4 @@
from rest_framework import serializers
from rest_framework import serializers, request
from rest_framework.reverse import reverse
from access.models.tenant import Tenant as Organization

View File

@ -4,6 +4,8 @@ from rest_framework.reverse import reverse
from access.serializers.organization import Tenant
from assistance.models.model_knowledge_base_article import all_models
from core import fields as centurion_field
from core.lib.feature_not_used import FeatureNotUsed
@ -63,7 +65,7 @@ class CommonModelSerializer(CommonBaseSerializer):
}
kb_model_name = self.Meta.model._meta.model_name
if getattr(item, 'kb_model_name', None):
if getattr(item, 'kb_model_name'):
kb_model_name = item.kb_model_name
@ -80,31 +82,26 @@ class CommonModelSerializer(CommonBaseSerializer):
if getattr(self.Meta.model, 'save_model_history', True):
history_app_label = self.Meta.model._meta.app_label
if getattr(item, 'history_app_label', None):
if getattr(item, 'history_app_label'):
history_app_label = item.history_app_label
history_model_name = self.Meta.model._meta.model_name
if getattr(item, 'history_model_name', None):
if getattr(item, 'history_model_name'):
history_model_name = item.history_model_name
if(
history_app_label is not None
and history_model_name is not None
):
get_url['history'] = reverse(
"v2:_api_v2_model_history-list",
request = self._context['view'].request,
kwargs = {
'app_label': history_app_label,
'model_name': history_model_name,
'model_id': item.pk
}
)
get_url['history'] = reverse(
"v2:_api_v2_model_history-list",
request = self._context['view'].request,
kwargs = {
'app_label': history_app_label,
'model_name': history_model_name,
'model_id': item.pk
}
)
obj = getattr(item, 'get_url_kwargs_notes', None)
@ -126,7 +123,7 @@ class CommonModelSerializer(CommonBaseSerializer):
note_basename = app_namespace + '_api_v2_' + str(item._meta.verbose_name).lower().replace(' ', '_') + '_note'
if getattr(item, 'note_basename', None):
if getattr(item, 'note_basename'):
note_basename = app_namespace + item.note_basename
@ -134,12 +131,10 @@ class CommonModelSerializer(CommonBaseSerializer):
note_basename = self.Meta.note_basename
if getattr(item, 'get_url_kwargs_notes', None):
get_url['notes'] = reverse(
"v2:" + note_basename + "-list",
request = self._context['view'].request,
kwargs = item.get_url_kwargs_notes()
)
get_url['notes'] = reverse(
"v2:" + note_basename + "-list",
request = self._context['view'].request,
kwargs = item.get_url_kwargs_notes()
)
return get_url

View File

@ -3,6 +3,8 @@ from django.urls import reverse
from rest_framework import serializers
from rest_framework.fields import empty
from api.serializers.core.ticket_comment import TicketCommentSerializer
from core import exceptions as centurion_exception
from core.forms.validate_ticket import TicketValidation
from core.models.ticket.ticket import Ticket

View File

@ -1,6 +1,11 @@
from django.urls import reverse
from rest_framework import serializers
from rest_framework.fields import empty
from api.serializers.core.ticket_comment import TicketCommentSerializer
from core.forms.validate_ticket import TicketValidation
from core.models.ticket.ticket_category import TicketCategory

View File

@ -1,3 +1,5 @@
from django.urls import reverse
from rest_framework import serializers
from rest_framework.fields import empty

View File

@ -2,6 +2,8 @@ from django.urls import reverse
from rest_framework import serializers
from api.serializers.config import ParentGroupSerializer
from config_management.models.groups import ConfigGroups
from itam.models.device import Device

View File

@ -1,3 +1,6 @@
from django.urls import reverse
from itam.models.device import Device
from rest_framework import serializers

View File

@ -1,3 +1,5 @@
from django.urls import reverse
from rest_framework import serializers
from rest_framework.fields import empty

View File

@ -1,3 +1,5 @@
from django.urls import reverse
from rest_framework import serializers
from rest_framework.fields import empty

View File

@ -1,6 +1,7 @@
from django.urls import reverse
from rest_framework import serializers
from rest_framework.fields import empty
from project_management.models.projects import Project

View File

@ -8,7 +8,7 @@ from access.models.tenant import Tenant as Organization
from api.serializers.auth_token import AuthToken, AuthTokenModelSerializer
from centurion.tests.abstract.mock_view import MockView, User
from app.tests.abstract.mock_view import MockView, User
# from core.serializers.manufacturer import Manufacturer, ManufacturerModelSerializer

View File

@ -11,7 +11,7 @@ from rest_framework.relations import Hyperlink
from access.models.team import Team
from access.models.team_user import TeamUsers
from centurion.tests.common import DoesNotExist
from app.tests.common import DoesNotExist
User = django.contrib.auth.get_user_model()

View File

@ -10,7 +10,7 @@ from api.viewsets import (
index as v2
)
from centurion.viewsets.base import (
from app.viewsets.base import (
index as base_index_v2,
content_type as content_type_v2,
permisson as permission_v2,

View File

@ -12,6 +12,7 @@ from rest_framework.response import Response
from access.mixins.organization import OrganizationMixin
from access.mixins.permissions import OrganizationPermissionMixin
from api.auth import TokenScheme
from api.react_ui_metadata import ReactUIMetadata

View File

@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'centurion.settings')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings')
application = get_asgi_application()

79
app/app/celery.py Normal file
View File

@ -0,0 +1,79 @@
import logging
import os
from django.conf import settings
from celery import Celery, signals
from celery.fixups.django import DjangoFixup
from pathlib import Path
from prometheus_client import CollectorRegistry, multiprocess, start_http_server
logger = logging.getLogger(__name__)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'app.settings')
worker = Celery('app')
worker.config_from_object(f'django.conf:settings', namespace='CELERY')
worker.autodiscover_tasks()
@worker.task(bind=True, ignore_result=True)
def debug_task(self):
print(f'Request: {self!r}')
@signals.worker_ready.connect()
def setup_prometheus(**kwargs):
if not getattr(settings, 'METRICS_ENABLED', False):
return
proc_path = None
try:
proc_path = os.environ["PROMETHEUS_MULTIPROC_DIR"]
except:
pass
if not proc_path:
os.environ["PROMETHEUS_MULTIPROC_DIR"] = settings.METRICS_MULTIPROC_DIR
proc_path = os.environ["PROMETHEUS_MULTIPROC_DIR"]
logger.info(f'Setting up prometheus metrics HTTP server on port {str(settings.METRICS_EXPORT_PORT)}.')
multiproc_folder_path = _setup_multiproc_folder()
registry = CollectorRegistry()
logger.info(f'Setting up prometheus metrics directory.')
multiprocess.MultiProcessCollector(registry, path=multiproc_folder_path)
logger.info(f'Starting prometheus metrics server.')
start_http_server( settings.METRICS_EXPORT_PORT, registry=registry)
logger.info(f'Starting prometheus serving on port {str(settings.METRICS_EXPORT_PORT)}.')
def _setup_multiproc_folder():
coordination_dir = Path(os.environ["PROMETHEUS_MULTIPROC_DIR"])
coordination_dir.mkdir(parents=True, exist_ok=True)
for filepath in coordination_dir.glob("*.db"):
filepath.unlink()
return coordination_dir

View File

@ -1,6 +1,6 @@
import re
from centurion.urls import urlpatterns
from app.urls import urlpatterns
from django.conf import settings
from django.urls import URLPattern, URLResolver

View File

@ -3,7 +3,7 @@ from django.contrib.auth.models import Permission
from rest_framework import serializers
from rest_framework.reverse import reverse
from centurion.serializers.content_type import ContentTypeBaseSerializer
from app.serializers.content_type import ContentTypeBaseSerializer
class PermissionBaseSerializer(serializers.ModelSerializer):

View File

@ -253,12 +253,12 @@ MIDDLEWARE = [
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'core.middleware.get_request.RequestMiddleware',
'centurion.middleware.timezone.TimezoneMiddleware',
'app.middleware.timezone.TimezoneMiddleware',
'centurion_feature_flag.middleware.feature_flag.FeatureFlagMiddleware',
]
ROOT_URLCONF = 'centurion.urls'
ROOT_URLCONF = 'app.urls'
TEMPLATES = [
{
@ -273,13 +273,13 @@ TEMPLATES = [
'django.contrib.messages.context_processors.messages',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
'centurion.context_processors.base.common',
'app.context_processors.base.common',
],
},
},
]
WSGI_APPLICATION = 'centurion.wsgi.application'
WSGI_APPLICATION = 'app.wsgi.application'
# Database

View File

@ -1,4 +1,4 @@
from centurion.tests.abstract.views import AddView, ChangeView, DeleteView, DisplayView, IndexView
from app.tests.abstract.views import AddView, ChangeView, DeleteView, DisplayView, IndexView

Some files were not shown because too many files have changed in this diff Show More