]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Bulk editor enabling/disabling by permissions
authorMichael Shamoon <4887959+shamoon@users.noreply.github.com>
Thu, 8 Dec 2022 10:22:58 +0000 (02:22 -0800)
committerMichael Shamoon <4887959+shamoon@users.noreply.github.com>
Thu, 8 Dec 2022 10:22:58 +0000 (02:22 -0800)
src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.html
src-ui/src/app/components/common/filterable-dropdown/filterable-dropdown.component.ts
src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.html
src-ui/src/app/components/common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component.ts
src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.html
src-ui/src/app/components/document-list/bulk-editor/bulk-editor.component.ts

index 9ce3c8da22535bc07c542667b7fd6709af391840..25bc14ddf6f209962b5d61ab0f31478effeaccc0 100644 (file)
@@ -1,5 +1,5 @@
 <div class="btn-group w-100" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
-  <button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="!editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'">
+  <button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="!editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'" [disabled]="disabled">
     <svg class="toolbaricon" fill="currentColor">
       <use attr.xlink:href="assets/bootstrap-icons.svg#{{icon}}" />
     </svg>
       </div>
       <div *ngIf="selectionModel.items" class="items">
         <ng-container *ngFor="let item of selectionModel.itemsSorted | filter: filterText">
-          <app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)" (exclude)="excludeClicked(item.id)"></app-toggleable-dropdown-button>
+          <app-toggleable-dropdown-button *ngIf="allowSelectNone || item.id" [item]="item" [state]="selectionModel.get(item.id)" (toggle)="selectionModel.toggle(item.id)" (exclude)="excludeClicked(item.id)" [disabled]="disabled"></app-toggleable-dropdown-button>
         </ng-container>
       </div>
-      <button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!modelIsDirty">
+      <button *ngIf="editing" class="list-group-item list-group-item-action bg-light" (click)="applyClicked()" [disabled]="!modelIsDirty || disabled">
         <small class="ms-2" [ngClass]="{'fw-bold': modelIsDirty}" i18n>Apply</small>
         <svg width="1.5em" height="1em" viewBox="0 0 16 16" fill="currentColor">
           <use xlink:href="assets/bootstrap-icons.svg#arrow-right" />
