mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge pull request #2147 from paperless-ngx/feature-permissions
Feature: multi-user permissions
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<div class="input-group-text" i18n>of {{previewNumPages}}</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-danger me-2 ms-auto" (click)="delete()">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger me-2 ms-auto" (click)="delete()" [disabled]="!userIsOwner">
|
||||
<svg class="buttonicon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#trash" />
|
||||
</svg><span class="d-none d-lg-inline ps-1" i18n>Delete</span>
|
||||
@@ -20,7 +20,7 @@
|
||||
</a>
|
||||
|
||||
<div class="btn-group" ngbDropdown role="group" *ngIf="metadata?.has_archive_version">
|
||||
<button class="btn btn-sm btn-outline-primary dropdown-toggle-split" ngbDropdownToggle></button>
|
||||
<button class="btn btn-sm btn-outline-primary dropdown-toggle" ngbDropdownToggle></button>
|
||||
<div class="dropdown-menu shadow" ngbDropdownMenu>
|
||||
<a ngbDropdownItem [href]="downloadOriginalUrl" i18n>Download original</a>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-outline-primary me-2" (click)="redoOcr()">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary me-2" (click)="redoOcr()" [disabled]="!userCanEdit">
|
||||
<svg class="buttonicon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#arrow-counterclockwise" />
|
||||
</svg><span class="d-none d-lg-inline ps-1" i18n>Redo OCR</span>
|
||||
@@ -170,19 +170,31 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
<li [ngbNavItem]="5" *ngIf="commentsEnabled">
|
||||
<a ngbNavLink i18n>Comments</a>
|
||||
<ng-template ngbNavContent>
|
||||
<app-document-comments [documentId]="documentId"></app-document-comments>
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
<li [ngbNavItem]="6" *appIfOwner="document">
|
||||
<a ngbNavLink i18n>Permissions</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div class="mb-3">
|
||||
<app-permissions-form [users]="users" formControlName="permissions_form"></app-permissions-form>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="discard()" i18n [disabled]="networkActive || (isDirty$ | async) !== true">Discard</button>
|
||||
<button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="networkActive || (isDirty$ | async) !== true || error">Save & next</button>
|
||||
<button type="submit" class="btn btn-primary" i18n [disabled]="networkActive || (isDirty$ | async) !== true || error">Save</button>
|
||||
<ng-container>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="discard()" i18n [disabled]="!userCanEdit || networkActive || (isDirty$ | async) !== true">Discard</button>
|
||||
<button type="button" class="btn btn-outline-primary" (click)="saveEditNext()" *ngIf="hasNext()" i18n [disabled]="!userCanEdit || networkActive || (isDirty$ | async) !== true || error">Save & next</button>
|
||||
<button type="submit" class="btn btn-primary" *appIfPermissions="{ action: PermissionAction.Change, type: PermissionType.Document }" i18n [disabled]="!userCanEdit || networkActive || (isDirty$ | async) !== true || error">Save</button>
|
||||
</ng-container>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@@ -35,6 +35,13 @@ import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||
import { StoragePathEditDialogComponent } from '../common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||
import {
|
||||
PermissionAction,
|
||||
PermissionsService,
|
||||
PermissionType,
|
||||
} from 'src/app/services/permissions.service'
|
||||
import { PaperlessUser } from 'src/app/data/paperless-user'
|
||||
import { UserService } from 'src/app/services/rest/user.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-document-detail',
|
||||
@@ -58,6 +65,7 @@ export class DocumentDetailComponent
|
||||
document: PaperlessDocument
|
||||
metadata: PaperlessDocumentMetadata
|
||||
suggestions: PaperlessDocumentSuggestions
|
||||
users: PaperlessUser[]
|
||||
|
||||
title: string
|
||||
titleSubject: Subject<string> = new Subject()
|
||||
@@ -78,6 +86,7 @@ export class DocumentDetailComponent
|
||||
storage_path: new FormControl(),
|
||||
archive_serial_number: new FormControl(),
|
||||
tags: new FormControl([]),
|
||||
permissions_form: new FormControl(null),
|
||||
})
|
||||
|
||||
previewCurrentPage: number = 1
|
||||
@@ -106,6 +115,9 @@ export class DocumentDetailComponent
|
||||
}
|
||||
}
|
||||
|
||||
PermissionAction = PermissionAction
|
||||
PermissionType = PermissionType
|
||||
|
||||
constructor(
|
||||
private documentsService: DocumentService,
|
||||
private route: ActivatedRoute,
|
||||
@@ -118,7 +130,9 @@ export class DocumentDetailComponent
|
||||
private documentTitlePipe: DocumentTitlePipe,
|
||||
private toastService: ToastService,
|
||||
private settings: SettingsService,
|
||||
private storagePathService: StoragePathService
|
||||
private storagePathService: StoragePathService,
|
||||
private permissionsService: PermissionsService,
|
||||
private userService: UserService
|
||||
) {}
|
||||
|
||||
titleKeyUp(event) {
|
||||
@@ -147,7 +161,13 @@ export class DocumentDetailComponent
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe(() => {
|
||||
this.error = null
|
||||
Object.assign(this.document, this.documentForm.value)
|
||||
const docValues = Object.assign({}, this.documentForm.value)
|
||||
docValues['owner'] =
|
||||
this.documentForm.get('permissions_form').value['owner']
|
||||
docValues['set_permissions'] =
|
||||
this.documentForm.get('permissions_form').value['set_permissions']
|
||||
delete docValues['permissions_form']
|
||||
Object.assign(this.document, docValues)
|
||||
})
|
||||
|
||||
this.correspondentService
|
||||
@@ -165,6 +185,11 @@ export class DocumentDetailComponent
|
||||
.pipe(first())
|
||||
.subscribe((result) => (this.storagePaths = result.results))
|
||||
|
||||
this.userService
|
||||
.listAll()
|
||||
.pipe(first())
|
||||
.subscribe((result) => (this.users = result.results))
|
||||
|
||||
this.route.paramMap
|
||||
.pipe(
|
||||
takeUntil(this.unsubscribeNotifier),
|
||||
@@ -232,6 +257,10 @@ export class DocumentDetailComponent
|
||||
storage_path: doc.storage_path,
|
||||
archive_serial_number: doc.archive_serial_number,
|
||||
tags: [...doc.tags],
|
||||
permissions_form: {
|
||||
owner: doc.owner,
|
||||
set_permissions: doc.permissions,
|
||||
},
|
||||
})
|
||||
|
||||
this.isDirty$ = dirtyCheck(
|
||||
@@ -286,7 +315,14 @@ export class DocumentDetailComponent
|
||||
},
|
||||
})
|
||||
this.title = this.documentTitlePipe.transform(doc.title)
|
||||
this.documentForm.patchValue(doc)
|
||||
const docFormValues = Object.assign({}, doc)
|
||||
docFormValues['permissions_form'] = {
|
||||
owner: doc.owner,
|
||||
set_permissions: doc.permissions,
|
||||
}
|
||||
|
||||
this.documentForm.patchValue(docFormValues, { emitEvent: false })
|
||||
if (!this.userCanEdit) this.documentForm.disable()
|
||||
}
|
||||
|
||||
createDocumentType(newName: string) {
|
||||
@@ -378,7 +414,7 @@ export class DocumentDetailComponent
|
||||
.update(this.document)
|
||||
.pipe(first())
|
||||
.subscribe({
|
||||
next: (result) => {
|
||||
next: () => {
|
||||
this.close()
|
||||
this.networkActive = false
|
||||
this.error = null
|
||||
@@ -564,6 +600,36 @@ export class DocumentDetailComponent
|
||||
}
|
||||
|
||||
get commentsEnabled(): boolean {
|
||||
return this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED)
|
||||
return (
|
||||
this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED) &&
|
||||
this.permissionsService.currentUserCan(
|
||||
PermissionAction.View,
|
||||
PermissionType.Document
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
get userIsOwner(): boolean {
|
||||
let doc: PaperlessDocument = Object.assign({}, this.document)
|
||||
// dont disable while editing
|
||||
if (this.document && this.store?.value.owner) {
|
||||
doc.owner = this.store?.value.owner
|
||||
}
|
||||
return !this.document || this.permissionsService.currentUserOwnsObject(doc)
|
||||
}
|
||||
|
||||
get userCanEdit(): boolean {
|
||||
let doc: PaperlessDocument = Object.assign({}, this.document)
|
||||
// dont disable while editing
|
||||
if (this.document && this.store?.value.owner) {
|
||||
doc.owner = this.store?.value.owner
|
||||
}
|
||||
return (
|
||||
!this.document ||
|
||||
this.permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.Change,
|
||||
doc
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user