Merge branch 'dev' into feature-ai

This commit is contained in:
shamoon
2025-10-29 11:13:37 -07:00
committed by GitHub
106 changed files with 5290 additions and 4712 deletions

View File

@@ -92,6 +92,12 @@ class TagFilterSet(FilterSet):
"name": CHAR_KWARGS,
}
is_root = BooleanFilter(
label="Is root tag",
field_name="tn_parent",
lookup_expr="isnull",
)
class DocumentTypeFilterSet(FilterSet):
class Meta:

View File

@@ -164,6 +164,24 @@ def has_perms_owner_aware(user, perms, obj):
return obj.owner is None or obj.owner == user or checker.has_perm(perms, obj)
class ViewDocumentsPermissions(BasePermission):
"""
Permissions class that checks for model permissions for only viewing Documents.
"""
perms_map = {
"OPTIONS": ["documents.view_document"],
"GET": ["documents.view_document"],
"POST": ["documents.view_document"],
}
def has_permission(self, request, view):
if not request.user or (not request.user.is_authenticated): # pragma: no cover
return False
return request.user.has_perms(self.perms_map.get(request.method, []))
class PaperlessNotePermissions(BasePermission):
"""
Permissions class that checks for model permissions for Notes.

View File

@@ -329,6 +329,34 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_email_only_requires_view_permission(self):
"""
GIVEN:
- User having only view documents permission
WHEN:
- API request is made to bulk email documents
THEN:
- Request succeeds
"""
user1 = User.objects.create_user(username="test1")
user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
self.client.force_authenticate(user1)
response = self.client.post(
self.ENDPOINT,
json.dumps(
{
"documents": [self.doc1.pk],
"addresses": "test@example.com",
"subject": "Test",
"message": "Test message",
},
),
content_type="application/json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
@override_settings(
EMAIL_ENABLED=True,
EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend",

View File

@@ -229,3 +229,24 @@ class TestTagHierarchy(APITestCase):
assert resp_ok.status_code in (200, 202)
x.refresh_from_db()
assert x.parent_pk == c.id
def test_is_root_filter_returns_only_root_tags(self):
other_root = Tag.objects.create(name="Other parent")
response = self.client.get(
"/api/tags/",
{"is_root": "true"},
)
assert response.status_code == 200
assert response.data["count"] == 2
returned_ids = {row["id"] for row in response.data["results"]}
assert self.child.pk not in returned_ids
assert self.parent.pk in returned_ids
assert other_root.pk in returned_ids
parent_entry = next(
row for row in response.data["results"] if row["id"] == self.parent.pk
)
assert any(child["id"] == self.child.pk for child in parent_entry["children"])

View File

@@ -147,6 +147,7 @@ from documents.permissions import AcknowledgeTasksPermissions
from documents.permissions import PaperlessAdminPermissions
from documents.permissions import PaperlessNotePermissions
from documents.permissions import PaperlessObjectPermissions
from documents.permissions import ViewDocumentsPermissions
from documents.permissions import get_document_count_filter_for_user
from documents.permissions import get_objects_for_user_owner_aware
from documents.permissions import has_perms_owner_aware
@@ -1252,7 +1253,12 @@ class DocumentViewSet(
return Response(sorted(entries, key=lambda x: x["timestamp"], reverse=True))
@action(methods=["post"], detail=True, url_path="email")
@action(
methods=["post"],
detail=True,
url_path="email",
permission_classes=[IsAuthenticated, ViewDocumentsPermissions],
)
# TODO: deprecated as of 2.19, remove in future release
def email_document(self, request, pk=None):
request_data = request.data.copy()
@@ -1264,6 +1270,7 @@ class DocumentViewSet(
detail=False,
url_path="email",
serializer_class=EmailSerializer,
permission_classes=[IsAuthenticated, ViewDocumentsPermissions],
)
def email_documents(self, request, data=None):
serializer = EmailSerializer(data=data or request.data)