diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts index 183a6ad25..60a6f4844 100644 --- a/src-ui/src/app/app.module.ts +++ b/src-ui/src/app/app.module.ts @@ -106,6 +106,7 @@ 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' +import { IfObjectPermissionsDirective } from './directives/if-object-permissions.directive' registerLocaleData(localeBe) registerLocaleData(localeCs) @@ -199,6 +200,7 @@ function initializeApp(settings: SettingsService) { MailRuleEditDialogComponent, ShareUserComponent, IfOwnerDirective, + IfObjectPermissionsDirective, ], imports: [ BrowserModule, diff --git a/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html index 857bd2f1c..83f24812f 100644 --- a/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/correspondent-edit-dialog/correspondent-edit-dialog.component.html @@ -11,7 +11,7 @@ -
+
Permissions
diff --git a/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html index b7d7f1335..3aa196f31 100644 --- a/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/document-type-edit-dialog/document-type-edit-dialog.component.html @@ -11,7 +11,7 @@ -
+
Permissions
diff --git a/src-ui/src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html index e122b8c00..a0e141907 100644 --- a/src-ui/src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/storage-path-edit-dialog/storage-path-edit-dialog.component.html @@ -16,7 +16,7 @@ -
+
Permissions
diff --git a/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html index a4a7fbbf5..4e6d0e22f 100644 --- a/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/tag-edit-dialog/tag-edit-dialog.component.html @@ -14,7 +14,7 @@ -
+
Permissions
diff --git a/src-ui/src/app/components/common/input/date/date.component.html b/src-ui/src/app/components/common/input/date/date.component.html index 926429a8d..dfc3950aa 100644 --- a/src-ui/src/app/components/common/input/date/date.component.html +++ b/src-ui/src/app/components/common/input/date/date.component.html @@ -3,8 +3,8 @@
- + +
{{error}} diff --git a/src-ui/src/app/components/common/input/select/select.component.html b/src-ui/src/app/components/common/input/select/select.component.html index d775f4ffa..6bb5f5036 100644 --- a/src-ui/src/app/components/common/input/select/select.component.html +++ b/src-ui/src/app/components/common/input/select/select.component.html @@ -20,7 +20,7 @@ (clear)="clearLastSearchTerm()" (blur)="onBlur()"> -
-   -   -   + +   +   +   +
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.ts b/src-ui/src/app/components/document-detail/document-detail.component.ts index 07f03ece6..8d564f4b5 100644 --- a/src-ui/src/app/components/document-detail/document-detail.component.ts +++ b/src-ui/src/app/components/document-detail/document-detail.component.ts @@ -306,6 +306,7 @@ export class DocumentDetailComponent .map((p) => p[0]), } this.documentForm.patchValue(doc) + if (!this.userCanEdit) this.documentForm.disable() } createDocumentType(newName: string) { @@ -591,4 +592,14 @@ export class DocumentDetailComponent }) ) } + + get userCanEdit(): boolean { + return ( + !this.document || + this.permissionsService.currentUserHasObjectPermissions( + PermissionAction.Change, + this.document + ) + ) + } } diff --git a/src-ui/src/app/directives/if-object-permissions.directive.ts b/src-ui/src/app/directives/if-object-permissions.directive.ts new file mode 100644 index 000000000..c897b848d --- /dev/null +++ b/src-ui/src/app/directives/if-object-permissions.directive.ts @@ -0,0 +1,54 @@ +import { + Directive, + Input, + OnChanges, + OnInit, + TemplateRef, + ViewContainerRef, +} from '@angular/core' +import { ObjectWithPermissions } from '../data/object-with-permissions' +import { + PermissionAction, + PermissionsService, +} from '../services/permissions.service' + +@Directive({ + selector: '[ifObjectPermissions]', +}) +export class IfObjectPermissionsDirective implements OnInit, OnChanges { + // The role the user must have + @Input() + ifObjectPermissions: ObjectWithPermissions + + @Input() + action: PermissionAction + + /** + * @param {ViewContainerRef} viewContainerRef -- The location where we need to render the templateRef + * @param {TemplateRef} 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, + private permissionsService: PermissionsService + ) {} + + public ngOnInit(): void { + if ( + !this.ifObjectPermissions || + this.permissionsService.currentUserHasObjectPermissions( + this.action, + this.ifObjectPermissions + ) + ) { + this.viewContainerRef.createEmbeddedView(this.templateRef) + } else { + this.viewContainerRef.clear() + } + } + + public ngOnChanges(): void { + this.ngOnInit() + } +} diff --git a/src-ui/src/app/directives/if-owner.directive.ts b/src-ui/src/app/directives/if-owner.directive.ts index 51a2c910f..86fcd3457 100644 --- a/src-ui/src/app/directives/if-owner.directive.ts +++ b/src-ui/src/app/directives/if-owner.directive.ts @@ -7,7 +7,7 @@ import { ViewContainerRef, } from '@angular/core' import { PaperlessUser } from '../data/paperless-user' -import { SettingsService } from '../services/settings.service' +import { PermissionsService } from '../services/permissions.service' @Directive({ selector: '[ifOwner]', @@ -25,11 +25,14 @@ export class IfOwnerDirective implements OnInit, OnChanges { constructor( private viewContainerRef: ViewContainerRef, private templateRef: TemplateRef, - private settings: SettingsService + private permissionsService: PermissionsService ) {} public ngOnInit(): void { - if (!this.ifOwner || this.ifOwner?.id === this.settings.currentUser.id) { + if ( + !this.ifOwner || + this.permissionsService.currentUserIsOwner(this.ifOwner) + ) { this.viewContainerRef.createEmbeddedView(this.templateRef) } else { this.viewContainerRef.clear() diff --git a/src-ui/src/app/services/permissions.service.ts b/src-ui/src/app/services/permissions.service.ts index 4302f1b27..0f7edee22 100644 --- a/src-ui/src/app/services/permissions.service.ts +++ b/src-ui/src/app/services/permissions.service.ts @@ -1,4 +1,6 @@ import { Injectable } from '@angular/core' +import { ObjectWithPermissions } from '../data/object-with-permissions' +import { PaperlessUser } from '../data/paperless-user' export enum PermissionAction { Add = 'add', @@ -33,15 +35,30 @@ export interface PaperlessPermission { }) export class PermissionsService { private permissions: string[] + private currentUser: PaperlessUser - public initialize(permissions: string[]) { + public initialize(permissions: string[], currentUser: PaperlessUser) { this.permissions = permissions + this.currentUser = currentUser } public currentUserCan(permission: PaperlessPermission): boolean { return this.permissions.includes(this.getPermissionCode(permission)) } + public currentUserIsOwner(owner: PaperlessUser): boolean { + return owner?.id === this.currentUser.id + } + + public currentUserHasObjectPermissions( + action: string, + object: ObjectWithPermissions + ): boolean { + return (object.permissions[action] as Array)?.includes( + this.currentUser.id + ) + } + public getPermissionCode(permission: PaperlessPermission): string { return permission.type.replace('%s', permission.action) } diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index fbf8b9320..72a34ea15 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -79,7 +79,10 @@ export class SettingsService { id: uisettings['user_id'], username: uisettings['username'], } - this.permissionsService.initialize(uisettings.permissions) + this.permissionsService.initialize( + uisettings.permissions, + this.currentUser + ) }) ) } diff --git a/src-ui/src/styles.scss b/src-ui/src/styles.scss index ab62dff25..a9169f038 100644 --- a/src-ui/src/styles.scss +++ b/src-ui/src/styles.scss @@ -255,6 +255,7 @@ a, a:hover, .paperless-input-tags { .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value { background-color: transparent; + border-color: transparent; } .ng-select.ng-select-multiple .ng-select-container .ng-value-container {