From e272d69aa4be2a0b32f356d72549fb3f28b046e7 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 1 Jun 2024 09:39:09 +0200 Subject: [PATCH] Refactoring --- .../src/app/portfolio/portfolio.controller.ts | 66 +++++++++---------- .../redact-values-in-response.interceptor.ts | 19 +++--- .../redact-values-in-response.module.ts | 9 +-- .../user-helper/user-helper.module.ts | 9 --- .../user-helper/user-helper.service.ts | 30 --------- libs/common/src/lib/permissions.ts | 24 ++++++- 6 files changed, 64 insertions(+), 93 deletions(-) delete mode 100644 apps/api/src/services/user-helper/user-helper.module.ts delete mode 100644 apps/api/src/services/user-helper/user-helper.service.ts diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index ed11c8a4c..5cdaa1641 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -14,7 +14,6 @@ import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; -import { UserHelperService } from '@ghostfolio/api/services/user-helper/user-helper.service'; import { DEFAULT_CURRENCY, HEADER_KEY_IMPERSONATION @@ -28,6 +27,10 @@ import { PortfolioPublicDetails, PortfolioReport } from '@ghostfolio/common/interfaces'; +import { + hasReadRestrictedAccessPermission, + isRestrictedView +} from '@ghostfolio/common/permissions'; import type { DateRange, GroupBy, @@ -66,7 +69,6 @@ export class PortfolioController { private readonly orderService: OrderService, private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser, - private readonly userHelperService: UserHelperService, private readonly userService: UserService ) {} @@ -86,11 +88,6 @@ export class PortfolioController { let hasDetails = true; let hasError = false; - const hasReadRestrictedAccessPermission = - this.userHelperService.hasReadRestrictedAccessPermission({ - impersonationId, - user: this.request.user - }); if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { hasDetails = this.request.user.subscription.type === 'Premium'; @@ -119,8 +116,11 @@ export class PortfolioController { let portfolioSummary = summary; if ( - hasReadRestrictedAccessPermission || - this.userHelperService.isRestrictedView(this.request.user) + hasReadRestrictedAccessPermission({ + impersonationId, + user: this.request.user + }) || + isRestrictedView(this.request.user) ) { const totalInvestment = Object.values(holdings) .map(({ investment }) => { @@ -160,8 +160,11 @@ export class PortfolioController { if ( hasDetails === false || - hasReadRestrictedAccessPermission || - this.userHelperService.isRestrictedView(this.request.user) + hasReadRestrictedAccessPermission({ + impersonationId, + user: this.request.user + }) || + isRestrictedView(this.request.user) ) { portfolioSummary = nullifyValuesInObject(summary, [ 'cash', @@ -228,12 +231,6 @@ export class PortfolioController { @Query('range') dateRange: DateRange = 'max', @Query('tags') filterByTags?: string ): Promise { - const hasReadRestrictedAccessPermission = - this.userHelperService.hasReadRestrictedAccessPermission({ - impersonationId, - user: this.request.user - }); - const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, @@ -261,8 +258,11 @@ export class PortfolioController { }); if ( - hasReadRestrictedAccessPermission || - this.userHelperService.isRestrictedView(this.request.user) + hasReadRestrictedAccessPermission({ + impersonationId, + user: this.request.user + }) || + isRestrictedView(this.request.user) ) { const maxDividend = dividends.reduce( (investment, item) => Math.max(investment, item.investment), @@ -328,12 +328,6 @@ export class PortfolioController { @Query('range') dateRange: DateRange = 'max', @Query('tags') filterByTags?: string ): Promise { - const hasReadRestrictedAccessPermission = - this.userHelperService.hasReadRestrictedAccessPermission({ - impersonationId, - user: this.request.user - }); - const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, @@ -349,8 +343,11 @@ export class PortfolioController { }); if ( - hasReadRestrictedAccessPermission || - this.userHelperService.isRestrictedView(this.request.user) + hasReadRestrictedAccessPermission({ + impersonationId, + user: this.request.user + }) || + isRestrictedView(this.request.user) ) { const maxInvestment = investments.reduce( (investment, item) => Math.max(investment, item.investment), @@ -399,12 +396,6 @@ export class PortfolioController { ): Promise { const withExcludedAccounts = withExcludedAccountsParam === 'true'; - const hasReadRestrictedAccessPermission = - this.userHelperService.hasReadRestrictedAccessPermission({ - impersonationId, - user: this.request.user - }); - const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, @@ -420,9 +411,12 @@ export class PortfolioController { }); if ( - hasReadRestrictedAccessPermission || - this.request.user.Settings.settings.viewMode === 'ZEN' || - this.userHelperService.isRestrictedView(this.request.user) + hasReadRestrictedAccessPermission({ + impersonationId, + user: this.request.user + }) || + isRestrictedView(this.request.user) || + this.request.user.Settings.settings.viewMode === 'ZEN' ) { performanceInformation.chart = performanceInformation.chart.map( ({ diff --git a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts index 8b8c0fd28..cae4f22ed 100644 --- a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts +++ b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts @@ -1,6 +1,9 @@ import { redactAttributes } from '@ghostfolio/api/helper/object.helper'; -import { UserHelperService } from '@ghostfolio/api/services/user-helper/user-helper.service'; import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; +import { + hasReadRestrictedAccessPermission, + isRestrictedView +} from '@ghostfolio/common/permissions'; import { UserWithSettings } from '@ghostfolio/common/types'; import { @@ -16,7 +19,7 @@ import { map } from 'rxjs/operators'; export class RedactValuesInResponseInterceptor implements NestInterceptor { - public constructor(private userHelperService: UserHelperService) {} + public constructor() {} public intercept( context: ExecutionContext, @@ -29,15 +32,13 @@ export class RedactValuesInResponseInterceptor const impersonationId = headers?.[HEADER_KEY_IMPERSONATION.toLowerCase()]; - const hasReadRestrictedPermission = - this.userHelperService.hasReadRestrictedAccessPermission({ - impersonationId, - user - }); if ( - hasReadRestrictedPermission || - this.userHelperService.isRestrictedView(user) + hasReadRestrictedAccessPermission({ + impersonationId, + user + }) || + isRestrictedView(user) ) { data = redactAttributes({ object: data, diff --git a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.module.ts b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.module.ts index 4c824b04f..90cf254b3 100644 --- a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.module.ts +++ b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.module.ts @@ -1,11 +1,4 @@ -import { UserHelperModule } from '@ghostfolio/api/services/user-helper/user-helper.module'; -import { UserHelperService } from '@ghostfolio/api/services/user-helper/user-helper.service'; - import { Module } from '@nestjs/common'; -@Module({ - exports: [UserHelperService], - imports: [UserHelperModule], - providers: [UserHelperService] -}) +@Module({}) export class RedactValuesInResponseModule {} diff --git a/apps/api/src/services/user-helper/user-helper.module.ts b/apps/api/src/services/user-helper/user-helper.module.ts deleted file mode 100644 index a6b2b0e96..000000000 --- a/apps/api/src/services/user-helper/user-helper.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { UserHelperService } from './user-helper.service'; - -@Module({ - exports: [UserHelperService], - providers: [UserHelperService] -}) -export class UserHelperModule {} diff --git a/apps/api/src/services/user-helper/user-helper.service.ts b/apps/api/src/services/user-helper/user-helper.service.ts deleted file mode 100644 index d18c24416..000000000 --- a/apps/api/src/services/user-helper/user-helper.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { UserWithSettings } from '@ghostfolio/common/types'; - -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class UserHelperService { - public constructor() {} - - public hasReadRestrictedAccessPermission({ - impersonationId, - user - }: { - impersonationId: string; - user: UserWithSettings; - }) { - if (!impersonationId) { - return false; - } - - const access = user.Access?.find(({ id }) => { - return id === impersonationId; - }); - - return access?.permissions?.includes('READ_RESTRICTED') ?? true; - } - - public isRestrictedView(aUser: UserWithSettings) { - return aUser.Settings.settings.isRestrictedView ?? false; - } -} diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index 890cb8b63..7c8b8ccbe 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -125,6 +125,28 @@ export function hasPermission( return aPermissions.includes(aPermission); } -export function hasRole(aUser: UserWithSettings, aRole: Role): boolean { +export function hasReadRestrictedAccessPermission({ + impersonationId, + user +}: { + impersonationId: string; + user: UserWithSettings; +}) { + if (!impersonationId) { + return false; + } + + const access = user.Access?.find(({ id }) => { + return id === impersonationId; + }); + + return access?.permissions?.includes('READ_RESTRICTED') ?? true; +} + +export function hasRole(aUser: UserWithSettings, aRole: Role) { return aUser?.role === aRole; } + +export function isRestrictedView(aUser: UserWithSettings) { + return aUser.Settings.settings.isRestrictedView ?? false; +}