mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-09-16 21:55:37 -05:00
Move backend to correct module, basic tests
This commit is contained in:
@@ -41,7 +41,6 @@ from documents.models import PaperlessTask
|
|||||||
from documents.models import ShareLink
|
from documents.models import ShareLink
|
||||||
from documents.models import StoragePath
|
from documents.models import StoragePath
|
||||||
from documents.models import Tag
|
from documents.models import Tag
|
||||||
from paperless_mail.models import ProcessedMail
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
@@ -803,15 +802,6 @@ class PaperlessTaskFilterSet(FilterSet):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ProcessedMailFilterSet(FilterSet):
|
|
||||||
class Meta:
|
|
||||||
model = ProcessedMail
|
|
||||||
fields = {
|
|
||||||
"rule": ["exact"],
|
|
||||||
"status": ["exact"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectOwnedOrGrantedPermissionsFilter(ObjectPermissionsFilter):
|
class ObjectOwnedOrGrantedPermissionsFilter(ObjectPermissionsFilter):
|
||||||
"""
|
"""
|
||||||
A filter backend that limits results to those where the requesting user
|
A filter backend that limits results to those where the requesting user
|
||||||
|
@@ -107,7 +107,6 @@ from documents.filters import DocumentTypeFilterSet
|
|||||||
from documents.filters import ObjectOwnedOrGrantedPermissionsFilter
|
from documents.filters import ObjectOwnedOrGrantedPermissionsFilter
|
||||||
from documents.filters import ObjectOwnedPermissionsFilter
|
from documents.filters import ObjectOwnedPermissionsFilter
|
||||||
from documents.filters import PaperlessTaskFilterSet
|
from documents.filters import PaperlessTaskFilterSet
|
||||||
from documents.filters import ProcessedMailFilterSet
|
|
||||||
from documents.filters import ShareLinkFilterSet
|
from documents.filters import ShareLinkFilterSet
|
||||||
from documents.filters import StoragePathFilterSet
|
from documents.filters import StoragePathFilterSet
|
||||||
from documents.filters import TagFilterSet
|
from documents.filters import TagFilterSet
|
||||||
@@ -182,11 +181,9 @@ from paperless.serialisers import UserSerializer
|
|||||||
from paperless.views import StandardPagination
|
from paperless.views import StandardPagination
|
||||||
from paperless_mail.models import MailAccount
|
from paperless_mail.models import MailAccount
|
||||||
from paperless_mail.models import MailRule
|
from paperless_mail.models import MailRule
|
||||||
from paperless_mail.models import ProcessedMail
|
|
||||||
from paperless_mail.oauth import PaperlessMailOAuth2Manager
|
from paperless_mail.oauth import PaperlessMailOAuth2Manager
|
||||||
from paperless_mail.serialisers import MailAccountSerializer
|
from paperless_mail.serialisers import MailAccountSerializer
|
||||||
from paperless_mail.serialisers import MailRuleSerializer
|
from paperless_mail.serialisers import MailRuleSerializer
|
||||||
from paperless_mail.serialisers import ProcessedMailSerializer
|
|
||||||
|
|
||||||
if settings.AUDIT_LOG_ENABLED:
|
if settings.AUDIT_LOG_ENABLED:
|
||||||
from auditlog.models import LogEntry
|
from auditlog.models import LogEntry
|
||||||
@@ -2984,31 +2981,3 @@ def serve_logo(request, filename=None):
|
|||||||
filename=app_logo.name,
|
filename=app_logo.name,
|
||||||
as_attachment=True,
|
as_attachment=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProcessedMailViewSet(ReadOnlyModelViewSet, DestroyModelMixin, PassUserMixin):
|
|
||||||
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
|
||||||
serializer_class = ProcessedMailSerializer
|
|
||||||
pagination_class = StandardPagination
|
|
||||||
filter_backends = (
|
|
||||||
DjangoFilterBackend,
|
|
||||||
OrderingFilter,
|
|
||||||
ObjectOwnedOrGrantedPermissionsFilter,
|
|
||||||
)
|
|
||||||
filterset_class = ProcessedMailFilterSet
|
|
||||||
|
|
||||||
queryset = ProcessedMail.objects.all().order_by("-processed")
|
|
||||||
|
|
||||||
@action(methods=["post"], detail=False)
|
|
||||||
def bulk_delete(self, request):
|
|
||||||
mail_ids = request.data.get("mail_ids", [])
|
|
||||||
if not isinstance(mail_ids, list) or not all(
|
|
||||||
isinstance(i, int) for i in mail_ids
|
|
||||||
):
|
|
||||||
return HttpResponseBadRequest("mail_ids must be a list of integers")
|
|
||||||
mails = ProcessedMail.objects.filter(id__in=mail_ids)
|
|
||||||
for mail in mails:
|
|
||||||
if not has_perms_owner_aware(request.user, "delete_processedmail", mail):
|
|
||||||
return HttpResponseForbidden("Insufficient permissions")
|
|
||||||
mail.delete()
|
|
||||||
return Response({"result": "OK", "deleted_mail_ids": mail_ids})
|
|
||||||
|
@@ -25,7 +25,6 @@ from documents.views import GlobalSearchView
|
|||||||
from documents.views import IndexView
|
from documents.views import IndexView
|
||||||
from documents.views import LogViewSet
|
from documents.views import LogViewSet
|
||||||
from documents.views import PostDocumentView
|
from documents.views import PostDocumentView
|
||||||
from documents.views import ProcessedMailViewSet
|
|
||||||
from documents.views import RemoteVersionView
|
from documents.views import RemoteVersionView
|
||||||
from documents.views import SavedViewViewSet
|
from documents.views import SavedViewViewSet
|
||||||
from documents.views import SearchAutoCompleteView
|
from documents.views import SearchAutoCompleteView
|
||||||
@@ -58,6 +57,7 @@ from paperless.views import UserViewSet
|
|||||||
from paperless_mail.views import MailAccountViewSet
|
from paperless_mail.views import MailAccountViewSet
|
||||||
from paperless_mail.views import MailRuleViewSet
|
from paperless_mail.views import MailRuleViewSet
|
||||||
from paperless_mail.views import OauthCallbackView
|
from paperless_mail.views import OauthCallbackView
|
||||||
|
from paperless_mail.views import ProcessedMailViewSet
|
||||||
|
|
||||||
api_router = DefaultRouter()
|
api_router = DefaultRouter()
|
||||||
api_router.register(r"correspondents", CorrespondentViewSet)
|
api_router.register(r"correspondents", CorrespondentViewSet)
|
||||||
|
12
src/paperless_mail/filters.py
Normal file
12
src/paperless_mail/filters.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django_filters import FilterSet
|
||||||
|
|
||||||
|
from paperless_mail.models import ProcessedMail
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessedMailFilterSet(FilterSet):
|
||||||
|
class Meta:
|
||||||
|
model = ProcessedMail
|
||||||
|
fields = {
|
||||||
|
"rule": ["exact"],
|
||||||
|
"status": ["exact"],
|
||||||
|
}
|
@@ -3,6 +3,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils import timezone
|
||||||
from guardian.shortcuts import assign_perm
|
from guardian.shortcuts import assign_perm
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
@@ -13,6 +14,7 @@ from documents.models import Tag
|
|||||||
from documents.tests.utils import DirectoriesMixin
|
from documents.tests.utils import DirectoriesMixin
|
||||||
from paperless_mail.models import MailAccount
|
from paperless_mail.models import MailAccount
|
||||||
from paperless_mail.models import MailRule
|
from paperless_mail.models import MailRule
|
||||||
|
from paperless_mail.models import ProcessedMail
|
||||||
from paperless_mail.tests.test_mail import BogusMailBox
|
from paperless_mail.tests.test_mail import BogusMailBox
|
||||||
|
|
||||||
|
|
||||||
@@ -721,3 +723,285 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
self.assertIn("maximum_age", response.data)
|
self.assertIn("maximum_age", response.data)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAPIProcessedMails(DirectoriesMixin, APITestCase):
|
||||||
|
ENDPOINT = "/api/processed_mail/"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
self.user = User.objects.create_user(username="temp_admin")
|
||||||
|
self.user.user_permissions.add(*Permission.objects.all())
|
||||||
|
self.user.save()
|
||||||
|
self.client.force_authenticate(user=self.user)
|
||||||
|
|
||||||
|
def test_get_processed_mails_owner_aware(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Configured processed mails with different users
|
||||||
|
WHEN:
|
||||||
|
- API call is made to get processed mails
|
||||||
|
THEN:
|
||||||
|
- Only unowned, owned by user or granted processed mails are provided
|
||||||
|
"""
|
||||||
|
user2 = User.objects.create_user(username="temp_admin2")
|
||||||
|
|
||||||
|
account = MailAccount.objects.create(
|
||||||
|
name="Email1",
|
||||||
|
username="username1",
|
||||||
|
password="password1",
|
||||||
|
imap_server="server.example.com",
|
||||||
|
imap_port=443,
|
||||||
|
imap_security=MailAccount.ImapSecurity.SSL,
|
||||||
|
character_set="UTF-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
rule = MailRule.objects.create(
|
||||||
|
name="Rule1",
|
||||||
|
account=account,
|
||||||
|
folder="INBOX",
|
||||||
|
filter_from="from@example.com",
|
||||||
|
order=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
pm1 = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="1",
|
||||||
|
subject="Subj1",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
pm2 = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="2",
|
||||||
|
subject="Subj2",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="FAILED",
|
||||||
|
error="err",
|
||||||
|
owner=self.user,
|
||||||
|
)
|
||||||
|
|
||||||
|
ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="3",
|
||||||
|
subject="Subj3",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
owner=user2,
|
||||||
|
)
|
||||||
|
|
||||||
|
pm4 = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="4",
|
||||||
|
subject="Subj4",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
)
|
||||||
|
pm4.owner = user2
|
||||||
|
pm4.save()
|
||||||
|
assign_perm("view_processedmail", self.user, pm4)
|
||||||
|
|
||||||
|
response = self.client.get(self.ENDPOINT)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data["count"], 3)
|
||||||
|
returned_ids = {r["id"] for r in response.data["results"]}
|
||||||
|
self.assertSetEqual(returned_ids, {pm1.id, pm2.id, pm4.id})
|
||||||
|
|
||||||
|
def test_get_processed_mails_filter_by_rule(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Processed mails belonging to two different rules
|
||||||
|
WHEN:
|
||||||
|
- API call is made with rule filter
|
||||||
|
THEN:
|
||||||
|
- Only processed mails for that rule are returned
|
||||||
|
"""
|
||||||
|
account = MailAccount.objects.create(
|
||||||
|
name="Email1",
|
||||||
|
username="username1",
|
||||||
|
password="password1",
|
||||||
|
imap_server="server.example.com",
|
||||||
|
imap_port=443,
|
||||||
|
imap_security=MailAccount.ImapSecurity.SSL,
|
||||||
|
character_set="UTF-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
rule1 = MailRule.objects.create(
|
||||||
|
name="Rule1",
|
||||||
|
account=account,
|
||||||
|
folder="INBOX",
|
||||||
|
filter_from="from1@example.com",
|
||||||
|
order=0,
|
||||||
|
)
|
||||||
|
rule2 = MailRule.objects.create(
|
||||||
|
name="Rule2",
|
||||||
|
account=account,
|
||||||
|
folder="INBOX",
|
||||||
|
filter_from="from2@example.com",
|
||||||
|
order=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
pm1 = ProcessedMail.objects.create(
|
||||||
|
rule=rule1,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="r1-1",
|
||||||
|
subject="R1-A",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
owner=self.user,
|
||||||
|
)
|
||||||
|
pm2 = ProcessedMail.objects.create(
|
||||||
|
rule=rule1,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="r1-2",
|
||||||
|
subject="R1-B",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="FAILED",
|
||||||
|
error="e",
|
||||||
|
)
|
||||||
|
ProcessedMail.objects.create(
|
||||||
|
rule=rule2,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="r2-1",
|
||||||
|
subject="R2-A",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.get(f"{self.ENDPOINT}?rule={rule1.pk}")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
returned_ids = {r["id"] for r in response.data["results"]}
|
||||||
|
self.assertSetEqual(returned_ids, {pm1.id, pm2.id})
|
||||||
|
|
||||||
|
def test_bulk_delete_processed_mails(self):
|
||||||
|
"""
|
||||||
|
GIVEN:
|
||||||
|
- Processed mails belonging to two different rules and different users
|
||||||
|
WHEN:
|
||||||
|
- API call is made to bulk delete some of the processed mails
|
||||||
|
THEN:
|
||||||
|
- Only the specified processed mails are deleted, respecting ownership and permissions
|
||||||
|
"""
|
||||||
|
user2 = User.objects.create_user(username="temp_admin2")
|
||||||
|
|
||||||
|
account = MailAccount.objects.create(
|
||||||
|
name="Email1",
|
||||||
|
username="username1",
|
||||||
|
password="password1",
|
||||||
|
imap_server="server.example.com",
|
||||||
|
imap_port=443,
|
||||||
|
imap_security=MailAccount.ImapSecurity.SSL,
|
||||||
|
character_set="UTF-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
rule = MailRule.objects.create(
|
||||||
|
name="Rule1",
|
||||||
|
account=account,
|
||||||
|
folder="INBOX",
|
||||||
|
filter_from="from@example.com",
|
||||||
|
order=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
# unowned and owned by self, and one with explicit object perm
|
||||||
|
pm_unowned = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="u1",
|
||||||
|
subject="Unowned",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
)
|
||||||
|
pm_owned = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="u2",
|
||||||
|
subject="Owned",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="FAILED",
|
||||||
|
error="e",
|
||||||
|
owner=self.user,
|
||||||
|
)
|
||||||
|
pm_granted = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="u3",
|
||||||
|
subject="Granted",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
owner=user2,
|
||||||
|
)
|
||||||
|
assign_perm("delete_processedmail", self.user, pm_granted)
|
||||||
|
pm_forbidden = ProcessedMail.objects.create(
|
||||||
|
rule=rule,
|
||||||
|
folder="INBOX",
|
||||||
|
uid="u4",
|
||||||
|
subject="Forbidden",
|
||||||
|
received=timezone.now(),
|
||||||
|
processed=timezone.now(),
|
||||||
|
status="SUCCESS",
|
||||||
|
error=None,
|
||||||
|
owner=user2,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Success for allowed items
|
||||||
|
response = self.client.post(
|
||||||
|
f"{self.ENDPOINT}bulk_delete/",
|
||||||
|
data={
|
||||||
|
"mail_ids": [pm_unowned.id, pm_owned.id, pm_granted.id],
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response.data["result"], "OK")
|
||||||
|
self.assertSetEqual(
|
||||||
|
set(response.data["deleted_mail_ids"]),
|
||||||
|
{pm_unowned.id, pm_owned.id, pm_granted.id},
|
||||||
|
)
|
||||||
|
self.assertFalse(ProcessedMail.objects.filter(id=pm_unowned.id).exists())
|
||||||
|
self.assertFalse(ProcessedMail.objects.filter(id=pm_owned.id).exists())
|
||||||
|
self.assertFalse(ProcessedMail.objects.filter(id=pm_granted.id).exists())
|
||||||
|
self.assertTrue(ProcessedMail.objects.filter(id=pm_forbidden.id).exists())
|
||||||
|
|
||||||
|
# 403 and not deleted
|
||||||
|
response = self.client.post(
|
||||||
|
f"{self.ENDPOINT}bulk_delete/",
|
||||||
|
data={
|
||||||
|
"mail_ids": [pm_forbidden.id],
|
||||||
|
},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
|
self.assertTrue(ProcessedMail.objects.filter(id=pm_forbidden.id).exists())
|
||||||
|
|
||||||
|
# missing mail_ids
|
||||||
|
response = self.client.post(
|
||||||
|
f"{self.ENDPOINT}bulk_delete/",
|
||||||
|
data={"mail_ids": "not-a-list"},
|
||||||
|
format="json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
@@ -3,8 +3,10 @@ import logging
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.http import HttpResponseBadRequest
|
from django.http import HttpResponseBadRequest
|
||||||
|
from django.http import HttpResponseForbidden
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import extend_schema
|
from drf_spectacular.utils import extend_schema
|
||||||
from drf_spectacular.utils import extend_schema_view
|
from drf_spectacular.utils import extend_schema_view
|
||||||
@@ -12,23 +14,29 @@ from drf_spectacular.utils import inline_serializer
|
|||||||
from httpx_oauth.oauth2 import GetAccessTokenError
|
from httpx_oauth.oauth2 import GetAccessTokenError
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.filters import OrderingFilter
|
||||||
from rest_framework.generics import GenericAPIView
|
from rest_framework.generics import GenericAPIView
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||||
|
|
||||||
from documents.filters import ObjectOwnedOrGrantedPermissionsFilter
|
from documents.filters import ObjectOwnedOrGrantedPermissionsFilter
|
||||||
from documents.permissions import PaperlessObjectPermissions
|
from documents.permissions import PaperlessObjectPermissions
|
||||||
|
from documents.permissions import has_perms_owner_aware
|
||||||
from documents.views import PassUserMixin
|
from documents.views import PassUserMixin
|
||||||
from paperless.views import StandardPagination
|
from paperless.views import StandardPagination
|
||||||
|
from paperless_mail.filters import ProcessedMailFilterSet
|
||||||
from paperless_mail.mail import MailError
|
from paperless_mail.mail import MailError
|
||||||
from paperless_mail.mail import get_mailbox
|
from paperless_mail.mail import get_mailbox
|
||||||
from paperless_mail.mail import mailbox_login
|
from paperless_mail.mail import mailbox_login
|
||||||
from paperless_mail.models import MailAccount
|
from paperless_mail.models import MailAccount
|
||||||
from paperless_mail.models import MailRule
|
from paperless_mail.models import MailRule
|
||||||
|
from paperless_mail.models import ProcessedMail
|
||||||
from paperless_mail.oauth import PaperlessMailOAuth2Manager
|
from paperless_mail.oauth import PaperlessMailOAuth2Manager
|
||||||
from paperless_mail.serialisers import MailAccountSerializer
|
from paperless_mail.serialisers import MailAccountSerializer
|
||||||
from paperless_mail.serialisers import MailRuleSerializer
|
from paperless_mail.serialisers import MailRuleSerializer
|
||||||
|
from paperless_mail.serialisers import ProcessedMailSerializer
|
||||||
from paperless_mail.tasks import process_mail_accounts
|
from paperless_mail.tasks import process_mail_accounts
|
||||||
|
|
||||||
|
|
||||||
@@ -126,6 +134,34 @@ class MailAccountViewSet(ModelViewSet, PassUserMixin):
|
|||||||
return Response({"result": "OK"})
|
return Response({"result": "OK"})
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessedMailViewSet(ReadOnlyModelViewSet, PassUserMixin):
|
||||||
|
permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
|
||||||
|
serializer_class = ProcessedMailSerializer
|
||||||
|
pagination_class = StandardPagination
|
||||||
|
filter_backends = (
|
||||||
|
DjangoFilterBackend,
|
||||||
|
OrderingFilter,
|
||||||
|
ObjectOwnedOrGrantedPermissionsFilter,
|
||||||
|
)
|
||||||
|
filterset_class = ProcessedMailFilterSet
|
||||||
|
|
||||||
|
queryset = ProcessedMail.objects.all().order_by("-processed")
|
||||||
|
|
||||||
|
@action(methods=["post"], detail=False)
|
||||||
|
def bulk_delete(self, request):
|
||||||
|
mail_ids = request.data.get("mail_ids", [])
|
||||||
|
if not isinstance(mail_ids, list) or not all(
|
||||||
|
isinstance(i, int) for i in mail_ids
|
||||||
|
):
|
||||||
|
return HttpResponseBadRequest("mail_ids must be a list of integers")
|
||||||
|
mails = ProcessedMail.objects.filter(id__in=mail_ids)
|
||||||
|
for mail in mails:
|
||||||
|
if not has_perms_owner_aware(request.user, "delete_processedmail", mail):
|
||||||
|
return HttpResponseForbidden("Insufficient permissions")
|
||||||
|
mail.delete()
|
||||||
|
return Response({"result": "OK", "deleted_mail_ids": mail_ids})
|
||||||
|
|
||||||
|
|
||||||
class MailRuleViewSet(ModelViewSet, PassUserMixin):
|
class MailRuleViewSet(ModelViewSet, PassUserMixin):
|
||||||
model = MailRule
|
model = MailRule
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user