index 373f0aa5dc0cb1c9b2a80c4b25d015bff3000cb7..3b54b11201d2cd7736dca1d84b029a732d742e51 100644 (file)
@@ -317,6 +317,9 @@ export class FilterableDropdownComponent {
   @Input()
   applyOnClose = false
 
+  @Input()
+  disabled = false
+
   @Output()
   apply = new EventEmitter<ChangedItems>()
 
index 8e4860a7d794d333418457d5448600d120994610..f8df1d4eb25bfb5bb6bdb9c8c438bd93af56e02f 100644 (file)
@@ -1,4 +1,4 @@
-<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="toggleItem($event)">
+<button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="toggleItem($event)" [disabled]="disabled">
   <div class="selected-icon me-1">
     <ng-container *ngIf="isChecked()">
       <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-check" viewBox="0 0 16 16">
index 6108245273454d9f14909f8f46f7fb687ea52122..32ec671b177a60f0265600ffeef22a655a94ab8f 100644 (file)
@@ -23,6 +23,9 @@ export class ToggleableDropdownButtonComponent {
   @Input()
   count: number
 
+  @Input()
+  disabled: boolean = false
+
   @Output()
   toggle = new EventEmitter()
 
index 2b6209dda4fbebfc4dc841b1045c5680eb6256a4..cb4e200dd86da0af1d6212b077624a6f549400a9 100644 (file)
@@ -28,6 +28,7 @@
       <app-filterable-dropdown class="me-2 me-md-3" title="Tags" icon="tag-fill" i18n-title
         filterPlaceholder="Filter tags" i18n-filterPlaceholder
         [items]="tags"
+        [disabled]="!userCanEditAll"
         [editing]="true"
         [multiple]="true"
         [applyOnClose]="applyOnClose"
@@ -38,6 +39,7 @@
       <app-filterable-dropdown class="me-2 me-md-3" title="Correspondent" icon="person-fill" i18n-title
         filterPlaceholder="Filter correspondents" i18n-filterPlaceholder
         [items]="correspondents"
+        [disabled]="!userCanEditAll"
         [editing]="true"
         [applyOnClose]="applyOnClose"
         (open)="openCorrespondentDropdown()"
@@ -47,6 +49,7 @@
       <app-filterable-dropdown class="me-2 me-md-3" title="Document type" icon="file-earmark-fill" i18n-title
         filterPlaceholder="Filter document types" i18n-filterPlaceholder
         [items]="documentTypes"
+        [disabled]="!userCanEditAll"
         [editing]="true"
         [applyOnClose]="applyOnClose"
         (open)="openDocumentTypeDropdown()"
@@ -56,6 +59,7 @@
       <app-filterable-dropdown class="me-2 me-md-3" title="Storage path" icon="folder-fill" i18n-title
         filterPlaceholder="Filter storage paths" i18n-filterPlaceholder
         [items]="storagePaths"
+        [disabled]="!userCanEditAll"
         [editing]="true"
         [applyOnClose]="applyOnClose"
         (open)="openStoragePathDropdown()"
@@ -67,7 +71,7 @@
   <div class="col-auto ms-auto mb-2 mb-xl-0 d-flex">
     <div class="btn-toolbar me-2">
 
-      <button type="button" class="btn btn-sm btn-outline-primary me-2" (click)="setPermissions()">
+      <button type="button" class="btn btn-sm btn-outline-primary me-2" (click)="setPermissions()" [disabled]="!userOwnsAll">
         <svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
           <use xlink:href="assets/bootstrap-icons.svg#person-fill-lock" />
         </svg>&nbsp;<ng-container i18n>Permissions</ng-container>
               <span class="visually-hidden">Preparing download...</span>
             </div>
           </button>
-          <button ngbDropdownItem (click)="redoOcrSelected()" i18n>Redo OCR</button>
+          <button ngbDropdownItem (click)="redoOcrSelected()" [disabled]="!userCanEditAll" i18n>Redo OCR</button>
         </div>
       </div>
 
-    <button type="button" class="btn btn-sm btn-outline-danger" (click)="applyDelete()" *ifPermissions="{ action: PermissionAction.Delete, type: PermissionType.Document }">
+    <button type="button" class="btn btn-sm btn-outline-danger" (click)="applyDelete()" *ifPermissions="{ action: PermissionAction.Delete, type: PermissionType.Document }" [disabled]="!userOwnsAll">
       <svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor">
         <use xlink:href="assets/bootstrap-icons.svg#trash" />
       </svg>&nbsp;<ng-container i18n>Delete</ng-container>
index b529b79205c5357a713145aea1977fd80a82a88a..32ad28ba78248c34229754503c8ada773896e940 100644 (file)
@@ -27,6 +27,7 @@ import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
 import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
 import { ComponentWithPermissions } from '../../with-permissions/with-permissions.component'
 import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
+import { PermissionsService } from 'src/app/services/permissions.service'
 
 @Component({
   selector: 'app-bulk-editor',
@@ -55,7 +56,8 @@ export class BulkEditorComponent extends ComponentWithPermissions {
     private openDocumentService: OpenDocumentsService,
     private settings: SettingsService,
     private toastService: ToastService,
-    private storagePathService: StoragePathService
+    private storagePathService: StoragePathService,
+    private permissionService: PermissionsService
   ) {
     super()
   }
@@ -67,6 +69,25 @@ export class BulkEditorComponent extends ComponentWithPermissions {
     SETTINGS_KEYS.BULK_EDIT_CONFIRMATION_DIALOGS
   )
 
+  get userCanEditAll(): boolean {
+    let canEdit: boolean = true
+    const docs = this.list.documents.filter((d) => this.list.selected.has(d.id))
+    canEdit = docs.every((d) =>
+      this.permissionService.currentUserHasObjectPermissions(
+        this.PermissionAction.Change,
+        d
+      )
+    )
+    return canEdit
+  }
+
+  get userOwnsAll(): boolean {
+    let ownsAll: boolean = true
+    const docs = this.list.documents.filter((d) => this.list.selected.has(d.id))
+    ownsAll = docs.every((d) => this.permissionService.currentUserOwnsObject(d))
+    return ownsAll
+  }
+
   ngOnInit() {
     this.tagService
       .listAll()