From e46f4a5aaae41bc3081b5aa5bed7ccc44c674b73 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 13 Apr 2026 12:43:06 -0700 Subject: [PATCH] Fix: do not submit permissions for non-owners (#12571) --- .../edit-dialog/edit-dialog.component.spec.ts | 23 +++++++++++++++++++ .../edit-dialog/edit-dialog.component.ts | 20 +++++++++++----- .../user-edit-dialog.component.ts | 2 -- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts index fa845f369..1dbd54edf 100644 --- a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.spec.ts @@ -26,6 +26,7 @@ import { } from 'src/app/data/matching-model' import { Tag } from 'src/app/data/tag' import { SETTINGS_KEYS } from 'src/app/data/ui-settings' +import { PermissionsService } from 'src/app/services/permissions.service' import { TagService } from 'src/app/services/rest/tag.service' import { UserService } from 'src/app/services/rest/user.service' import { SettingsService } from 'src/app/services/settings.service' @@ -87,6 +88,7 @@ describe('EditDialogComponent', () => { let component: TestComponent let fixture: ComponentFixture let tagService: TagService + let permissionsService: PermissionsService let settingsService: SettingsService let activeModal: NgbActiveModal let httpTestingController: HttpTestingController @@ -118,8 +120,10 @@ describe('EditDialogComponent', () => { }).compileComponents() tagService = TestBed.inject(TagService) + permissionsService = TestBed.inject(PermissionsService) settingsService = TestBed.inject(SettingsService) settingsService.currentUser = currentUser + permissionsService.initialize([], currentUser as any) activeModal = TestBed.inject(NgbActiveModal) httpTestingController = TestBed.inject(HttpTestingController) @@ -226,6 +230,25 @@ describe('EditDialogComponent', () => { expect(updateSpy).toHaveBeenCalled() }) + it('should not submit owner or permissions for non-owner edits', () => { + component.object = tag + component.dialogMode = EditDialogMode.EDIT + component.ngOnInit() + + component.objectForm.get('name').setValue('Updated tag') + component.save() + + const req = httpTestingController.expectOne( + `${environment.apiBaseUrl}tags/${tag.id}/` + ) + expect(req.request.method).toEqual('PUT') + expect(req.request.body.name).toEqual('Updated tag') + expect(req.request.body.owner).toEqual(tag.owner) + expect(req.request.body.set_permissions).toBeUndefined() + + req.flush({}) + }) + it('should create an object on save in edit mode', () => { const createSpy = jest.spyOn(tagService, 'create') component.dialogMode = EditDialogMode.CREATE diff --git a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts index 75534a777..3110f3090 100644 --- a/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/edit-dialog.component.ts @@ -18,6 +18,7 @@ import { ObjectWithId } from 'src/app/data/object-with-id' import { ObjectWithPermissions } from 'src/app/data/object-with-permissions' import { SETTINGS_KEYS } from 'src/app/data/ui-settings' import { User } from 'src/app/data/user' +import { PermissionsService } from 'src/app/services/permissions.service' import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service' import { UserService } from 'src/app/services/rest/user.service' import { SettingsService } from 'src/app/services/settings.service' @@ -42,6 +43,7 @@ export abstract class EditDialogComponent< protected activeModal = inject(NgbActiveModal) protected userService = inject(UserService) protected settingsService = inject(SettingsService) + protected permissionsService = inject(PermissionsService) users: User[] @@ -69,10 +71,6 @@ export abstract class EditDialogComponent< ngOnInit(): void { if (this.object != null && this.dialogMode !== EditDialogMode.CREATE) { - if ((this.object as ObjectWithPermissions).permissions) { - this.object['set_permissions'] = this.object['permissions'] - } - this.object['permissions_form'] = { owner: (this.object as ObjectWithPermissions).owner, set_permissions: (this.object as ObjectWithPermissions).permissions, @@ -151,18 +149,28 @@ export abstract class EditDialogComponent< return Object.assign({}, this.objectForm.value) } + protected shouldSubmitPermissions(): boolean { + return ( + this.dialogMode === EditDialogMode.CREATE || + this.permissionsService.currentUserOwnsObject(this.object) + ) + } + save() { this.error = null const formValues = this.getFormValues() const permissionsObject: PermissionsFormObject = this.objectForm.get('permissions_form')?.value - if (permissionsObject) { + if (permissionsObject && this.shouldSubmitPermissions()) { formValues.owner = permissionsObject.owner formValues.set_permissions = permissionsObject.set_permissions - delete formValues.permissions_form } + delete formValues.permissions_form var newObject = Object.assign(Object.assign({}, this.object), formValues) + if (!this.shouldSubmitPermissions()) { + delete newObject['set_permissions'] + } var serverResponse: Observable switch (this.dialogMode) { case EditDialogMode.CREATE: diff --git a/src-ui/src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts index 1c87a4308..215b2c137 100644 --- a/src-ui/src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/user-edit-dialog/user-edit-dialog.component.ts @@ -9,7 +9,6 @@ import { first } from 'rxjs' import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component' import { Group } from 'src/app/data/group' import { User } from 'src/app/data/user' -import { PermissionsService } from 'src/app/services/permissions.service' import { GroupService } from 'src/app/services/rest/group.service' import { UserService } from 'src/app/services/rest/user.service' import { SettingsService } from 'src/app/services/settings.service' @@ -39,7 +38,6 @@ export class UserEditDialogComponent implements OnInit { private toastService = inject(ToastService) - private permissionsService = inject(PermissionsService) private groupsService: GroupService groups: Group[]