mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Merge pull request #3347 from paperless-ngx/fix/issue-3346
Fix: default frontend to current owner, allow setting no owner on create
This commit is contained in:
		| @@ -6,6 +6,7 @@ import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' | |||||||
| import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' | import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent' | ||||||
| import { CorrespondentService } from 'src/app/services/rest/correspondent.service' | import { CorrespondentService } from 'src/app/services/rest/correspondent.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-correspondent-edit-dialog', |   selector: 'app-correspondent-edit-dialog', | ||||||
| @@ -16,9 +17,10 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl | |||||||
|   constructor( |   constructor( | ||||||
|     service: CorrespondentService, |     service: CorrespondentService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getCreateTitle() { |   getCreateTitle() { | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' | |||||||
| import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' | import { PaperlessDocumentType } from 'src/app/data/paperless-document-type' | ||||||
| import { DocumentTypeService } from 'src/app/services/rest/document-type.service' | import { DocumentTypeService } from 'src/app/services/rest/document-type.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-document-type-edit-dialog', |   selector: 'app-document-type-edit-dialog', | ||||||
| @@ -16,9 +17,10 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent<Paperle | |||||||
|   constructor( |   constructor( | ||||||
|     service: DocumentTypeService, |     service: DocumentTypeService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getCreateTitle() { |   getCreateTitle() { | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ import { PaperlessUser } from 'src/app/data/paperless-user' | |||||||
| import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service' | import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
| import { PermissionsFormObject } from '../input/permissions/permissions-form/permissions-form.component' | import { PermissionsFormObject } from '../input/permissions/permissions-form/permissions-form.component' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Directive() | @Directive() | ||||||
| export abstract class EditDialogComponent< | export abstract class EditDialogComponent< | ||||||
| @@ -22,7 +23,8 @@ export abstract class EditDialogComponent< | |||||||
|   constructor( |   constructor( | ||||||
|     protected service: AbstractPaperlessService<T>, |     protected service: AbstractPaperlessService<T>, | ||||||
|     private activeModal: NgbActiveModal, |     private activeModal: NgbActiveModal, | ||||||
|     private userService: UserService |     private userService: UserService, | ||||||
|  |     private settingsService: SettingsService | ||||||
|   ) {} |   ) {} | ||||||
|  |  | ||||||
|   users: PaperlessUser[] |   users: PaperlessUser[] | ||||||
| @@ -64,7 +66,14 @@ export abstract class EditDialogComponent< | |||||||
|       this.closeEnabled = true |       this.closeEnabled = true | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|     this.userService.listAll().subscribe((r) => (this.users = r.results)) |     this.userService.listAll().subscribe((r) => { | ||||||
|  |       this.users = r.results | ||||||
|  |       if (this.dialogMode === 'create') { | ||||||
|  |         this.objectForm.get('permissions_form').setValue({ | ||||||
|  |           owner: this.settingsService.currentUser.id, | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getCreateTitle() { |   getCreateTitle() { | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit- | |||||||
| import { PaperlessGroup } from 'src/app/data/paperless-group' | import { PaperlessGroup } from 'src/app/data/paperless-group' | ||||||
| import { GroupService } from 'src/app/services/rest/group.service' | import { GroupService } from 'src/app/services/rest/group.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-group-edit-dialog', |   selector: 'app-group-edit-dialog', | ||||||
| @@ -15,9 +16,10 @@ export class GroupEditDialogComponent extends EditDialogComponent<PaperlessGroup | |||||||
|   constructor( |   constructor( | ||||||
|     service: GroupService, |     service: GroupService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getCreateTitle() { |   getCreateTitle() { | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import { | |||||||
| } from 'src/app/data/paperless-mail-account' | } from 'src/app/data/paperless-mail-account' | ||||||
| import { MailAccountService } from 'src/app/services/rest/mail-account.service' | import { MailAccountService } from 'src/app/services/rest/mail-account.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| const IMAP_SECURITY_OPTIONS = [ | const IMAP_SECURITY_OPTIONS = [ | ||||||
|   { id: IMAPSecurity.None, name: $localize`No encryption` }, |   { id: IMAPSecurity.None, name: $localize`No encryption` }, | ||||||
| @@ -30,9 +31,10 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<Paperles | |||||||
|   constructor( |   constructor( | ||||||
|     service: MailAccountService, |     service: MailAccountService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getCreateTitle() { |   getCreateTitle() { | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ import { DocumentTypeService } from 'src/app/services/rest/document-type.service | |||||||
| import { MailAccountService } from 'src/app/services/rest/mail-account.service' | import { MailAccountService } from 'src/app/services/rest/mail-account.service' | ||||||
| import { MailRuleService } from 'src/app/services/rest/mail-rule.service' | import { MailRuleService } from 'src/app/services/rest/mail-rule.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| const ATTACHMENT_TYPE_OPTIONS = [ | const ATTACHMENT_TYPE_OPTIONS = [ | ||||||
|   { |   { | ||||||
| @@ -115,9 +116,10 @@ export class MailRuleEditDialogComponent extends EditDialogComponent<PaperlessMa | |||||||
|     accountService: MailAccountService, |     accountService: MailAccountService, | ||||||
|     correspondentService: CorrespondentService, |     correspondentService: CorrespondentService, | ||||||
|     documentTypeService: DocumentTypeService, |     documentTypeService: DocumentTypeService, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|  |  | ||||||
|     accountService |     accountService | ||||||
|       .listAll() |       .listAll() | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' | |||||||
| import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path' | import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path' | ||||||
| import { StoragePathService } from 'src/app/services/rest/storage-path.service' | import { StoragePathService } from 'src/app/services/rest/storage-path.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-storage-path-edit-dialog', |   selector: 'app-storage-path-edit-dialog', | ||||||
| @@ -16,9 +17,10 @@ export class StoragePathEditDialogComponent extends EditDialogComponent<Paperles | |||||||
|   constructor( |   constructor( | ||||||
|     service: StoragePathService, |     service: StoragePathService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   get pathHint() { |   get pathHint() { | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import { TagService } from 'src/app/services/rest/tag.service' | |||||||
| import { randomColor } from 'src/app/utils/color' | import { randomColor } from 'src/app/utils/color' | ||||||
| import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' | import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-tag-edit-dialog', |   selector: 'app-tag-edit-dialog', | ||||||
| @@ -17,9 +18,10 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> { | |||||||
|   constructor( |   constructor( | ||||||
|     service: TagService, |     service: TagService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     userService: UserService |     userService: UserService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, userService) |     super(service, activeModal, userService, settingsService) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   getCreateTitle() { |   getCreateTitle() { | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import { PaperlessGroup } from 'src/app/data/paperless-group' | |||||||
| import { PaperlessUser } from 'src/app/data/paperless-user' | import { PaperlessUser } from 'src/app/data/paperless-user' | ||||||
| import { GroupService } from 'src/app/services/rest/group.service' | import { GroupService } from 'src/app/services/rest/group.service' | ||||||
| import { UserService } from 'src/app/services/rest/user.service' | import { UserService } from 'src/app/services/rest/user.service' | ||||||
|  | import { SettingsService } from 'src/app/services/settings.service' | ||||||
|  |  | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-user-edit-dialog', |   selector: 'app-user-edit-dialog', | ||||||
| @@ -23,9 +24,10 @@ export class UserEditDialogComponent | |||||||
|   constructor( |   constructor( | ||||||
|     service: UserService, |     service: UserService, | ||||||
|     activeModal: NgbActiveModal, |     activeModal: NgbActiveModal, | ||||||
|     groupsService: GroupService |     groupsService: GroupService, | ||||||
|  |     settingsService: SettingsService | ||||||
|   ) { |   ) { | ||||||
|     super(service, activeModal, service) |     super(service, activeModal, service, settingsService) | ||||||
|  |  | ||||||
|     groupsService |     groupsService | ||||||
|       .listAll() |       .listAll() | ||||||
|   | |||||||
| @@ -220,6 +220,8 @@ class OwnedObjectSerializer(serializers.ModelSerializer, SetPermissionsMixin): | |||||||
|         permissions = None |         permissions = None | ||||||
|         if "set_permissions" in validated_data: |         if "set_permissions" in validated_data: | ||||||
|             permissions = validated_data.pop("set_permissions") |             permissions = validated_data.pop("set_permissions") | ||||||
|  |             if "user" not in permissions or permissions["user"] is None: | ||||||
|  |                 validated_data["owner"] = None | ||||||
|         instance = super().create(validated_data) |         instance = super().create(validated_data) | ||||||
|         if permissions is not None: |         if permissions is not None: | ||||||
|             self._set_permissions(permissions, instance) |             self._set_permissions(permissions, instance) | ||||||
|   | |||||||
| @@ -3550,6 +3550,77 @@ class TestApiAuth(DirectoriesMixin, APITestCase): | |||||||
|             status.HTTP_404_NOT_FOUND, |             status.HTTP_404_NOT_FOUND, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |     def test_api_set_permissions(self): | ||||||
|  |         """ | ||||||
|  |         GIVEN: | ||||||
|  |             - API request to create an object (Tag) that supplies set_permissions object | ||||||
|  |         WHEN: | ||||||
|  |             - owner is passed as null or as a user id | ||||||
|  |             - view > users is set | ||||||
|  |         THEN: | ||||||
|  |             - Object permissions are set appropriately | ||||||
|  |         """ | ||||||
|  |         user1 = User.objects.create_superuser(username="user1") | ||||||
|  |         user2 = User.objects.create(username="user2") | ||||||
|  |  | ||||||
|  |         self.client.force_authenticate(user1) | ||||||
|  |  | ||||||
|  |         response = self.client.post( | ||||||
|  |             "/api/tags/", | ||||||
|  |             json.dumps( | ||||||
|  |                 { | ||||||
|  |                     "name": "test1", | ||||||
|  |                     "matching_algorithm": MatchingModel.MATCH_AUTO, | ||||||
|  |                     "set_permissions": { | ||||||
|  |                         "owner": None, | ||||||
|  |                         "view": { | ||||||
|  |                             "users": None, | ||||||
|  |                             "groups": None, | ||||||
|  |                         }, | ||||||
|  |                         "change": { | ||||||
|  |                             "users": None, | ||||||
|  |                             "groups": None, | ||||||
|  |                         }, | ||||||
|  |                     }, | ||||||
|  |                 }, | ||||||
|  |             ), | ||||||
|  |             content_type="application/json", | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         self.assertEqual(response.status_code, status.HTTP_201_CREATED) | ||||||
|  |  | ||||||
|  |         tag1 = Tag.objects.filter(name="test1").first() | ||||||
|  |         self.assertEqual(tag1.owner, None) | ||||||
|  |  | ||||||
|  |         response = self.client.post( | ||||||
|  |             "/api/tags/", | ||||||
|  |             json.dumps( | ||||||
|  |                 { | ||||||
|  |                     "name": "test2", | ||||||
|  |                     "matching_algorithm": MatchingModel.MATCH_AUTO, | ||||||
|  |                     "set_permissions": { | ||||||
|  |                         "owner": user1.id, | ||||||
|  |                         "view": { | ||||||
|  |                             "users": [user2.id], | ||||||
|  |                             "groups": None, | ||||||
|  |                         }, | ||||||
|  |                         "change": { | ||||||
|  |                             "users": None, | ||||||
|  |                             "groups": None, | ||||||
|  |                         }, | ||||||
|  |                     }, | ||||||
|  |                 }, | ||||||
|  |             ), | ||||||
|  |             content_type="application/json", | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         tag2 = Tag.objects.filter(name="test2").first() | ||||||
|  |  | ||||||
|  |         from guardian.core import ObjectPermissionChecker | ||||||
|  |  | ||||||
|  |         checker = ObjectPermissionChecker(user2) | ||||||
|  |         self.assertEqual(checker.has_perm("view_tag", tag2), True) | ||||||
|  |  | ||||||
|     def test_dynamic_permissions_fields(self): |     def test_dynamic_permissions_fields(self): | ||||||
|         user1 = User.objects.create_user(username="user1") |         user1 = User.objects.create_user(username="user1") | ||||||
|         user1.user_permissions.add(*Permission.objects.filter(codename="view_document")) |         user1.user_permissions.add(*Permission.objects.filter(codename="view_document")) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon