feat: 添加审计日志auditlog表
This commit is contained in:
parent
d9ddefe5db
commit
ba34b26928
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 3.2.12 on 2023-12-07 01:35
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('monitor', '0003_alter_drfrequestlog_view_method'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='AuditLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||||
|
('action', models.CharField(max_length=20, verbose_name='动作')),
|
||||||
|
('model_name', models.CharField(max_length=20, verbose_name='模型名')),
|
||||||
|
('instance_id', models.CharField(editable=False, max_length=20, verbose_name='记录ID')),
|
||||||
|
('change_reason', models.CharField(default='', max_length=50, verbose_name='变更原因')),
|
||||||
|
('change_time', models.DateTimeField(verbose_name='变更时间')),
|
||||||
|
('val_new', models.JSONField(default=dict, verbose_name='变更后完整数据')),
|
||||||
|
('difference', models.JSONField(default=list, verbose_name='变更情况')),
|
||||||
|
('change_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='操作人')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -4,6 +4,19 @@ from django.db import models
|
||||||
from apps.utils.models import BaseModel
|
from apps.utils.models import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class AuditLog(models.Model):
|
||||||
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
|
action = models.CharField('动作', max_length=20)
|
||||||
|
model_name = models.CharField('模型名', max_length=20)
|
||||||
|
instance_id = models.CharField('记录ID', max_length=20, editable=False)
|
||||||
|
change_reason = models.CharField('变更原因', default='', max_length=50)
|
||||||
|
change_user = models.ForeignKey(
|
||||||
|
'system.user', on_delete=models.SET_NULL, verbose_name='操作人', null=True, blank=True)
|
||||||
|
change_time = models.DateTimeField('变更时间')
|
||||||
|
val_new = models.JSONField('变更后完整数据', default=dict)
|
||||||
|
difference = models.JSONField('变更情况', default=list)
|
||||||
|
|
||||||
|
|
||||||
class DrfRequestLog(BaseModel):
|
class DrfRequestLog(BaseModel):
|
||||||
"""Logs Django rest framework API requests"""
|
"""Logs Django rest framework API requests"""
|
||||||
|
|
||||||
|
@ -42,7 +55,8 @@ class DrfRequestLog(BaseModel):
|
||||||
response = models.TextField(null=True, blank=True)
|
response = models.TextField(null=True, blank=True)
|
||||||
errors = models.TextField(null=True, blank=True)
|
errors = models.TextField(null=True, blank=True)
|
||||||
agent = models.TextField(null=True, blank=True)
|
agent = models.TextField(null=True, blank=True)
|
||||||
status_code = models.PositiveIntegerField(null=True, blank=True, db_index=True)
|
status_code = models.PositiveIntegerField(
|
||||||
|
null=True, blank=True, db_index=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "DRF请求日志"
|
verbose_name = "DRF请求日志"
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from apps.utils.serializers import CustomModelSerializer
|
||||||
|
from apps.monitor.models import AuditLog
|
||||||
|
|
||||||
|
|
||||||
class DbbackupDeleteSerializer(serializers.Serializer):
|
class DbbackupDeleteSerializer(serializers.Serializer):
|
||||||
filepaths = serializers.ListField(child=serializers.CharField(), label="文件地址列表")
|
filepaths = serializers.ListField(
|
||||||
|
child=serializers.CharField(), label="文件地址列表")
|
||||||
|
|
||||||
|
|
||||||
|
class AuditLogSerializer(CustomModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = AuditLog
|
||||||
|
fields = '__all__'
|
||||||
|
|
|
@ -1,4 +1,63 @@
|
||||||
import psutil
|
import psutil
|
||||||
|
from apps.monitor.models import AuditLog
|
||||||
|
from apps.system.models import User
|
||||||
|
from datetime import datetime
|
||||||
|
from apps.utils.tools import compare_values
|
||||||
|
from apps.utils.models import get_model_info
|
||||||
|
|
||||||
|
|
||||||
|
def delete_auditlog(model, instance_id):
|
||||||
|
"""
|
||||||
|
删除其对应的审计记录
|
||||||
|
"""
|
||||||
|
model_name = get_model_info(model)
|
||||||
|
AuditLog.objects.filter(model_name=model_name,
|
||||||
|
instance_id=instance_id).delete()
|
||||||
|
|
||||||
|
|
||||||
|
def create_auditlog(action: str, instance, val_new: dict, val_old: dict = None, change_reason: str = '', delete_time: datetime = None, delete_user: User = None):
|
||||||
|
"""
|
||||||
|
生成审计日志
|
||||||
|
action: create/update/delete/其他action
|
||||||
|
"""
|
||||||
|
app_label_model_name = get_model_info(instance)
|
||||||
|
if val_old is None:
|
||||||
|
val_old = {}
|
||||||
|
difference = []
|
||||||
|
has_changed = False
|
||||||
|
if action == 'create':
|
||||||
|
has_changed = True
|
||||||
|
change_user = instance.create_by
|
||||||
|
change_time = instance.create_time
|
||||||
|
elif action == 'delete':
|
||||||
|
has_changed = True
|
||||||
|
change_user = delete_user if delete_user else instance.update_by
|
||||||
|
change_time = delete_time if delete_time else instance.update_time
|
||||||
|
else:
|
||||||
|
change_user = instance.update_by
|
||||||
|
change_time = instance.update_time
|
||||||
|
for k, v in val_new.items():
|
||||||
|
if k not in ['create_by', 'update_by', 'create_time', 'update_time', 'id']:
|
||||||
|
if k not in val_old:
|
||||||
|
difference.append(
|
||||||
|
{'field': k, 'action': 'create', 'val_old': None, 'val_new': v})
|
||||||
|
elif not compare_values(val_new.get(k), val_old.get(k), ignore_order=True):
|
||||||
|
difference.append(
|
||||||
|
{'field': k, 'action': 'update', 'val_old': val_old[k], 'val_new': v})
|
||||||
|
if difference:
|
||||||
|
has_changed = True
|
||||||
|
if has_changed:
|
||||||
|
AuditLog.objects.create(
|
||||||
|
action=action,
|
||||||
|
model_name=app_label_model_name,
|
||||||
|
instance_id=instance.id,
|
||||||
|
val_new=val_new,
|
||||||
|
difference=difference,
|
||||||
|
change_reason=change_reason,
|
||||||
|
change_user=change_user,
|
||||||
|
change_time=change_time
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ServerService:
|
class ServerService:
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -17,7 +76,7 @@ class ServerService:
|
||||||
ret['count'] = psutil.cpu_count(logical=False)
|
ret['count'] = psutil.cpu_count(logical=False)
|
||||||
ret['percent'] = psutil.cpu_percent(interval=1)
|
ret['percent'] = psutil.cpu_percent(interval=1)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_disk_dict(cls):
|
def get_disk_dict(cls):
|
||||||
ret = {}
|
ret = {}
|
||||||
|
@ -29,4 +88,4 @@ class ServerService:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_full(cls):
|
def get_full(cls):
|
||||||
return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()}
|
return {'cpu': cls.get_cpu_dict(), 'memory': cls.get_memory_dict(), 'disk': cls.get_disk_dict()}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .views import DrfRequestLogViewSet, ServerInfoView, LogView, LogDetailView, index, room, video, DbBackupView
|
from .views import DrfRequestLogViewSet, ServerInfoView, LogView, LogDetailView, index, room, video, DbBackupView, AuditlogViewSet
|
||||||
|
|
||||||
API_BASE_URL = 'api/monitor/'
|
API_BASE_URL = 'api/monitor/'
|
||||||
HTML_BASE_URL = 'monitor/'
|
HTML_BASE_URL = 'monitor/'
|
||||||
|
@ -13,5 +13,8 @@ urlpatterns = [
|
||||||
path(API_BASE_URL + 'log/<str:name>/', LogDetailView.as_view()),
|
path(API_BASE_URL + 'log/<str:name>/', LogDetailView.as_view()),
|
||||||
path(API_BASE_URL + 'dbbackup/', DbBackupView.as_view()),
|
path(API_BASE_URL + 'dbbackup/', DbBackupView.as_view()),
|
||||||
path(API_BASE_URL + 'server/', ServerInfoView.as_view()),
|
path(API_BASE_URL + 'server/', ServerInfoView.as_view()),
|
||||||
path(API_BASE_URL + 'request_log/', DrfRequestLogViewSet.as_view({'get': 'list'}), name='requestlog_view')
|
path(API_BASE_URL + 'request_log/',
|
||||||
|
DrfRequestLogViewSet.as_view({'get': 'list'}), name='requestlog_view'),
|
||||||
|
path(API_BASE_URL + 'auditlog/',
|
||||||
|
AuditlogViewSet.as_view({'get': 'list'}), name='auditlog_view')
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,13 +7,13 @@ from rest_framework.permissions import IsAuthenticated
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import os
|
import os
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from apps.monitor.serializers import DbbackupDeleteSerializer
|
from apps.monitor.serializers import DbbackupDeleteSerializer, AuditLogSerializer
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
from drf_yasg.utils import swagger_auto_schema
|
from drf_yasg.utils import swagger_auto_schema
|
||||||
from rest_framework.exceptions import NotFound
|
from rest_framework.exceptions import NotFound
|
||||||
from rest_framework.mixins import ListModelMixin
|
from rest_framework.mixins import ListModelMixin
|
||||||
from apps.monitor.filters import DrfLogFilterSet
|
from apps.monitor.filters import DrfLogFilterSet
|
||||||
from apps.monitor.models import DrfRequestLog
|
from apps.monitor.models import DrfRequestLog, AuditLog
|
||||||
|
|
||||||
from apps.monitor.errors import LOG_NOT_FONED
|
from apps.monitor.errors import LOG_NOT_FONED
|
||||||
from apps.monitor.services import ServerService
|
from apps.monitor.services import ServerService
|
||||||
|
@ -188,3 +188,16 @@ class DrfRequestLogViewSet(ListModelMixin, CustomGenericViewSet):
|
||||||
ordering = ['-requested_at']
|
ordering = ['-requested_at']
|
||||||
filterset_class = DrfLogFilterSet
|
filterset_class = DrfLogFilterSet
|
||||||
search_fields = ['path', 'view']
|
search_fields = ['path', 'view']
|
||||||
|
|
||||||
|
|
||||||
|
class AuditlogViewSet(ListModelMixin, CustomGenericViewSet):
|
||||||
|
"""审计日志
|
||||||
|
|
||||||
|
审计日志
|
||||||
|
"""
|
||||||
|
perms_map = {'get': '*'}
|
||||||
|
queryset = AuditLog.objects.all()
|
||||||
|
list_serializer_class = AuditLogSerializer
|
||||||
|
ordering = ['-change_time']
|
||||||
|
filterset_fields = ['change_user']
|
||||||
|
search_fields = ['model_name', 'action']
|
||||||
|
|
Loading…
Reference in New Issue