mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Merge pull request #3103 from paperless-ngx/fix/issue-3101
Fix: respect permissions for matching suggestions
This commit is contained in:
		@@ -56,8 +56,6 @@ describe('settings', () => {
 | 
			
		||||
            'GET',
 | 
			
		||||
            'http://localhost:8000/api/mail_accounts/*',
 | 
			
		||||
            (req) => {
 | 
			
		||||
              console.log(req, this.newMailAccounts)
 | 
			
		||||
 | 
			
		||||
              let response = { ...mailAccountsJson }
 | 
			
		||||
              if (this.newMailAccounts.length) {
 | 
			
		||||
                response.results = response.results.concat(this.newMailAccounts)
 | 
			
		||||
@@ -142,7 +140,7 @@ describe('settings', () => {
 | 
			
		||||
    cy.get('app-saved-view-widget').contains('Inbox').should('not.exist')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should show a list of mail accounts & rules & support creation', () => {
 | 
			
		||||
  it('should show a list of mail accounts & support creation', () => {
 | 
			
		||||
    cy.contains('a', 'Mail').click()
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
 | 
			
		||||
    cy.contains('button', 'Add Account').click()
 | 
			
		||||
@@ -162,6 +160,13 @@ describe('settings', () => {
 | 
			
		||||
      .wait('@getAccounts')
 | 
			
		||||
    cy.contains('Saved account')
 | 
			
		||||
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 6)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should show a list of mail rules & support creation', () => {
 | 
			
		||||
    cy.contains('a', 'Mail').click()
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
 | 
			
		||||
 | 
			
		||||
    cy.wait(1000)
 | 
			
		||||
    cy.contains('button', 'Add Rule').click()
 | 
			
		||||
    cy.contains('Create new mail rule')
 | 
			
		||||
@@ -177,6 +182,6 @@ describe('settings', () => {
 | 
			
		||||
      .wait('@getRules')
 | 
			
		||||
    cy.contains('Saved rule').wait(1000)
 | 
			
		||||
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 7)
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 6)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -27,21 +27,31 @@ export class SelectComponent extends AbstractInputComponent<number> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _items: any[]
 | 
			
		||||
  privateItems: any[] = []
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  set items(items) {
 | 
			
		||||
    if (this.value && items.find((i) => i.id === this.value) === undefined) {
 | 
			
		||||
      items.push({
 | 
			
		||||
        id: this.value,
 | 
			
		||||
    this._items = items
 | 
			
		||||
    if (this.value) this.checkForPrivateItem(this.value)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  writeValue(newValue: any): void {
 | 
			
		||||
    if (newValue && this._items) this.checkForPrivateItem(newValue)
 | 
			
		||||
    super.writeValue(newValue)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  checkForPrivateItem(value) {
 | 
			
		||||
    if (this._items.find((i) => i.id === value) === undefined) {
 | 
			
		||||
      this.privateItems.push({
 | 
			
		||||
        id: value,
 | 
			
		||||
        name: $localize`Private`,
 | 
			
		||||
        private: true,
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    this._items = items
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get items(): any[] {
 | 
			
		||||
    return this._items
 | 
			
		||||
    return this._items?.concat(this.privateItems)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ from documents.models import DocumentType
 | 
			
		||||
from documents.models import MatchingModel
 | 
			
		||||
from documents.models import StoragePath
 | 
			
		||||
from documents.models import Tag
 | 
			
		||||
from documents.permissions import get_objects_for_user_owner_aware
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("paperless.matching")
 | 
			
		||||
@@ -19,40 +20,64 @@ def log_reason(matching_model, document, reason):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_correspondents(document, classifier):
 | 
			
		||||
def match_correspondents(document, classifier, user=None):
 | 
			
		||||
    pred_id = classifier.predict_correspondent(document.content) if classifier else None
 | 
			
		||||
 | 
			
		||||
    correspondents = Correspondent.objects.all()
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        correspondents = get_objects_for_user_owner_aware(
 | 
			
		||||
            user,
 | 
			
		||||
            "documents.view_correspondent",
 | 
			
		||||
            Correspondent,
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        correspondents = Correspondent.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
        filter(lambda o: matches(o, document) or o.pk == pred_id, correspondents),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_document_types(document, classifier):
 | 
			
		||||
def match_document_types(document, classifier, user=None):
 | 
			
		||||
    pred_id = classifier.predict_document_type(document.content) if classifier else None
 | 
			
		||||
 | 
			
		||||
    document_types = DocumentType.objects.all()
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        document_types = get_objects_for_user_owner_aware(
 | 
			
		||||
            user,
 | 
			
		||||
            "documents.view_documenttype",
 | 
			
		||||
            DocumentType,
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        document_types = DocumentType.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
        filter(lambda o: matches(o, document) or o.pk == pred_id, document_types),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_tags(document, classifier):
 | 
			
		||||
def match_tags(document, classifier, user=None):
 | 
			
		||||
    predicted_tag_ids = classifier.predict_tags(document.content) if classifier else []
 | 
			
		||||
 | 
			
		||||
    tags = Tag.objects.all()
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        tags = get_objects_for_user_owner_aware(user, "documents.view_tag", Tag)
 | 
			
		||||
    else:
 | 
			
		||||
        tags = Tag.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
        filter(lambda o: matches(o, document) or o.pk in predicted_tag_ids, tags),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_storage_paths(document, classifier):
 | 
			
		||||
def match_storage_paths(document, classifier, user=None):
 | 
			
		||||
    pred_id = classifier.predict_storage_path(document.content) if classifier else None
 | 
			
		||||
 | 
			
		||||
    storage_paths = StoragePath.objects.all()
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        storage_paths = get_objects_for_user_owner_aware(
 | 
			
		||||
            user,
 | 
			
		||||
            "documents.view_storagepath",
 | 
			
		||||
            StoragePath,
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        storage_paths = StoragePath.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
        filter(
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ from django.contrib.auth.models import User
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from guardian.models import GroupObjectPermission
 | 
			
		||||
from guardian.shortcuts import assign_perm
 | 
			
		||||
from guardian.shortcuts import get_objects_for_user
 | 
			
		||||
from guardian.shortcuts import get_users_with_perms
 | 
			
		||||
from guardian.shortcuts import remove_perm
 | 
			
		||||
from rest_framework.permissions import BasePermission
 | 
			
		||||
@@ -101,3 +102,15 @@ def set_permissions_for_object(permissions, object):
 | 
			
		||||
                        group,
 | 
			
		||||
                        object,
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_objects_for_user_owner_aware(user, perms, Model):
 | 
			
		||||
    objects_owned = Model.objects.filter(owner=user)
 | 
			
		||||
    objects_unowned = Model.objects.filter(owner__isnull=True)
 | 
			
		||||
    objects_with_perms = get_objects_for_user(
 | 
			
		||||
        user=user,
 | 
			
		||||
        perms=perms,
 | 
			
		||||
        klass=Model,
 | 
			
		||||
        accept_global_perms=False,
 | 
			
		||||
    )
 | 
			
		||||
    return objects_owned | objects_unowned | objects_with_perms
 | 
			
		||||
 
 | 
			
		||||
@@ -401,12 +401,16 @@ class DocumentViewSet(
 | 
			
		||||
 | 
			
		||||
        return Response(
 | 
			
		||||
            {
 | 
			
		||||
                "correspondents": [c.id for c in match_correspondents(doc, classifier)],
 | 
			
		||||
                "tags": [t.id for t in match_tags(doc, classifier)],
 | 
			
		||||
                "document_types": [
 | 
			
		||||
                    dt.id for dt in match_document_types(doc, classifier)
 | 
			
		||||
                "correspondents": [
 | 
			
		||||
                    c.id for c in match_correspondents(doc, classifier, request.user)
 | 
			
		||||
                ],
 | 
			
		||||
                "tags": [t.id for t in match_tags(doc, classifier, request.user)],
 | 
			
		||||
                "document_types": [
 | 
			
		||||
                    dt.id for dt in match_document_types(doc, classifier, request.user)
 | 
			
		||||
                ],
 | 
			
		||||
                "storage_paths": [
 | 
			
		||||
                    dt.id for dt in match_storage_paths(doc, classifier, request.user)
 | 
			
		||||
                ],
 | 
			
		||||
                "storage_paths": [dt.id for dt in match_storage_paths(doc, classifier)],
 | 
			
		||||
                "dates": [
 | 
			
		||||
                    date.strftime("%Y-%m-%d") for date in dates if date is not None
 | 
			
		||||
                ],
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user