mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-05-01 11:19:32 -05:00
update API access for logs
This commit is contained in:
parent
723c10771f
commit
1e1f2267e7
@ -153,19 +153,6 @@ class DocumentSerializer(DynamicFieldsModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LogSerializer(serializers.ModelSerializer):
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Log
|
|
||||||
fields = (
|
|
||||||
"id",
|
|
||||||
"created",
|
|
||||||
"message",
|
|
||||||
"group",
|
|
||||||
"level"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SavedViewFilterRuleSerializer(serializers.ModelSerializer):
|
class SavedViewFilterRuleSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -4,7 +4,9 @@ import shutil
|
|||||||
import tempfile
|
import tempfile
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.test import override_settings
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
from whoosh.writing import AsyncWriter
|
from whoosh.writing import AsyncWriter
|
||||||
|
|
||||||
@ -717,6 +719,28 @@ class TestDocumentApi(DirectoriesMixin, APITestCase):
|
|||||||
v1 = SavedView.objects.get(id=v1.id)
|
v1 = SavedView.objects.get(id=v1.id)
|
||||||
self.assertEqual(v1.filter_rules.count(), 0)
|
self.assertEqual(v1.filter_rules.count(), 0)
|
||||||
|
|
||||||
|
def test_get_logs(self):
|
||||||
|
response = self.client.get("/api/logs/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertCountEqual(response.data, ["mail", "paperless"])
|
||||||
|
|
||||||
|
def test_get_invalid_log(self):
|
||||||
|
response = self.client.get("/api/logs/bogus_log/")
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
@override_settings(LOGGING_DIR="bogus_dir")
|
||||||
|
def test_get_nonexistent_log(self):
|
||||||
|
response = self.client.get("/api/logs/paperless/")
|
||||||
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
|
def test_get_log(self):
|
||||||
|
log_data = "test\ntest2\n"
|
||||||
|
with open(os.path.join(settings.LOGGING_DIR, "paperless.log"), "w") as f:
|
||||||
|
f.write(log_data)
|
||||||
|
response = self.client.get("/api/logs/paperless/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertListEqual(response.data, ["test", "test2"])
|
||||||
|
|
||||||
|
|
||||||
class TestBulkEdit(DirectoriesMixin, APITestCase):
|
class TestBulkEdit(DirectoriesMixin, APITestCase):
|
||||||
|
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
import logging
|
|
||||||
import uuid
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from django.test import TestCase, override_settings
|
|
||||||
|
|
||||||
from ..models import Log
|
|
||||||
|
|
||||||
|
|
||||||
class TestPaperlessLog(TestCase):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
TestCase.__init__(self, *args, **kwargs)
|
|
||||||
self.logger = logging.getLogger(
|
|
||||||
"documents.management.commands.document_consumer")
|
|
||||||
|
|
||||||
@override_settings(DISABLE_DBHANDLER=False)
|
|
||||||
def test_that_it_saves_at_all(self):
|
|
||||||
|
|
||||||
kw = {"group": uuid.uuid4()}
|
|
||||||
|
|
||||||
self.assertEqual(Log.objects.all().count(), 0)
|
|
||||||
|
|
||||||
with mock.patch("logging.StreamHandler.emit") as __:
|
|
||||||
|
|
||||||
# Debug messages are ignored by default
|
|
||||||
self.logger.debug("This is a debugging message", extra=kw)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 1)
|
|
||||||
|
|
||||||
self.logger.info("This is an informational message", extra=kw)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 2)
|
|
||||||
|
|
||||||
self.logger.warning("This is an warning message", extra=kw)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 3)
|
|
||||||
|
|
||||||
self.logger.error("This is an error message", extra=kw)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 4)
|
|
||||||
|
|
||||||
self.logger.critical("This is a critical message", extra=kw)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 5)
|
|
||||||
|
|
||||||
@override_settings(DISABLE_DBHANDLER=False)
|
|
||||||
def test_groups(self):
|
|
||||||
|
|
||||||
kw1 = {"group": uuid.uuid4()}
|
|
||||||
kw2 = {"group": uuid.uuid4()}
|
|
||||||
|
|
||||||
self.assertEqual(Log.objects.all().count(), 0)
|
|
||||||
|
|
||||||
with mock.patch("logging.StreamHandler.emit") as __:
|
|
||||||
|
|
||||||
self.logger.info("This is an informational message", extra=kw2)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 1)
|
|
||||||
self.assertEqual(Log.objects.filter(group=kw2["group"]).count(), 1)
|
|
||||||
|
|
||||||
self.logger.warning("This is an warning message", extra=kw1)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 2)
|
|
||||||
self.assertEqual(Log.objects.filter(group=kw1["group"]).count(), 1)
|
|
||||||
|
|
||||||
self.logger.error("This is an error message", extra=kw2)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 3)
|
|
||||||
self.assertEqual(Log.objects.filter(group=kw2["group"]).count(), 2)
|
|
||||||
|
|
||||||
self.logger.critical("This is a critical message", extra=kw1)
|
|
||||||
self.assertEqual(Log.objects.all().count(), 4)
|
|
||||||
self.assertEqual(Log.objects.filter(group=kw1["group"]).count(), 2)
|
|
@ -19,12 +19,15 @@ def setup_directories():
|
|||||||
dirs.originals_dir = os.path.join(dirs.media_dir, "documents", "originals")
|
dirs.originals_dir = os.path.join(dirs.media_dir, "documents", "originals")
|
||||||
dirs.thumbnail_dir = os.path.join(dirs.media_dir, "documents", "thumbnails")
|
dirs.thumbnail_dir = os.path.join(dirs.media_dir, "documents", "thumbnails")
|
||||||
dirs.archive_dir = os.path.join(dirs.media_dir, "documents", "archive")
|
dirs.archive_dir = os.path.join(dirs.media_dir, "documents", "archive")
|
||||||
|
dirs.logging_dir = os.path.join(dirs.data_dir, "log")
|
||||||
|
|
||||||
os.makedirs(dirs.index_dir, exist_ok=True)
|
os.makedirs(dirs.index_dir, exist_ok=True)
|
||||||
os.makedirs(dirs.originals_dir, exist_ok=True)
|
os.makedirs(dirs.originals_dir, exist_ok=True)
|
||||||
os.makedirs(dirs.thumbnail_dir, exist_ok=True)
|
os.makedirs(dirs.thumbnail_dir, exist_ok=True)
|
||||||
os.makedirs(dirs.archive_dir, exist_ok=True)
|
os.makedirs(dirs.archive_dir, exist_ok=True)
|
||||||
|
|
||||||
|
os.makedirs(dirs.logging_dir, exist_ok=True)
|
||||||
|
|
||||||
dirs.settings_override = override_settings(
|
dirs.settings_override = override_settings(
|
||||||
DATA_DIR=dirs.data_dir,
|
DATA_DIR=dirs.data_dir,
|
||||||
SCRATCH_DIR=dirs.scratch_dir,
|
SCRATCH_DIR=dirs.scratch_dir,
|
||||||
@ -33,6 +36,7 @@ def setup_directories():
|
|||||||
THUMBNAIL_DIR=dirs.thumbnail_dir,
|
THUMBNAIL_DIR=dirs.thumbnail_dir,
|
||||||
ARCHIVE_DIR=dirs.archive_dir,
|
ARCHIVE_DIR=dirs.archive_dir,
|
||||||
CONSUMPTION_DIR=dirs.consumption_dir,
|
CONSUMPTION_DIR=dirs.consumption_dir,
|
||||||
|
LOGGING_DIR=dirs.logging_dir,
|
||||||
INDEX_DIR=dirs.index_dir,
|
INDEX_DIR=dirs.index_dir,
|
||||||
MODEL_FILE=os.path.join(dirs.data_dir, "classification_model.pickle"),
|
MODEL_FILE=os.path.join(dirs.data_dir, "classification_model.pickle"),
|
||||||
MEDIA_LOCK=os.path.join(dirs.media_dir, "media.lock")
|
MEDIA_LOCK=os.path.join(dirs.media_dir, "media.lock")
|
||||||
|
@ -29,7 +29,7 @@ from rest_framework.views import APIView
|
|||||||
from rest_framework.viewsets import (
|
from rest_framework.viewsets import (
|
||||||
GenericViewSet,
|
GenericViewSet,
|
||||||
ModelViewSet,
|
ModelViewSet,
|
||||||
ReadOnlyModelViewSet
|
ViewSet
|
||||||
)
|
)
|
||||||
|
|
||||||
import documents.index as index
|
import documents.index as index
|
||||||
@ -40,16 +40,14 @@ from .filters import (
|
|||||||
CorrespondentFilterSet,
|
CorrespondentFilterSet,
|
||||||
DocumentFilterSet,
|
DocumentFilterSet,
|
||||||
TagFilterSet,
|
TagFilterSet,
|
||||||
DocumentTypeFilterSet,
|
DocumentTypeFilterSet
|
||||||
LogFilterSet
|
|
||||||
)
|
)
|
||||||
from .matching import match_correspondents, match_tags, match_document_types
|
from .matching import match_correspondents, match_tags, match_document_types
|
||||||
from .models import Correspondent, Document, Log, Tag, DocumentType, SavedView
|
from .models import Correspondent, Document, Tag, DocumentType, SavedView
|
||||||
from .parsers import get_parser_class_for_mime_type
|
from .parsers import get_parser_class_for_mime_type
|
||||||
from .serialisers import (
|
from .serialisers import (
|
||||||
CorrespondentSerializer,
|
CorrespondentSerializer,
|
||||||
DocumentSerializer,
|
DocumentSerializer,
|
||||||
LogSerializer,
|
|
||||||
TagSerializer,
|
TagSerializer,
|
||||||
DocumentTypeSerializer,
|
DocumentTypeSerializer,
|
||||||
PostDocumentSerializer,
|
PostDocumentSerializer,
|
||||||
@ -307,16 +305,28 @@ class DocumentViewSet(RetrieveModelMixin,
|
|||||||
raise Http404()
|
raise Http404()
|
||||||
|
|
||||||
|
|
||||||
class LogViewSet(ReadOnlyModelViewSet):
|
class LogViewSet(ViewSet):
|
||||||
model = Log
|
|
||||||
|
|
||||||
queryset = Log.objects.all()
|
|
||||||
serializer_class = LogSerializer
|
|
||||||
pagination_class = StandardPagination
|
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
filter_backends = (DjangoFilterBackend, OrderingFilter)
|
|
||||||
filterset_class = LogFilterSet
|
log_files = ["paperless", "mail"]
|
||||||
ordering_fields = ("created",)
|
|
||||||
|
def retrieve(self, request, pk=None, *args, **kwargs):
|
||||||
|
if not pk in self.log_files:
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
filename = os.path.join(settings.LOGGING_DIR, f"{pk}.log")
|
||||||
|
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
raise Http404()
|
||||||
|
|
||||||
|
with open(filename, "r") as f:
|
||||||
|
lines = [l.rstrip() for l in f.readlines()]
|
||||||
|
|
||||||
|
return Response(lines)
|
||||||
|
|
||||||
|
def list(self, request, *args, **kwargs):
|
||||||
|
return Response(self.log_files)
|
||||||
|
|
||||||
|
|
||||||
class SavedViewViewSet(ModelViewSet):
|
class SavedViewViewSet(ModelViewSet):
|
||||||
|
@ -31,7 +31,7 @@ api_router = DefaultRouter()
|
|||||||
api_router.register(r"correspondents", CorrespondentViewSet)
|
api_router.register(r"correspondents", CorrespondentViewSet)
|
||||||
api_router.register(r"document_types", DocumentTypeViewSet)
|
api_router.register(r"document_types", DocumentTypeViewSet)
|
||||||
api_router.register(r"documents", DocumentViewSet)
|
api_router.register(r"documents", DocumentViewSet)
|
||||||
api_router.register(r"logs", LogViewSet)
|
api_router.register(r"logs", LogViewSet, basename="logs")
|
||||||
api_router.register(r"tags", TagViewSet)
|
api_router.register(r"tags", TagViewSet)
|
||||||
api_router.register(r"saved_views", SavedViewViewSet)
|
api_router.register(r"saved_views", SavedViewViewSet)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user