diff --git a/CHANGELOG.md b/CHANGELOG.md index 9334d7407..6b6e13f2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added support to grant private access with permissions - Added `permissions` to the `Access` model ### Changed diff --git a/apps/api/src/app/access/create-access.dto.ts b/apps/api/src/app/access/create-access.dto.ts index a6a24690d..de9ea3b82 100644 --- a/apps/api/src/app/access/create-access.dto.ts +++ b/apps/api/src/app/access/create-access.dto.ts @@ -12,4 +12,8 @@ export class CreateAccessDto { @IsOptional() @IsString() type?: 'PUBLIC'; + + @IsOptional() + @IsString() + permission?: string; } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index fe6625439..d923e7c12 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -109,6 +109,10 @@ export class UserService { return aUser.Settings.settings.isRestrictedView ?? false; } + public hasReadRestrictedPermission(user: UserWithSettings): boolean { + return user.permissions.includes('READ_RESTRICTED'); + } + public async user( userWhereUniqueInput: Prisma.UserWhereUniqueInput ): Promise { diff --git a/apps/api/src/interceptors/redact-values-in-response.interceptor.ts b/apps/api/src/interceptors/redact-values-in-response.interceptor.ts index 6b10a4ebb..56111bf4b 100644 --- a/apps/api/src/interceptors/redact-values-in-response.interceptor.ts +++ b/apps/api/src/interceptors/redact-values-in-response.interceptor.ts @@ -28,7 +28,7 @@ export class RedactValuesInResponseInterceptor if ( hasImpersonationId || - this.userService.isRestrictedView(request.user) + this.userService.hasReadRestrictedPermission(request.user) ) { data = redactAttributes({ object: data, diff --git a/apps/client/src/app/components/access-table/access-table.component.html b/apps/client/src/app/components/access-table/access-table.component.html index 473be0e81..d0b7dbcb2 100644 --- a/apps/client/src/app/components/access-table/access-table.component.html +++ b/apps/client/src/app/components/access-table/access-table.component.html @@ -18,7 +18,7 @@
- Restricted View + {{ getDisplayName(element.type) }}
diff --git a/apps/client/src/app/components/access-table/access-table.component.ts b/apps/client/src/app/components/access-table/access-table.component.ts index c0db8fb2f..33cd6d910 100644 --- a/apps/client/src/app/components/access-table/access-table.component.ts +++ b/apps/client/src/app/components/access-table/access-table.component.ts @@ -44,6 +44,21 @@ export class AccessTableComponent implements OnChanges, OnInit { } } + public getDisplayName( + type: 'PRIVATE' | 'PUBLIC' | 'RESTRICTED_VIEW' | 'VIEW' + ): string { + switch (type) { + case 'PUBLIC': + return $localize`Public`; + case 'RESTRICTED_VIEW': + return $localize`Restricted View`; + case 'VIEW': + return $localize`View`; + default: + return $localize`Unknown`; + } + } + public onDeleteAccess(aId: string) { const confirmation = confirm( $localize`Do you really want to revoke this granted access?` diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts index 495ad3354..4248dc6ef 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts @@ -38,19 +38,23 @@ export class CreateOrUpdateAccessDialog implements OnDestroy { this.accessForm = this.formBuilder.group({ alias: [this.data.access.alias], type: [this.data.access.type, Validators.required], - userId: [this.data.access.grantee, Validators.required] + userId: [this.data.access.grantee, Validators.required], + permission: [this.data.access.permission, Validators.required] }); this.accessForm.get('type').valueChanges.subscribe((value) => { const userIdControl = this.accessForm.get('userId'); + const permissionControl = this.accessForm.get('permission'); if (value === 'PRIVATE') { userIdControl.setValidators(Validators.required); + permissionControl.setValidators(Validators.required); } else { userIdControl.clearValidators(); } userIdControl.updateValueAndValidity(); + permissionControl.updateValueAndValidity(); this.changeDetectorRef.markForCheck(); }); @@ -64,9 +68,10 @@ export class CreateOrUpdateAccessDialog implements OnDestroy { const access: CreateAccessDto = { alias: this.accessForm.controls['alias'].value, granteeUserId: this.accessForm.controls['userId'].value, - type: this.accessForm.controls['type'].value + type: this.accessForm.controls['type'].value, + permission: this.accessForm.controls['permission'].value }; - + this.dataService .postAccess(access) .pipe( diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html index 31b9d7626..df740a654 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -30,9 +30,9 @@ @if (accessForm.controls['type'].value === 'PRIVATE') {
- Ghostfolio User ID + + Ghostfolio User ID +
+
+ + Permission + + Restricted view + View + + +
}
diff --git a/libs/common/src/lib/interfaces/access.interface.ts b/libs/common/src/lib/interfaces/access.interface.ts index 299616cf4..78b9494d4 100644 --- a/libs/common/src/lib/interfaces/access.interface.ts +++ b/libs/common/src/lib/interfaces/access.interface.ts @@ -3,4 +3,5 @@ export interface Access { grantee?: string; id: string; type: 'PRIVATE' | 'PUBLIC' | 'RESTRICTED_VIEW'; + permission: 'READ' | 'READ_RESTRICTED'; }