|
|
@ -1,8 +1,8 @@ |
|
|
import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; |
|
|
import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; |
|
|
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; |
|
|
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; |
|
|
import { Impersonation } from '@ghostfolio/api/decorators/impersonation.decorator'; |
|
|
import { Impersonation } from '@ghostfolio/api/decorators/impersonation.decorator'; |
|
|
|
|
|
import { RequiresScope } from '@ghostfolio/api/decorators/requires-scope.decorator'; |
|
|
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; |
|
|
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; |
|
|
import { ImpersonationGuard } from '@ghostfolio/api/guards/impersonation.guard'; |
|
|
|
|
|
import { |
|
|
import { |
|
|
hasNotDefinedValuesInObject, |
|
|
hasNotDefinedValuesInObject, |
|
|
nullifyValuesInObject |
|
|
nullifyValuesInObject |
|
|
@ -25,11 +25,8 @@ import { |
|
|
PortfolioPerformanceResponse, |
|
|
PortfolioPerformanceResponse, |
|
|
PortfolioReportResponse |
|
|
PortfolioReportResponse |
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
import { |
|
|
import { isRestrictedView, permissions } from '@ghostfolio/common/permissions'; |
|
|
hasReadRestrictedAccessPermission, |
|
|
import { hasScope, scopes } from '@ghostfolio/common/scopes'; |
|
|
isRestrictedView, |
|
|
|
|
|
permissions |
|
|
|
|
|
} from '@ghostfolio/common/permissions'; |
|
|
|
|
|
import type { |
|
|
import type { |
|
|
ImpersonationContext, |
|
|
ImpersonationContext, |
|
|
RequestWithUser |
|
|
RequestWithUser |
|
|
@ -73,12 +70,13 @@ export class PortfolioController { |
|
|
) {} |
|
|
) {} |
|
|
|
|
|
|
|
|
@Get('details') |
|
|
@Get('details') |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
@UseInterceptors(RedactValuesInResponseInterceptor) |
|
|
@UseInterceptors(RedactValuesInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
public async getDetails( |
|
|
public async getDetails( |
|
|
@Impersonation() { accessId, userId }: ImpersonationContext, |
|
|
@Impersonation() |
|
|
|
|
|
{ scopes: impersonationScopes, userId }: ImpersonationContext, |
|
|
@Query() |
|
|
@Query() |
|
|
{ |
|
|
{ |
|
|
accounts: filterByAccounts, |
|
|
accounts: filterByAccounts, |
|
|
@ -130,10 +128,7 @@ export class PortfolioController { |
|
|
let portfolioSummary = summary; |
|
|
let portfolioSummary = summary; |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
hasReadRestrictedAccessPermission({ |
|
|
!hasScope(impersonationScopes, scopes.portfolioReadValues) || |
|
|
accesses: this.request.user?.accessesGet, |
|
|
|
|
|
impersonationId: accessId |
|
|
|
|
|
}) || |
|
|
|
|
|
isRestrictedView(this.request.user) |
|
|
isRestrictedView(this.request.user) |
|
|
) { |
|
|
) { |
|
|
const totalInvestment = Object.values(holdings) |
|
|
const totalInvestment = Object.values(holdings) |
|
|
@ -174,10 +169,7 @@ export class PortfolioController { |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
hasDetails === false || |
|
|
hasDetails === false || |
|
|
hasReadRestrictedAccessPermission({ |
|
|
!hasScope(impersonationScopes, scopes.portfolioReadValues) || |
|
|
accesses: this.request.user?.accessesGet, |
|
|
|
|
|
impersonationId: accessId |
|
|
|
|
|
}) || |
|
|
|
|
|
isRestrictedView(this.request.user) |
|
|
isRestrictedView(this.request.user) |
|
|
) { |
|
|
) { |
|
|
Object.values(markets ?? {}).forEach((market) => { |
|
|
Object.values(markets ?? {}).forEach((market) => { |
|
|
@ -319,10 +311,11 @@ export class PortfolioController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Get('dividends') |
|
|
@Get('dividends') |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
public async getDividends( |
|
|
public async getDividends( |
|
|
@Impersonation() { accessId, userId, userSettings }: ImpersonationContext, |
|
|
@Impersonation() |
|
|
|
|
|
{ scopes: impersonationScopes, userId, userSettings }: ImpersonationContext, |
|
|
@Query() |
|
|
@Query() |
|
|
{ |
|
|
{ |
|
|
accounts, |
|
|
accounts, |
|
|
@ -364,10 +357,7 @@ export class PortfolioController { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
hasReadRestrictedAccessPermission({ |
|
|
!hasScope(impersonationScopes, scopes.portfolioReadValues) || |
|
|
accesses: this.request.user?.accessesGet, |
|
|
|
|
|
impersonationId: accessId |
|
|
|
|
|
}) || |
|
|
|
|
|
isRestrictedView(this.request.user) |
|
|
isRestrictedView(this.request.user) |
|
|
) { |
|
|
) { |
|
|
const maxDividend = dividends.reduce( |
|
|
const maxDividend = dividends.reduce( |
|
|
@ -397,7 +387,7 @@ export class PortfolioController { |
|
|
@UseInterceptors(RedactValuesInResponseInterceptor) |
|
|
@UseInterceptors(RedactValuesInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
public async getHolding( |
|
|
public async getHolding( |
|
|
@Impersonation() { userId }: ImpersonationContext, |
|
|
@Impersonation() { userId }: ImpersonationContext, |
|
|
@Param('dataSource') dataSource: DataSource, |
|
|
@Param('dataSource') dataSource: DataSource, |
|
|
@ -420,7 +410,7 @@ export class PortfolioController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Get('holdings') |
|
|
@Get('holdings') |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
@UseInterceptors(RedactValuesInResponseInterceptor) |
|
|
@UseInterceptors(RedactValuesInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@ -458,10 +448,11 @@ export class PortfolioController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Get('investments') |
|
|
@Get('investments') |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
public async getInvestments( |
|
|
public async getInvestments( |
|
|
@Impersonation() { accessId, userId }: ImpersonationContext, |
|
|
@Impersonation() |
|
|
|
|
|
{ scopes: impersonationScopes, userId }: ImpersonationContext, |
|
|
@Query() |
|
|
@Query() |
|
|
{ |
|
|
{ |
|
|
accounts, |
|
|
accounts, |
|
|
@ -490,10 +481,7 @@ export class PortfolioController { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
hasReadRestrictedAccessPermission({ |
|
|
!hasScope(impersonationScopes, scopes.portfolioReadValues) || |
|
|
accesses: this.request.user?.accessesGet, |
|
|
|
|
|
impersonationId: accessId |
|
|
|
|
|
}) || |
|
|
|
|
|
isRestrictedView(this.request.user) |
|
|
isRestrictedView(this.request.user) |
|
|
) { |
|
|
) { |
|
|
const maxInvestment = investments.reduce( |
|
|
const maxInvestment = investments.reduce( |
|
|
@ -532,13 +520,14 @@ export class PortfolioController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Get('performance') |
|
|
@Get('performance') |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
@UseInterceptors(PerformanceLoggingInterceptor) |
|
|
@UseInterceptors(PerformanceLoggingInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInResponseInterceptor) |
|
|
@Version('2') |
|
|
@Version('2') |
|
|
public async getPerformanceV2( |
|
|
public async getPerformanceV2( |
|
|
@Impersonation() { accessId, userId }: ImpersonationContext, |
|
|
@Impersonation() |
|
|
|
|
|
{ scopes: impersonationScopes, userId }: ImpersonationContext, |
|
|
@Query() |
|
|
@Query() |
|
|
{ |
|
|
{ |
|
|
accounts, |
|
|
accounts, |
|
|
@ -566,10 +555,7 @@ export class PortfolioController { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
hasReadRestrictedAccessPermission({ |
|
|
!hasScope(impersonationScopes, scopes.portfolioReadValues) || |
|
|
accesses: this.request.user?.accessesGet, |
|
|
|
|
|
impersonationId: accessId |
|
|
|
|
|
}) || |
|
|
|
|
|
isRestrictedView(this.request.user) || |
|
|
isRestrictedView(this.request.user) || |
|
|
this.request.user.settings.settings.viewMode === 'ZEN' |
|
|
this.request.user.settings.settings.viewMode === 'ZEN' |
|
|
) { |
|
|
) { |
|
|
@ -645,17 +631,15 @@ export class PortfolioController { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Get('report') |
|
|
@Get('report') |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@RequiresScope(scopes.portfolioRead) |
|
|
public async getReport( |
|
|
public async getReport( |
|
|
@Impersonation() { accessId, userId }: ImpersonationContext |
|
|
@Impersonation() |
|
|
|
|
|
{ scopes: impersonationScopes, userId }: ImpersonationContext |
|
|
): Promise<PortfolioReportResponse> { |
|
|
): Promise<PortfolioReportResponse> { |
|
|
const report = await this.portfolioService.getReport({ userId }); |
|
|
const report = await this.portfolioService.getReport({ userId }); |
|
|
|
|
|
|
|
|
if ( |
|
|
if ( |
|
|
hasReadRestrictedAccessPermission({ |
|
|
!hasScope(impersonationScopes, scopes.portfolioReadValues) || |
|
|
accesses: this.request.user?.accessesGet, |
|
|
|
|
|
impersonationId: accessId |
|
|
|
|
|
}) || |
|
|
|
|
|
isRestrictedView(this.request.user) || |
|
|
isRestrictedView(this.request.user) || |
|
|
(this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && |
|
|
(this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && |
|
|
this.request.user.subscription?.type === SubscriptionType.Basic) |
|
|
this.request.user.subscription?.type === SubscriptionType.Basic) |
|
|
@ -676,7 +660,7 @@ export class PortfolioController { |
|
|
@HasPermission(permissions.updateActivity) |
|
|
@HasPermission(permissions.updateActivity) |
|
|
@Put('holding/:dataSource/:symbol/tags') |
|
|
@Put('holding/:dataSource/:symbol/tags') |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard, ImpersonationGuard) |
|
|
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) |
|
|
public async updateHoldingTags( |
|
|
public async updateHoldingTags( |
|
|
@Body() data: UpdateHoldingTagsDto, |
|
|
@Body() data: UpdateHoldingTagsDto, |
|
|
@Param('dataSource') dataSource: DataSource, |
|
|
@Param('dataSource') dataSource: DataSource, |
|
|
|