Browse Source

Add support to remove a received access on the access page

pull/7701/head
Thomas Kaul 7 days ago
parent
commit
b587458245
  1. 4
      apps/api/src/app/access/access.controller.ts
  2. 43
      apps/client/src/app/components/user-account-access/user-account-access.component.ts
  3. 4
      apps/client/src/app/components/user-account-access/user-account-access.html
  4. 3
      libs/ui/src/lib/services/data.service.ts

4
apps/api/src/app/access/access.controller.ts

@ -114,7 +114,7 @@ export class AccessController {
@Delete(':id') @Delete(':id')
@HasPermission(permissions.deleteAccess) @HasPermission(permissions.deleteAccess)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async deleteAccess(@Param('id') id: string): Promise<AccessModel> { public async deleteAccess(@Param('id') id: string): Promise<void> {
const originalAccess = await this.accessService.access({ const originalAccess = await this.accessService.access({
id, id,
OR: [ OR: [
@ -130,7 +130,7 @@ export class AccessController {
); );
} }
return this.accessService.deleteAccess({ await this.accessService.deleteAccess({
id id
}); });
} }

43
apps/client/src/app/components/user-account-access/user-account-access.component.ts

@ -1,4 +1,5 @@
import { GfAccessTableComponent } from '@ghostfolio/client/components/access-table/access-table.component'; import { GfAccessTableComponent } from '@ghostfolio/client/components/access-table/access-table.component';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { CreateAccessDto } from '@ghostfolio/common/dtos'; import { CreateAccessDto } from '@ghostfolio/common/dtos';
import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { ConfirmationDialogType } from '@ghostfolio/common/enums';
@ -63,6 +64,7 @@ import { CreateOrUpdateAccessDialogParams } from './create-or-update-access-dial
export class GfUserAccountAccessComponent implements OnInit { export class GfUserAccountAccessComponent implements OnInit {
protected accessesGet: Access[]; protected accessesGet: Access[];
protected accessesGive: Access[]; protected accessesGive: Access[];
protected hasImpersonationId: boolean;
protected hasPermissionToCreateAccess: boolean; protected hasPermissionToCreateAccess: boolean;
protected hasPermissionToDeleteAccess: boolean; protected hasPermissionToDeleteAccess: boolean;
protected hasPermissionToUpdateOwnAccessToken: boolean; protected hasPermissionToUpdateOwnAccessToken: boolean;
@ -84,6 +86,9 @@ export class GfUserAccountAccessComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
private readonly deviceDetectorService = inject(DeviceDetectorService); private readonly deviceDetectorService = inject(DeviceDetectorService);
private readonly dialog = inject(MatDialog); private readonly dialog = inject(MatDialog);
private readonly impersonationStorageService = inject(
ImpersonationStorageService
);
private readonly notificationService = inject(NotificationService); private readonly notificationService = inject(NotificationService);
private readonly route = inject(ActivatedRoute); private readonly route = inject(ActivatedRoute);
private readonly router = inject(Router); private readonly router = inject(Router);
@ -97,6 +102,15 @@ export class GfUserAccountAccessComponent implements OnInit {
permissions.deleteAccess permissions.deleteAccess
); );
this.impersonationStorageService
.onChangeHasImpersonation()
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((impersonationId) => {
this.hasImpersonationId = !!impersonationId;
this.changeDetectorRef.markForCheck();
});
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((state) => { .subscribe((state) => {
@ -140,18 +154,41 @@ export class GfUserAccountAccessComponent implements OnInit {
} }
protected onDeleteAccess(aId: string) { protected onDeleteAccess(aId: string) {
this.dataService
.deleteAccess(aId)
.pipe(
catchError(() => {
this.notificationService.alert({
title: $localize`Oops! Could not revoke the granted access.`
});
return EMPTY;
}),
takeUntilDestroyed(this.destroyRef)
)
.subscribe(() => {
this.update();
});
}
protected onDeleteReceivedAccess(aId: string) {
this.dataService this.dataService
.deleteAccess(aId) .deleteAccess(aId)
.pipe( .pipe(
switchMap(() => { switchMap(() => {
return this.userService.get(true); return this.userService.get(true);
}), }),
catchError(() => {
this.notificationService.alert({
title: $localize`Oops! Could not remove the received access.`
});
return EMPTY;
}),
takeUntilDestroyed(this.destroyRef) takeUntilDestroyed(this.destroyRef)
) )
.subscribe({ .subscribe(() => {
next: () => {
this.update(); this.update();
}
}); });
} }

4
apps/client/src/app/components/user-account-access/user-account-access.html

@ -57,9 +57,9 @@
class="mb-5" class="mb-5"
[accesses]="accessesGet" [accesses]="accessesGet"
[isReceivedAccess]="true" [isReceivedAccess]="true"
[showActions]="hasPermissionToDeleteAccess" [showActions]="hasPermissionToDeleteAccess && !hasImpersonationId"
[user]="user" [user]="user"
(accessDeleted)="onDeleteAccess($event)" (accessDeleted)="onDeleteReceivedAccess($event)"
/> />
} }
<h1 class="align-items-center d-flex h3 justify-content-center mb-3"> <h1 class="align-items-center d-flex h3 justify-content-center mb-3">

3
libs/ui/src/lib/services/data.service.ts

@ -70,7 +70,6 @@ import { inject, Service } from '@angular/core';
import { SortDirection } from '@angular/material/sort'; import { SortDirection } from '@angular/material/sort';
import { utc } from '@date-fns/utc'; import { utc } from '@date-fns/utc';
import { import {
Access as AccessModel,
Account, Account,
AccountBalance, AccountBalance,
DataSource, DataSource,
@ -316,7 +315,7 @@ export class DataService {
} }
public deleteAccess(aId: string) { public deleteAccess(aId: string) {
return this.http.delete<AccessModel>(`/api/v1/access/${aId}`); return this.http.delete<void>(`/api/v1/access/${aId}`);
} }
public deleteAccount(aId: string) { public deleteAccount(aId: string) {

Loading…
Cancel
Save