16
app/core/migrations/0028_delete_history.py
Normal file
16
app/core/migrations/0028_delete_history.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-05 06:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0027_centurionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="History",
|
||||
),
|
||||
]
|
@ -1,132 +0,0 @@
|
||||
import django
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
from access.fields import *
|
||||
|
||||
User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
class HistoryCommonFields(models.Model):
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
id = models.AutoField(
|
||||
blank=False,
|
||||
help_text = 'ID for this history entry',
|
||||
primary_key=True,
|
||||
unique=True,
|
||||
verbose_name = 'ID'
|
||||
)
|
||||
|
||||
created = AutoCreatedField()
|
||||
|
||||
|
||||
|
||||
class History(HistoryCommonFields):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
ordering = [
|
||||
'-created'
|
||||
]
|
||||
|
||||
verbose_name = 'History'
|
||||
|
||||
verbose_name_plural = 'History'
|
||||
|
||||
|
||||
class Actions(models.IntegerChoices):
|
||||
ADD = 1, 'Create'
|
||||
UPDATE = 2, 'Update'
|
||||
DELETE = 3, 'Delete'
|
||||
|
||||
|
||||
before = models.JSONField(
|
||||
blank = True,
|
||||
default = None,
|
||||
help_text = 'JSON Object before Change',
|
||||
null = True,
|
||||
verbose_name = 'Before'
|
||||
)
|
||||
|
||||
|
||||
after = models.JSONField(
|
||||
blank = True,
|
||||
default = None,
|
||||
help_text = 'JSON Object After Change',
|
||||
null = True,
|
||||
verbose_name = 'After'
|
||||
)
|
||||
|
||||
|
||||
action = models.IntegerField(
|
||||
blank = False,
|
||||
choices=Actions,
|
||||
default=None,
|
||||
help_text = 'History action performed',
|
||||
null=True,
|
||||
verbose_name = 'Action'
|
||||
)
|
||||
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
blank= False,
|
||||
help_text = 'User whom performed the action this history relates to',
|
||||
null = True,
|
||||
on_delete=models.DO_NOTHING,
|
||||
verbose_name = 'User'
|
||||
)
|
||||
|
||||
item_pk = models.IntegerField(
|
||||
blank = False,
|
||||
default=None,
|
||||
help_text = 'Primary Key of the item this history relates to',
|
||||
null = True,
|
||||
verbose_name = 'Item ID'
|
||||
)
|
||||
|
||||
item_class = models.CharField(
|
||||
blank = False,
|
||||
default=None,
|
||||
help_text = 'Class of the item this history relates to',
|
||||
null = True,
|
||||
max_length = 50,
|
||||
unique = False,
|
||||
)
|
||||
|
||||
item_parent_pk = models.IntegerField(
|
||||
blank = False,
|
||||
default=None,
|
||||
help_text = 'Primary Key of the Parent Item this history relates to',
|
||||
null = True,
|
||||
verbose_name = 'Parent ID'
|
||||
)
|
||||
|
||||
item_parent_class = models.CharField(
|
||||
blank = False,
|
||||
default=None,
|
||||
help_text = 'Class oof the Paarent Item this history relates to',
|
||||
max_length = 50,
|
||||
null = True,
|
||||
unique = False,
|
||||
verbose_name = 'Parent Class'
|
||||
)
|
||||
|
||||
|
||||
table_fields: list = [
|
||||
'created',
|
||||
'action',
|
||||
'item_class',
|
||||
'user',
|
||||
'nbsp',
|
||||
[
|
||||
'before',
|
||||
'after'
|
||||
]
|
||||
]
|
@ -1,143 +0,0 @@
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework import serializers
|
||||
|
||||
from access.serializers.organization import TenantBaseSerializer
|
||||
|
||||
from centurion.serializers.user import UserBaseSerializer
|
||||
|
||||
from core.models.model_history import ModelHistory
|
||||
|
||||
|
||||
|
||||
class HistoryBaseSerializer(serializers.ModelSerializer):
|
||||
|
||||
display_name = serializers.SerializerMethodField('get_display_name')
|
||||
|
||||
def get_display_name(self, item) -> str:
|
||||
|
||||
return str( item )
|
||||
|
||||
url = serializers.SerializerMethodField('get_my_url')
|
||||
|
||||
def get_my_url(self, item) -> str:
|
||||
|
||||
return reverse("v2:_api_v2_model_history-detail",
|
||||
request=self._context['view'].request,
|
||||
kwargs={
|
||||
'model_class': self._kwargs['context']['view'].kwargs['model_class'],
|
||||
'model_id': self._kwargs['context']['view'].kwargs['model_id'],
|
||||
'pk': item.pk
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
model = ModelHistory
|
||||
|
||||
fields = [
|
||||
'id',
|
||||
'display_name',
|
||||
'url',
|
||||
]
|
||||
|
||||
read_only_fields = [
|
||||
'id',
|
||||
'display_name',
|
||||
'url',
|
||||
]
|
||||
|
||||
|
||||
class HistoryModelSerializer(HistoryBaseSerializer):
|
||||
|
||||
|
||||
after = serializers.JSONField(read_only=True)
|
||||
|
||||
before = serializers.JSONField(read_only=True)
|
||||
|
||||
_urls = serializers.SerializerMethodField('get_url')
|
||||
|
||||
def get_url(self, item) -> dict:
|
||||
|
||||
return {
|
||||
'_self': reverse("v2:_api_v2_model_history-detail",
|
||||
request=self._context['view'].request,
|
||||
kwargs={
|
||||
'app_label': self._kwargs['context']['view'].kwargs['app_label'],
|
||||
'model_name': self._kwargs['context']['view'].kwargs['model_name'],
|
||||
'model_id': self._kwargs['context']['view'].kwargs['model_id'],
|
||||
'pk': item.pk
|
||||
}
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
model = serializers.SerializerMethodField('get_model', label = 'device')
|
||||
|
||||
def get_model(self, item):
|
||||
|
||||
model = {}
|
||||
|
||||
model = item.get_serialized_model_field( self.context )
|
||||
|
||||
return model
|
||||
|
||||
|
||||
child_model = serializers.SerializerMethodField('get_child_model')
|
||||
|
||||
def get_child_model(self, item):
|
||||
|
||||
model = {}
|
||||
|
||||
model = item.get_serialized_child_model_field( self.context )
|
||||
|
||||
return model
|
||||
|
||||
content = serializers.SerializerMethodField('get_content')
|
||||
|
||||
def get_content(self, item):
|
||||
|
||||
model = getattr(item, item.get_related_field_name( item ))
|
||||
|
||||
content = model.model._meta.model_name
|
||||
|
||||
if self.get_child_model(item):
|
||||
|
||||
return getattr(model, item.get_related_field_name( model )).child_model._meta.model_name
|
||||
|
||||
return content
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
model = ModelHistory
|
||||
|
||||
fields = [
|
||||
'id',
|
||||
'display_name',
|
||||
'content',
|
||||
'before',
|
||||
'after',
|
||||
'action',
|
||||
'user',
|
||||
'model',
|
||||
'child_model',
|
||||
'organization',
|
||||
'created',
|
||||
'_urls',
|
||||
]
|
||||
|
||||
read_only_fields = [
|
||||
'id',
|
||||
'display_name',
|
||||
'created',
|
||||
'_urls',
|
||||
]
|
||||
|
||||
|
||||
|
||||
class HistoryViewSerializer(HistoryModelSerializer):
|
||||
|
||||
organization = TenantBaseSerializer( read_only = True )
|
||||
|
||||
user = UserBaseSerializer( read_only = True )
|
@ -1,171 +0,0 @@
|
||||
from django.contrib.auth.models import ContentType
|
||||
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse
|
||||
|
||||
from api.viewsets.common import ReadOnlyModelViewSet
|
||||
|
||||
from core.serializers.history import (
|
||||
ModelHistory,
|
||||
HistoryViewSerializer
|
||||
)
|
||||
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
create=extend_schema( exclude = True ),
|
||||
destroy = extend_schema( exclude = True ),
|
||||
list = extend_schema(
|
||||
summary = 'Fetch entire history for a model',
|
||||
description='',
|
||||
responses = {
|
||||
200: OpenApiResponse(description='', response=HistoryViewSerializer),
|
||||
403: OpenApiResponse(description='User is missing view permissions'),
|
||||
}
|
||||
),
|
||||
retrieve = extend_schema( exclude = True ),
|
||||
update = extend_schema( exclude = True ),
|
||||
partial_update = extend_schema( exclude = True )
|
||||
)
|
||||
class ViewSet(ReadOnlyModelViewSet):
|
||||
|
||||
allowed_methods = [
|
||||
'GET',
|
||||
'OPTIONS'
|
||||
]
|
||||
|
||||
|
||||
filterset_fields = [
|
||||
'content_type',
|
||||
'user',
|
||||
]
|
||||
|
||||
model = ModelHistory
|
||||
|
||||
view_description: str = 'Model Change History'
|
||||
|
||||
_content_type: ContentType = None
|
||||
|
||||
|
||||
def get_content_type(self) -> ContentType:
|
||||
|
||||
if self._content_type is None:
|
||||
|
||||
self._content_type = ContentType.objects.prefetch_related(
|
||||
'permission_set'
|
||||
).get(
|
||||
app_label = self.kwargs['app_label'],
|
||||
model = self.kwargs['model_name'],
|
||||
)
|
||||
|
||||
return self._content_type
|
||||
|
||||
|
||||
def get_dynamic_permissions(self):
|
||||
|
||||
|
||||
view_action: str = None
|
||||
|
||||
if(
|
||||
self.action == 'create'
|
||||
or getattr(self.request, 'method', '') == 'POST'
|
||||
):
|
||||
|
||||
view_action = 'add'
|
||||
|
||||
elif (
|
||||
self.action == 'partial_update'
|
||||
or self.action == 'update'
|
||||
or getattr(self.request, 'method', '') == 'PATCH'
|
||||
or getattr(self.request, 'method', '') == 'PUT'
|
||||
):
|
||||
|
||||
view_action = 'change'
|
||||
|
||||
elif(
|
||||
self.action == 'destroy'
|
||||
or getattr(self.request, 'method', '') == 'DELETE'
|
||||
):
|
||||
|
||||
view_action = 'delete'
|
||||
|
||||
elif (
|
||||
self.action == 'list'
|
||||
):
|
||||
|
||||
view_action = 'view'
|
||||
|
||||
elif self.action == 'retrieve':
|
||||
|
||||
view_action = 'view'
|
||||
|
||||
elif self.action == 'metadata':
|
||||
|
||||
view_action = 'view'
|
||||
|
||||
self._permission_required = self.kwargs['app_label'] + '.' + view_action + '_' + self.kwargs['model_name'] + 'history'
|
||||
|
||||
return self._permission_required
|
||||
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
if self.queryset is not None:
|
||||
|
||||
return self.queryset
|
||||
|
||||
history_models = ContentType.objects.filter(
|
||||
model__contains = 'history'
|
||||
).exclude(
|
||||
model__contains = 'audithistory'
|
||||
).exclude(
|
||||
app_label = 'core',
|
||||
model = 'modelhistory'
|
||||
).exclude( # Old history model. This exclude block can be removed when the model is removed.
|
||||
app_label = 'core',
|
||||
model = 'history'
|
||||
).exclude(
|
||||
model__in = self.model.child_history_models
|
||||
)
|
||||
|
||||
history_models: list = list([ f.model for f in history_models ])
|
||||
|
||||
self.queryset = self.model.objects.select_related(
|
||||
*history_models
|
||||
).filter(
|
||||
content_type_id = self.get_content_type().id
|
||||
)
|
||||
|
||||
if len( self.queryset ) > 0:
|
||||
|
||||
related_object_name = self.queryset[0].get_related_field_name( self.queryset[0] )
|
||||
|
||||
|
||||
self.queryset = self.queryset.filter(
|
||||
**{
|
||||
str(related_object_name + '__model_id'): int(self.kwargs['model_id']),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return self.queryset
|
||||
|
||||
|
||||
def get_serializer_class(self):
|
||||
|
||||
model_name = str( self.model._meta.verbose_name).replace(' ', '')
|
||||
|
||||
if model_name == 'ModelHistory':
|
||||
|
||||
model_name = 'History'
|
||||
|
||||
self.serializer_class = globals()[model_name + 'ViewSerializer']
|
||||
|
||||
return self.serializer_class
|
||||
|
||||
|
||||
def get_view_name(self):
|
||||
if self.detail:
|
||||
return "History"
|
||||
|
||||
return 'History'
|
Reference in New Issue
Block a user