@@ -368,6 +368,7 @@ class DocumentViewSet(
368368 queryset = models .Document .objects .select_related ("creator" ).all ()
369369 serializer_class = serializers .DocumentSerializer
370370 ai_translate_serializer_class = serializers .AITranslateSerializer
371+ all_serializer_class = serializers .ListDocumentSerializer
371372 children_serializer_class = serializers .ListDocumentSerializer
372373 descendants_serializer_class = serializers .ListDocumentSerializer
373374 list_serializer_class = serializers .ListDocumentSerializer
@@ -837,6 +838,60 @@ def children(self, request, *args, **kwargs):
837838 },
838839 )
839840
841+ @drf .decorators .action (
842+ detail = False ,
843+ methods = ["get" ],
844+ )
845+ def all (self , request , * args , ** kwargs ):
846+ """
847+ Returns all documents (including descendants) that the user has access to.
848+
849+ Unlike the list endpoint which only returns top-level documents, this endpoint
850+ returns all documents including children, grandchildren, etc.
851+ """
852+ user = self .request .user
853+
854+ accessible_documents = self .get_queryset ()
855+ accessible_paths = list (accessible_documents .values_list ("path" , flat = True ))
856+
857+ if not accessible_paths :
858+ return self .get_response_for_queryset (self .queryset .none ())
859+
860+ # Build query to include all descendants using path prefix matching
861+ descendants_clause = db .Q ()
862+ for path in accessible_paths :
863+ descendants_clause |= db .Q (path__startswith = path )
864+
865+ queryset = self .queryset .filter (
866+ descendants_clause , ancestors_deleted_at__isnull = True
867+ )
868+
869+ # Apply existing filters
870+ filterset = ListDocumentFilter (
871+ self .request .GET , queryset = queryset , request = self .request
872+ )
873+ if not filterset .is_valid ():
874+ raise drf .exceptions .ValidationError (filterset .errors )
875+ filter_data = filterset .form .cleaned_data
876+
877+ # Filter as early as possible on fields that are available on the model
878+ for field in ["is_creator_me" , "title" ]:
879+ queryset = filterset .filters [field ].filter (queryset , filter_data [field ])
880+
881+ queryset = queryset .annotate_user_roles (user )
882+
883+ # Annotate favorite status and filter if applicable as late as possible
884+ queryset = queryset .annotate_is_favorite (user )
885+ for field in ["is_favorite" , "is_masked" ]:
886+ queryset = filterset .filters [field ].filter (queryset , filter_data [field ])
887+
888+ # Apply ordering only now that everything is filtered and annotated
889+ queryset = filters .OrderingFilter ().filter_queryset (
890+ self .request , queryset , self
891+ )
892+
893+ return self .get_response_for_queryset (queryset )
894+
840895 @drf .decorators .action (
841896 detail = True ,
842897 methods = ["get" ],
0 commit comments