mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	add share to c/dt/t/sp, refactor share input, ifOwner directive
This commit is contained in:
		| @@ -104,6 +104,8 @@ import localeSr from '@angular/common/locales/sr' | ||||
| import localeSv from '@angular/common/locales/sv' | ||||
| import localeTr from '@angular/common/locales/tr' | ||||
| import localeZh from '@angular/common/locales/zh' | ||||
| import { ShareUserComponent } from './components/common/input/share-user/share-user.component' | ||||
| import { IfOwnerDirective } from './directives/if-owner.directive' | ||||
|  | ||||
| registerLocaleData(localeBe) | ||||
| registerLocaleData(localeCs) | ||||
| @@ -195,6 +197,8 @@ function initializeApp(settings: SettingsService) { | ||||
|     PermissionsSelectComponent, | ||||
|     MailAccountEditDialogComponent, | ||||
|     MailRuleEditDialogComponent, | ||||
|     ShareUserComponent, | ||||
|     IfOwnerDirective, | ||||
|   ], | ||||
|   imports: [ | ||||
|     BrowserModule, | ||||
|   | ||||
| @@ -5,10 +5,20 @@ | ||||
|     </button> | ||||
|   </div> | ||||
|   <div class="modal-body"> | ||||
|  | ||||
|     <app-input-text i18n-title title="Name" formControlName="name" [error]="error?.name"></app-input-text> | ||||
|     <app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|     <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|     <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></app-input-check> | ||||
|  | ||||
|     <div *ifOwner="object.owner"> | ||||
|       <h5 i18n>Permissions</h5> | ||||
|       <div formGroupName="set_permissions"> | ||||
|         <app-share-user type="view" formControlName="view"></app-share-user> | ||||
|         <app-share-user type="change" formControlName="change"></app-share-user> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button> | ||||
|   | ||||
| @@ -30,6 +30,10 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl | ||||
|       matching_algorithm: new FormControl(DEFAULT_MATCHING_ALGORITHM), | ||||
|       match: new FormControl(''), | ||||
|       is_insensitive: new FormControl(true), | ||||
|       set_permissions: new FormGroup({ | ||||
|         view: new FormControl(null), | ||||
|         change: new FormControl(null), | ||||
|       }), | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,14 @@ | ||||
|       <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|       <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|  | ||||
|       <div *ifOwner="object.owner"> | ||||
|         <h5 i18n>Permissions</h5> | ||||
|         <div formGroupName="set_permissions"> | ||||
|           <app-share-user type="view" formControlName="view"></app-share-user> | ||||
|           <app-share-user type="change" formControlName="change"></app-share-user> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|       <button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button> | ||||
|   | ||||
| @@ -30,6 +30,10 @@ export class DocumentTypeEditDialogComponent extends EditDialogComponent<Paperle | ||||
|       matching_algorithm: new FormControl(DEFAULT_MATCHING_ALGORITHM), | ||||
|       match: new FormControl(''), | ||||
|       is_insensitive: new FormControl(true), | ||||
|       set_permissions: new FormGroup({ | ||||
|         view: new FormControl(null), | ||||
|         change: new FormControl(null), | ||||
|       }), | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,11 +4,13 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' | ||||
| import { Observable } from 'rxjs' | ||||
| import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model' | ||||
| import { ObjectWithId } from 'src/app/data/object-with-id' | ||||
| import { ObjectWithPermissions } from 'src/app/data/object-with-permissions' | ||||
| import { AbstractPaperlessService } from 'src/app/services/rest/abstract-paperless-service' | ||||
|  | ||||
| @Directive() | ||||
| export abstract class EditDialogComponent<T extends ObjectWithId> | ||||
|   implements OnInit | ||||
| export abstract class EditDialogComponent< | ||||
|   T extends ObjectWithPermissions | ObjectWithId | ||||
| > implements OnInit | ||||
| { | ||||
|   constructor( | ||||
|     private service: AbstractPaperlessService<T>, | ||||
| @@ -36,6 +38,16 @@ export abstract class EditDialogComponent<T extends ObjectWithId> | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     if (this.object != null) { | ||||
|       if (this.object['permissions']) { | ||||
|         this.object['set_permissions'] = { | ||||
|           view: (this.object as ObjectWithPermissions).permissions | ||||
|             .filter((p) => (p[1] as string).includes('view')) | ||||
|             .map((p) => p[0]), | ||||
|           change: (this.object as ObjectWithPermissions).permissions | ||||
|             .filter((p) => (p[1] as string).includes('change')) | ||||
|             .map((p) => p[0]), | ||||
|         } | ||||
|       } | ||||
|       this.objectForm.patchValue(this.object) | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -16,6 +16,14 @@ | ||||
|     <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|     <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|  | ||||
|     <div *ifOwner="object.owner"> | ||||
|       <h5 i18n>Permissions</h5> | ||||
|       <div formGroupName="set_permissions"> | ||||
|         <app-share-user type="view" formControlName="view"></app-share-user> | ||||
|         <app-share-user type="change" formControlName="change"></app-share-user> | ||||
|       </div> | ||||
|     </div> | ||||
|  | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button> | ||||
|   | ||||
| @@ -41,6 +41,10 @@ export class StoragePathEditDialogComponent extends EditDialogComponent<Paperles | ||||
|       matching_algorithm: new FormControl(DEFAULT_MATCHING_ALGORITHM), | ||||
|       match: new FormControl(''), | ||||
|       is_insensitive: new FormControl(true), | ||||
|       set_permissions: new FormGroup({ | ||||
|         view: new FormControl(null), | ||||
|         change: new FormControl(null), | ||||
|       }), | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,15 @@ | ||||
|       <app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|       <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|       <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|  | ||||
|       <div *ifOwner="object.owner"> | ||||
|         <h5 i18n>Permissions</h5> | ||||
|         <div formGroupName="set_permissions"> | ||||
|           <app-share-user type="view" formControlName="view"></app-share-user> | ||||
|           <app-share-user type="change" formControlName="change"></app-share-user> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|       <button type="button" class="btn btn-outline-secondary" (click)="cancel()" i18n [disabled]="networkActive">Cancel</button> | ||||
|   | ||||
| @@ -33,6 +33,10 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> { | ||||
|       matching_algorithm: new FormControl(DEFAULT_MATCHING_ALGORITHM), | ||||
|       match: new FormControl(''), | ||||
|       is_insensitive: new FormControl(true), | ||||
|       set_permissions: new FormGroup({ | ||||
|         view: new FormControl(null), | ||||
|         change: new FormControl(null), | ||||
|       }), | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,15 @@ | ||||
| <div class="mb-3 paperless-input-select"> | ||||
|     <label class="form-label" [for]="inputId">{{title}}</label> | ||||
|       <div> | ||||
|         <ng-select name="inputId" [(ngModel)]="value" | ||||
|           [disabled]="disabled" | ||||
|           clearable="true" | ||||
|           [items]="users" | ||||
|           multiple="true" | ||||
|           bindLabel="username" | ||||
|           bindValue="id" | ||||
|           (change)="onChange(value)"> | ||||
|         </ng-select> | ||||
|       </div> | ||||
|     <small *ngIf="hint" class="form-text text-muted">{{hint}}</small> | ||||
|   </div> | ||||
| @@ -0,0 +1,47 @@ | ||||
| import { Component, forwardRef, Input, OnInit } from '@angular/core' | ||||
| import { NG_VALUE_ACCESSOR } from '@angular/forms' | ||||
| import { first } from 'rxjs/operators' | ||||
| import { PaperlessUser } from 'src/app/data/paperless-user' | ||||
| import { UserService } from 'src/app/services/rest/user.service' | ||||
| import { AbstractInputComponent } from '../abstract-input' | ||||
|  | ||||
| @Component({ | ||||
|   providers: [ | ||||
|     { | ||||
|       provide: NG_VALUE_ACCESSOR, | ||||
|       useExisting: forwardRef(() => ShareUserComponent), | ||||
|       multi: true, | ||||
|     }, | ||||
|   ], | ||||
|   selector: 'app-share-user', | ||||
|   templateUrl: './share-user.component.html', | ||||
|   styleUrls: ['./share-user.component.scss'], | ||||
| }) | ||||
| export class ShareUserComponent | ||||
|   extends AbstractInputComponent<PaperlessUser> | ||||
|   implements OnInit | ||||
| { | ||||
|   users: PaperlessUser[] | ||||
|  | ||||
|   @Input() | ||||
|   type: string | ||||
|  | ||||
|   constructor(userService: UserService) { | ||||
|     super() | ||||
|     userService | ||||
|       .listAll() | ||||
|       .pipe(first()) | ||||
|       .subscribe((result) => (this.users = result.results)) | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     if (this.type == 'view') { | ||||
|       this.title = $localize`Users can view` | ||||
|     } else if (this.type == 'change') { | ||||
|       this.title = $localize`Users can edit` | ||||
|       this.hint = $localize`Edit permissions also grant viewing permissions` | ||||
|     } | ||||
|  | ||||
|     super.ngOnInit() | ||||
|   } | ||||
| } | ||||
| @@ -178,12 +178,12 @@ | ||||
|                     </ng-template> | ||||
|                 </li> | ||||
|  | ||||
|                 <li [ngbNavItem]="6"> | ||||
|                 <li [ngbNavItem]="6" *ifOwner="document?.owner"> | ||||
|                     <a ngbNavLink i18n>Permissions</a> | ||||
|                     <ng-template ngbNavContent> | ||||
|                         <div formGroupName="set_permissions"> | ||||
|                             <app-input-select i18n-title title="Users can view" [items]="users" [bindLabel]="'username'" multiple="true" formControlName="view"></app-input-select> | ||||
|                             <app-input-select i18n-title title="Users can edit" [items]="users" [bindLabel]="'username'" multiple="true" formControlName="change"></app-input-select> | ||||
|                             <app-share-user type="view" formControlName="view"></app-share-user> | ||||
|                             <app-share-user type="change" formControlName="change"></app-share-user> | ||||
|                         </div> | ||||
|                     </ng-template> | ||||
|                 </li> | ||||
|   | ||||
| @@ -40,7 +40,6 @@ import { | ||||
|   PermissionsService, | ||||
|   PermissionType, | ||||
| } from 'src/app/services/permissions.service' | ||||
| import { UserService } from 'src/app/services/rest/user.service' | ||||
| import { PaperlessUser } from 'src/app/data/paperless-user' | ||||
|  | ||||
| @Component({ | ||||
| @@ -75,7 +74,6 @@ export class DocumentDetailComponent | ||||
|   correspondents: PaperlessCorrespondent[] | ||||
|   documentTypes: PaperlessDocumentType[] | ||||
|   storagePaths: PaperlessStoragePath[] | ||||
|   users: PaperlessUser[] | ||||
|  | ||||
|   documentForm: FormGroup = new FormGroup({ | ||||
|     title: new FormControl(''), | ||||
| @@ -134,8 +132,7 @@ export class DocumentDetailComponent | ||||
|     private toastService: ToastService, | ||||
|     private settings: SettingsService, | ||||
|     private storagePathService: StoragePathService, | ||||
|     private permissionsService: PermissionsService, | ||||
|     private userService: UserService | ||||
|     private permissionsService: PermissionsService | ||||
|   ) {} | ||||
|  | ||||
|   titleKeyUp(event) { | ||||
| @@ -175,11 +172,6 @@ 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), | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { ObjectWithId } from './object-with-id' | ||||
| import { PaperlessUser } from './paperless-user' | ||||
|  | ||||
| export interface ObjectWithPermissions extends ObjectWithId { | ||||
|   user?: PaperlessUser | ||||
|   owner?: PaperlessUser | ||||
|  | ||||
|   permissions?: Array<[number, string]> | ||||
| } | ||||
|   | ||||
							
								
								
									
										42
									
								
								src-ui/src/app/directives/if-owner.directive.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src-ui/src/app/directives/if-owner.directive.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import { | ||||
|   Directive, | ||||
|   Input, | ||||
|   OnChanges, | ||||
|   OnInit, | ||||
|   TemplateRef, | ||||
|   ViewContainerRef, | ||||
| } from '@angular/core' | ||||
| import { PaperlessUser } from '../data/paperless-user' | ||||
| import { SettingsService } from '../services/settings.service' | ||||
|  | ||||
| @Directive({ | ||||
|   selector: '[ifOwner]', | ||||
| }) | ||||
| export class IfOwnerDirective implements OnInit, OnChanges { | ||||
|   // The role the user must have | ||||
|   @Input() | ||||
|   ifOwner: PaperlessUser | ||||
|  | ||||
|   /** | ||||
|    * @param {ViewContainerRef} viewContainerRef -- The location where we need to render the templateRef | ||||
|    * @param {TemplateRef<any>} templateRef -- The templateRef to be potentially rendered | ||||
|    * @param {PermissionsService} permissionsService -- Will give us access to the permissions a user has | ||||
|    */ | ||||
|   constructor( | ||||
|     private viewContainerRef: ViewContainerRef, | ||||
|     private templateRef: TemplateRef<any>, | ||||
|     private settings: SettingsService | ||||
|   ) {} | ||||
|  | ||||
|   public ngOnInit(): void { | ||||
|     if (!this.ifOwner || this.ifOwner?.id === this.settings.currentUser.id) { | ||||
|       this.viewContainerRef.createEmbeddedView(this.templateRef) | ||||
|     } else { | ||||
|       this.viewContainerRef.clear() | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public ngOnChanges(): void { | ||||
|     this.ngOnInit() | ||||
|   } | ||||
| } | ||||
| @@ -23,6 +23,7 @@ import { | ||||
|   SETTINGS, | ||||
|   SETTINGS_KEYS, | ||||
| } from '../data/paperless-uisettings' | ||||
| import { PaperlessUser } from '../data/paperless-user' | ||||
| import { PermissionsService } from './permissions.service' | ||||
| import { SavedViewService } from './rest/saved-view.service' | ||||
| import { ToastService } from './toast.service' | ||||
| @@ -46,8 +47,7 @@ export class SettingsService { | ||||
|   protected baseUrl: string = environment.apiBaseUrl + 'ui_settings/' | ||||
|  | ||||
|   private settings: Object = {} | ||||
|  | ||||
|   public displayName: string | ||||
|   currentUser: PaperlessUser | ||||
|  | ||||
|   public settingsSaved: EventEmitter<any> = new EventEmitter() | ||||
|  | ||||
| @@ -75,12 +75,23 @@ export class SettingsService { | ||||
|         // to update lang cookie | ||||
|         if (this.settings['language']?.length) | ||||
|           this.setLanguage(this.settings['language']) | ||||
|         this.displayName = uisettings.display_name.trim() | ||||
|         this.currentUser = { | ||||
|           id: uisettings['user_id'], | ||||
|           username: uisettings['username'], | ||||
|         } | ||||
|         this.permissionsService.initialize(uisettings.permissions) | ||||
|       }) | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   get displayName(): string { | ||||
|     return ( | ||||
|       this.currentUser.first_name ?? | ||||
|       this.currentUser.username ?? | ||||
|       '' | ||||
|     ).trim() | ||||
|   } | ||||
|  | ||||
|   public updateAppearanceSettings( | ||||
|     darkModeUseSystem = null, | ||||
|     darkModeEnabled = null, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Michael Shamoon
					Michael Shamoon