Repository: paperless-ngx/paperless-ngx

Issue:
[BUG] Dashboard counts documents from inbox tags, user are unable to access.
### Description

I setup paperless-ngx for my wife and me. I bought a scan to ftp document scanner. I set up **three** users:

1. admin
2. husband
3. wife

I created **two inbox tags**, one for her and one for me. 
![grafik](https://github.com/paperless-ngx/paperless-ngx/assets/12057348/5678c029-0326-44ad-80ee-544cfba6f751)
![grafik](https://github.com/paperless-ngx/paperless-ngx/assets/12057348/95732ffb-50ad-46df-9e75-2eb314358f9d)

Our goal is that everybody has full access to all documents, should anything unexpected ever happen.
Therefore, I set the following default permissions in the settings and in the workflow:
![grafik](https://github.com/paperless-ngx/paperless-ngx/assets/12057348/0288b333-bfc5-43ec-a2cd-c55d30b8973f)
![grafik](https://github.com/paperless-ngx/paperless-ngx/assets/12057348/b27fa548-7d02-4934-bd17-d134c972c843)

Now I expected the workflow to be, that if either she or I scan a document, the workflow assigns the owner, so we can easily see our own documents, but could access each others, if we ever must. That works very well, except one thing:

Whenever one of us scans a document, **both** of our dashboards show documents waiting in the inbox, although we don't have access to each other's inbox tag. I was under the assumption, that when I isolate the tags to our specific users, the dashboard notifier wouldn't count documents for each other's inbox. 

Example: 

1. I (husband) scanned a document.
2. **Her** dashboard shows one document in the inbox:
![grafik](https://github.com/paperless-ngx/paperless-ngx/assets/12057348/f8e51b2b-7f33-4f9f-9b89-3e0d9b05ec7a)
3. When she clicks the link, it opens a filter for **her** tag, with empty filter results:
![grafik](https://github.com/paperless-ngx/paperless-ngx/assets/12057348/f1d8dc91-ee9a-42eb-add7-61526f232fff)
4. Which of course makes sense, because the dashboard link creates a filter view for her inbox tag(s) because she can't see my tags.
5. Still the dashboards tells her, she has open todos in the inbox.

### Steps to reproduce

1. Create two users, who are not super-user
2. Create two inbox tags, who each belong exclusively to one of the users
3. Create two consume workflows that assign one of the users as owner and set the corresponding inbox tag 
  3b. Alternativ create the documents manually with the inbox tags as super user, the result will be the same.
4. Consume a few documents for each of the users and see that **both** dashboards count for both tags, although the filter from the dashboard link won't show anything. 

### Webserver logs

```bash
I don't think the webserver logs are related to my dashboard issue.
```


### Browser logs

_No response_

### Paperless-ngx version

2.7.2

### Host OS

Debian 12

### Installation method

Docker - official image

### Browser

Firefox

### Configuration changes

_No response_

### Other

_No response_

### Please confirm the following

- [X] I believe this issue is a bug that affects all users of Paperless-ngx, not something specific to my installation.
- [X] I have already searched for relevant existing issues and discussions before opening this report.
- [X] I have updated the title field above with a concise description.


Discussion:
The inbox tag is going to show documents a user can access.  If you are assigning a group to ever incoming document where they have access, that's going to be displayed
I feared that would be the answer. So the dashboard looks at the document's permissions, not at the tag's permissions. Isn't that something that could/should be adjusted? Because it's just not **my** inbox tag, that is notifying me. 

But assumed this is not a bug, then is my design not feasible at all or just wrongly implemented?

1. Two (or more) users.
2. Everybody can access everything, should anybody die. 
3. Documents still have owners, for easy filtering.
4. Separate inboxes, so we don't clutter each other's dashboard inbox.
You should just use a superuser account, or at least have one available as the backup plan. I suppose you could make a feature request about this but I think it is working as intended here. Thanks.
hi @shamoon
First of all, thank you very much for the suggestion, that didn't come to my mind. It's very similar to the concept of Azure break glass accounts. I like that very much. I will create a super-user for my wife and me, which we could use, if one of us dies. 
On the other hand, I will get rid of the **_all_** group on documents, so we won't see each other's documents at all. That should clean up the dashboard and the inbox for us. But I think I will keep the **_all_** group on tags and correspondents, as I see no need to separate that and we can share the base data.

But back to the initial bug report. I don't want to sound rude, and maybe I did a config mistake, but I still don't want to believe this is just okay as it is. 
There still is the situation, that if a document is tagged with an inbox _tag_, you don't have any access to, your inbox counter gets triggered and shows you nothing when clicked. And it's super easy to reproduce. I understand the initial answer from @stumpylog that the dashboard box shows all documents I could access with any tag that is an inbox tag. But that doesn't take into account, if I have access to that particular inbox _**tag**_. And I find it very strange, that that is considered _working as intended_. 

So I guess I have to make a Feature Request, that the dashboard counter only counts documents that are:

1. Accessible for the user through permissions (Already the case)
2. Tagged as inbox (Already the case)
**3. The specific inbox tag is Accessible for the user through permissions (not as of today, hence this issue)**

~~I will create the feature request now.~~ The Feature Request is created at #6667 

Resolving patch:
diff --git a/src/documents/views.py b/src/documents/views.py
--- a/src/documents/views.py
+++ b/src/documents/views.py
@@ -1391,7 +1391,9 @@ def get(self, request, format=None):
         inbox_tag = tags.filter(is_inbox_tag=True)
 
         documents_inbox = (
-            documents.filter(tags__is_inbox_tag=True).distinct().count()
+            documents.filter(tags__is_inbox_tag=True, tags__id__in=tags)
+            .distinct()
+            .count()
             if inbox_tag.exists()
             else None
         )


Test patch:
diff --git a/src/documents/tests/test_api_documents.py b/src/documents/tests/test_api_documents.py
--- a/src/documents/tests/test_api_documents.py
+++ b/src/documents/tests/test_api_documents.py
@@ -930,6 +930,45 @@ def test_statistics_no_inbox_tag(self):
         self.assertEqual(response.data["documents_inbox"], None)
         self.assertEqual(response.data["inbox_tag"], None)
 
+    def test_statistics_multiple_users(self):
+        """
+        GIVEN:
+            - Inbox tags with different owners and documents that are accessible to different users
+        WHEN:
+            - Statistics are requested
+        THEN:
+            - Statistics only include inbox counts for tags accessible by the user
+        """
+        u1 = User.objects.create_user("user1")
+        u2 = User.objects.create_user("user2")
+        inbox_tag_u1 = Tag.objects.create(name="inbox_u1", is_inbox_tag=True, owner=u1)
+        Tag.objects.create(name="inbox_u2", is_inbox_tag=True, owner=u2)
+        doc_u1 = Document.objects.create(
+            title="none1",
+            checksum="A",
+            mime_type="application/pdf",
+            owner=u1,
+        )
+        doc2_u1 = Document.objects.create(
+            title="none2",
+            checksum="B",
+            mime_type="application/pdf",
+        )
+        doc_u1.tags.add(inbox_tag_u1)
+        doc2_u1.save()
+        doc2_u1.tags.add(inbox_tag_u1)
+        doc2_u1.save()
+
+        self.client.force_authenticate(user=u1)
+        response = self.client.get("/api/statistics/")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data["documents_inbox"], 2)
+
+        self.client.force_authenticate(user=u2)
+        response = self.client.get("/api/statistics/")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data["documents_inbox"], 0)
+
     def test_upload(self):
         self.consume_file_mock.return_value = celery.result.AsyncResult(
             id=str(uuid.uuid4()),