@ -1,9 +1,3 @@
import { AccessService } from '@ghostfolio/api/app/access/access.service' ;
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service' ;
import { UserService } from '@ghostfolio/api/app/user/user.service' ;
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor' ;
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service' ;
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service' ;
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config' ;
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config' ;
import { getSum } from '@ghostfolio/common/helper' ;
import { getSum } from '@ghostfolio/common/helper' ;
import { PublicPortfolioResponse } from '@ghostfolio/common/interfaces' ;
import { PublicPortfolioResponse } from '@ghostfolio/common/interfaces' ;
@ -21,18 +15,29 @@ import { REQUEST } from '@nestjs/core';
import { Big } from 'big.js' ;
import { Big } from 'big.js' ;
import { StatusCodes , getReasonPhrase } from 'http-status-codes' ;
import { StatusCodes , getReasonPhrase } from 'http-status-codes' ;
import { RedactValuesInResponseInterceptor } from '../../../interceptors/redact-values-in-response/redact-values-in-response.interceptor' ;
import { TransformDataSourceInResponseInterceptor } from '../../../interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor' ;
import { ConfigurationService } from '../../../services/configuration/configuration.service' ;
import { ExchangeRateDataService } from '../../../services/exchange-rate-data/exchange-rate-data.service' ;
import { AccessService } from '../../access/access.service' ;
import { OrderService } from '../../order/order.service' ;
import { PortfolioService } from '../../portfolio/portfolio.service' ;
import { UserService } from '../../user/user.service' ;
@Controller ( 'public' )
@Controller ( 'public' )
export class PublicController {
export class PublicController {
public constructor (
public constructor (
private readonly accessService : AccessService ,
private readonly accessService : AccessService ,
private readonly configurationService : ConfigurationService ,
private readonly configurationService : ConfigurationService ,
private readonly exchangeRateDataService : ExchangeRateDataService ,
private readonly exchangeRateDataService : ExchangeRateDataService ,
private readonly _orderService : OrderService ,
private readonly portfolioService : PortfolioService ,
private readonly portfolioService : PortfolioService ,
@Inject ( REQUEST ) private readonly request : RequestWithUser ,
@Inject ( REQUEST ) private readonly request : RequestWithUser ,
private readonly userService : UserService
private readonly userService : UserService
) { }
) { }
@Get ( ':accessId/portfolio' )
@Get ( ':accessId/portfolio' )
@UseInterceptors ( RedactValuesInResponseInterceptor )
@UseInterceptors ( TransformDataSourceInResponseInterceptor )
@UseInterceptors ( TransformDataSourceInResponseInterceptor )
public async getPublicPortfolio (
public async getPublicPortfolio (
@Param ( 'accessId' ) accessId
@Param ( 'accessId' ) accessId
@ -56,26 +61,69 @@ export class PublicController {
hasDetails = user . subscription . type === 'Premium' ;
hasDetails = user . subscription . type === 'Premium' ;
}
}
const detailsPromise = this . portfolioService . getDetails ( {
impersonationId : access.userId ,
userId : user.id ,
withMarkets : true
} ) ;
const performance1dPromise = this . portfolioService . getPerformance ( {
dateRange : '1d' ,
impersonationId : undefined ,
userId : user.id
} ) ;
const performanceMaxPromise = this . portfolioService . getPerformance ( {
dateRange : 'max' ,
impersonationId : undefined ,
userId : user.id
} ) ;
const performanceYtdPromise = this . portfolioService . getPerformance ( {
dateRange : 'ytd' ,
impersonationId : undefined ,
userId : user.id
} ) ;
const latestActivitiesPromise = this . _orderService . getOrders ( {
includeDrafts : false ,
take : 10 ,
sortColumn : 'date' ,
sortDirection : 'desc' ,
userCurrency :
this . request . user ? . settings ? . settings . baseCurrency ? ? DEFAULT_CURRENCY ,
userId : user.id ,
withExcludedAccountsAndActivities : false
} ) ;
const [
const [
{ createdAt , holdings , markets } ,
{ createdAt , holdings , markets } ,
{ performance : performance1d } ,
{ performance : performance1d } ,
{ performance : performanceMax } ,
{ performance : performanceMax } ,
{ performance : performanceYtd }
{ performance : performanceYtd }
] = await Promise . all ( [
] = await Promise . all ( [
this . portfolioService . getDetails ( {
detailsPromise ,
impersonationId : access.userId ,
performance1dPromise ,
userId : user.id ,
performanceMaxPromise ,
withMarkets : true
performanceYtdPromise
} ) ,
. . . [ '1d' , 'max' , 'ytd' ] . map ( ( dateRange ) = > {
return this . portfolioService . getPerformance ( {
dateRange ,
impersonationId : undefined ,
userId : user.id
} ) ;
} )
] ) ;
] ) ;
const { activities } = await latestActivitiesPromise ;
const latestActivities = activities . map ( ( a ) = > {
return {
account : a.account
? { name : a.account.name , currency : a.account.currency }
: undefined ,
dataSource : a.SymbolProfile?.dataSource ,
date : a.date ,
name : a.SymbolProfile?.name ? ? '' ,
quantity : a.quantity ,
symbol : a . SymbolProfile ? . symbol ? ? '' ,
type : a . type ,
unitPrice : a.unitPrice
} ;
} ) ;
Object . values ( markets ? ? { } ) . forEach ( ( market ) = > {
Object . values ( markets ? ? { } ) . forEach ( ( market ) = > {
delete market . valueInBaseCurrency ;
delete market . valueInBaseCurrency ;
} ) ;
} ) ;
@ -83,6 +131,7 @@ export class PublicController {
const publicPortfolioResponse : PublicPortfolioResponse = {
const publicPortfolioResponse : PublicPortfolioResponse = {
createdAt ,
createdAt ,
hasDetails ,
hasDetails ,
latestActivities ,
markets ,
markets ,
alias : access.alias ,
alias : access.alias ,
holdings : { } ,
holdings : { } ,