mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Feature: Audit Trail (#4425)
Adds new feature for optionally enabling change tracking for possible audit purposes --------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> Co-authored-by: Trenton Holmes <797416+stumpylog@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from guardian.admin import GuardedModelAdmin
|
||||
|
||||
@@ -12,6 +13,10 @@ from documents.models import ShareLink
|
||||
from documents.models import StoragePath
|
||||
from documents.models import Tag
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
from auditlog.admin import LogEntryAdmin
|
||||
from auditlog.models import LogEntry
|
||||
|
||||
|
||||
class CorrespondentAdmin(GuardedModelAdmin):
|
||||
list_display = ("name", "match", "matching_algorithm")
|
||||
@@ -148,3 +153,12 @@ admin.site.register(StoragePath, StoragePathAdmin)
|
||||
admin.site.register(PaperlessTask, TaskAdmin)
|
||||
admin.site.register(Note, NotesAdmin)
|
||||
admin.site.register(ShareLink, ShareLinksAdmin)
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
|
||||
class LogEntryAUDIT(LogEntryAdmin):
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
admin.site.unregister(LogEntry)
|
||||
admin.site.register(LogEntry, LogEntryAUDIT)
|
||||
|
@@ -20,6 +20,9 @@ from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from multiselectfield import MultiSelectField
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
from auditlog.registry import auditlog
|
||||
|
||||
from documents.data_models import DocumentSource
|
||||
from documents.parsers import get_default_file_extension
|
||||
|
||||
@@ -872,3 +875,11 @@ class ConsumptionTemplate(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
auditlog.register(Document, m2m_fields={"tags"})
|
||||
auditlog.register(Correspondent)
|
||||
auditlog.register(Tag)
|
||||
auditlog.register(DocumentType)
|
||||
auditlog.register(Note)
|
||||
|
@@ -37,6 +37,10 @@ from documents.parsers import DocumentParser
|
||||
from documents.parsers import get_parser_class_for_mime_type
|
||||
from documents.sanity_checker import SanityCheckFailedException
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
import json
|
||||
|
||||
from auditlog.models import LogEntry
|
||||
logger = logging.getLogger("paperless.tasks")
|
||||
|
||||
|
||||
@@ -258,11 +262,37 @@ def update_document_archive_file(document_id):
|
||||
document,
|
||||
archive_filename=True,
|
||||
)
|
||||
oldDocument = Document.objects.get(pk=document.pk)
|
||||
Document.objects.filter(pk=document.pk).update(
|
||||
archive_checksum=checksum,
|
||||
content=parser.get_text(),
|
||||
archive_filename=document.archive_filename,
|
||||
)
|
||||
newDocument = Document.objects.get(pk=document.pk)
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
LogEntry.objects.log_create(
|
||||
instance=oldDocument,
|
||||
changes=json.dumps(
|
||||
{
|
||||
"content": [oldDocument.content, newDocument.content],
|
||||
"archive_checksum": [
|
||||
oldDocument.archive_checksum,
|
||||
newDocument.archive_checksum,
|
||||
],
|
||||
"archive_filename": [
|
||||
oldDocument.archive_filename,
|
||||
newDocument.archive_filename,
|
||||
],
|
||||
},
|
||||
),
|
||||
additional_data=json.dumps(
|
||||
{
|
||||
"reason": "Redo OCR called",
|
||||
},
|
||||
),
|
||||
action=LogEntry.Action.UPDATE,
|
||||
)
|
||||
|
||||
with FileLock(settings.MEDIA_LOCK):
|
||||
create_source_path_directory(document.archive_path)
|
||||
shutil.move(parser.get_archive_path(), document.archive_path)
|
||||
|
@@ -115,6 +115,9 @@ from paperless import version
|
||||
from paperless.db import GnuPG
|
||||
from paperless.views import StandardPagination
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
from auditlog.models import LogEntry
|
||||
|
||||
logger = logging.getLogger("paperless.api")
|
||||
|
||||
|
||||
@@ -521,6 +524,18 @@ class DocumentViewSet(
|
||||
user=currentUser,
|
||||
)
|
||||
c.save()
|
||||
# If audit log is enabled make an entry in the log
|
||||
# about this note change
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
LogEntry.objects.log_create(
|
||||
instance=doc,
|
||||
changes=json.dumps(
|
||||
{
|
||||
"Note Added": ["None", c.id],
|
||||
},
|
||||
),
|
||||
action=LogEntry.Action.UPDATE,
|
||||
)
|
||||
|
||||
doc.modified = timezone.now()
|
||||
doc.save()
|
||||
@@ -546,6 +561,17 @@ class DocumentViewSet(
|
||||
return HttpResponseForbidden("Insufficient permissions to delete")
|
||||
|
||||
note = Note.objects.get(id=int(request.GET.get("id")))
|
||||
if settings.AUDIT_LOG_ENABLED:
|
||||
LogEntry.objects.log_create(
|
||||
instance=doc,
|
||||
changes=json.dumps(
|
||||
{
|
||||
"Note Deleted": [note.id, "None"],
|
||||
},
|
||||
),
|
||||
action=LogEntry.Action.UPDATE,
|
||||
)
|
||||
|
||||
note.delete()
|
||||
|
||||
doc.modified = timezone.now()
|
||||
|
Reference in New Issue
Block a user