From aa4b685a07dc4e9c3ae8bcb3aa165dc852b88372 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:14:50 -0800 Subject: [PATCH] Nice, UX for doc in trash --- .../document-detail.component.html | 4 +++ .../document-detail.component.ts | 5 ++++ src/documents/permissions.py | 24 ++++++++++++--- src/documents/serialisers.py | 30 ++++++++----------- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src-ui/src/app/components/document-detail/document-detail.component.html b/src-ui/src/app/components/document-detail/document-detail.component.html index 49cbb0d08..de7aef394 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.html +++ b/src-ui/src/app/components/document-detail/document-detail.component.html @@ -385,9 +385,13 @@ {{ duplicate.title || ('#' + duplicate.id) }} + @if (duplicate.deleted_at) { + In trash + } #{{ duplicate.id }} diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts index f31737722..b407aabcb 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.ts @@ -456,6 +456,11 @@ export class DocumentDetailComponent const openDocument = this.openDocumentService.getOpenDocument( this.documentId ) + // update duplicate documents if present + if (openDocument && doc?.duplicate_documents) { + openDocument.duplicate_documents = doc.duplicate_documents + this.openDocumentService.save() + } const useDoc = openDocument || doc if (openDocument) { if ( diff --git a/src/documents/permissions.py b/src/documents/permissions.py index ac6d3f9ca..9d5c9eb68 100644 --- a/src/documents/permissions.py +++ b/src/documents/permissions.py @@ -148,13 +148,29 @@ def get_document_count_filter_for_user(user): ) -def get_objects_for_user_owner_aware(user, perms, Model) -> QuerySet: - objects_owned = Model.objects.filter(owner=user) - objects_unowned = Model.objects.filter(owner__isnull=True) +def get_objects_for_user_owner_aware( + user, + perms, + Model, + *, + include_deleted=False, +) -> QuerySet: + """ + Returns objects the user owns, are unowned, or has explicit perms. + When include_deleted is True, soft-deleted items are also included. + """ + manager = ( + Model.global_objects + if include_deleted and hasattr(Model, "global_objects") + else Model.objects + ) + + objects_owned = manager.filter(owner=user) + objects_unowned = manager.filter(owner__isnull=True) objects_with_perms = get_objects_for_user( user=user, perms=perms, - klass=Model, + klass=manager.all(), accept_global_perms=False, ) return objects_owned | objects_unowned | objects_with_perms diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index 4f941b41c..ace49a9ce 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -1020,23 +1020,17 @@ def _get_viewable_duplicates(document: Document, user: User | None): checksums = {document.checksum} if document.archive_checksum: checksums.add(document.archive_checksum) - duplicates = ( - Document.global_objects.filter( - Q(checksum__in=checksums) | Q(archive_checksum__in=checksums), - deleted_at__isnull=True, - ) - .exclude(pk=document.pk) - .order_by("-created") - ) - if user.is_superuser: - return duplicates - return duplicates.filter( - id__in=get_objects_for_user_owner_aware( - user, - "documents.view_document", - Document, - ).values_list("id", flat=True), + duplicates = Document.global_objects.filter( + Q(checksum__in=checksums) | Q(archive_checksum__in=checksums), + ).exclude(pk=document.pk) + duplicates = duplicates.order_by("-created") + allowed = get_objects_for_user_owner_aware( + user, + "documents.view_document", + Document, + include_deleted=True, ) + return duplicates.filter(id__in=allowed.values_list("id", flat=True)) @extend_schema_serializer( @@ -1089,7 +1083,7 @@ class DocumentSerializer( request = self.context.get("request") user = request.user if request else None duplicates = _get_viewable_duplicates(obj, user) - return list(duplicates.values("id", "title")) + return list(duplicates.values("id", "title", "deleted_at")) def get_original_file_name(self, obj) -> str | None: return obj.original_filename @@ -2178,7 +2172,7 @@ class TasksViewSerializer(OwnedObjectSerializer): request = self.context.get("request") user = request.user if request else None duplicates = _get_viewable_duplicates(document, user) - cache[obj.pk] = list(duplicates.values("id", "title")) + cache[obj.pk] = list(duplicates.values("id", "title", "deleted_at")) return cache[obj.pk] def get_duplicate_documents(self, obj):