mirror of https://github.com/ghostfolio/ghostfolio
7 changed files with 171 additions and 0 deletions
@ -0,0 +1,41 @@ |
|||
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; |
|||
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; |
|||
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; |
|||
import { UpdateAssetProfileDataDto } from '@ghostfolio/common/dtos'; |
|||
import { EnhancedSymbolProfile } from '@ghostfolio/common/interfaces'; |
|||
import { permissions } from '@ghostfolio/common/permissions'; |
|||
|
|||
import { |
|||
Body, |
|||
Controller, |
|||
Param, |
|||
Patch, |
|||
UseGuards, |
|||
UseInterceptors |
|||
} from '@nestjs/common'; |
|||
import { AuthGuard } from '@nestjs/passport'; |
|||
import { DataSource } from '@prisma/client'; |
|||
|
|||
import { AssetProfilesService } from './asset-profiles.service'; |
|||
|
|||
@Controller('asset-profiles') |
|||
export class AssetProfilesController { |
|||
public constructor( |
|||
private readonly assetProfilesService: AssetProfilesService |
|||
) {} |
|||
|
|||
@HasPermission(permissions.accessAdminControl) |
|||
@Patch(':dataSource/:symbol') |
|||
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) |
|||
@UseInterceptors(TransformDataSourceInRequestInterceptor) |
|||
public async updateAssetProfileData( |
|||
@Body() assetProfileData: UpdateAssetProfileDataDto, |
|||
@Param('dataSource') dataSource: DataSource, |
|||
@Param('symbol') symbol: string |
|||
): Promise<EnhancedSymbolProfile> { |
|||
return this.assetProfilesService.updateAssetProfileData( |
|||
{ dataSource, symbol }, |
|||
assetProfileData |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; |
|||
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; |
|||
|
|||
import { Module } from '@nestjs/common'; |
|||
|
|||
import { AssetProfilesController } from './asset-profiles.controller'; |
|||
import { AssetProfilesService } from './asset-profiles.service'; |
|||
|
|||
@Module({ |
|||
controllers: [AssetProfilesController], |
|||
imports: [SymbolProfileModule, TransformDataSourceInRequestModule], |
|||
providers: [AssetProfilesService] |
|||
}) |
|||
export class AssetProfilesModule {} |
|||
@ -0,0 +1,95 @@ |
|||
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; |
|||
import { UpdateAssetProfileDataDto } from '@ghostfolio/common/dtos'; |
|||
import { |
|||
AssetProfileIdentifier, |
|||
EnhancedSymbolProfile |
|||
} from '@ghostfolio/common/interfaces'; |
|||
|
|||
import { Injectable, NotFoundException } from '@nestjs/common'; |
|||
import { DataSource, Prisma } from '@prisma/client'; |
|||
|
|||
@Injectable() |
|||
export class AssetProfilesService { |
|||
public constructor( |
|||
private readonly symbolProfileService: SymbolProfileService |
|||
) {} |
|||
|
|||
public async updateAssetProfileData( |
|||
{ dataSource, symbol }: AssetProfileIdentifier, |
|||
assetProfileData: UpdateAssetProfileDataDto |
|||
): Promise<EnhancedSymbolProfile> { |
|||
const [assetProfile] = await this.symbolProfileService.getSymbolProfiles([ |
|||
{ |
|||
dataSource, |
|||
symbol |
|||
} |
|||
]); |
|||
|
|||
if (!assetProfile) { |
|||
throw new NotFoundException( |
|||
`Asset profile with data source ${dataSource} and symbol ${symbol} not found` |
|||
); |
|||
} |
|||
|
|||
const data = this.getAssetProfileDataUpdate(assetProfileData); |
|||
|
|||
if (Object.keys(data).length === 0) { |
|||
return assetProfile; |
|||
} |
|||
|
|||
await this.symbolProfileService.updateSymbolProfile( |
|||
{ |
|||
dataSource, |
|||
symbol |
|||
}, |
|||
dataSource === DataSource.MANUAL |
|||
? data |
|||
: { |
|||
SymbolProfileOverrides: { |
|||
upsert: { |
|||
create: data, |
|||
update: data |
|||
} |
|||
} |
|||
} |
|||
); |
|||
|
|||
const [updatedAssetProfile] = |
|||
await this.symbolProfileService.getSymbolProfiles([ |
|||
{ |
|||
dataSource, |
|||
symbol |
|||
} |
|||
]); |
|||
|
|||
return updatedAssetProfile; |
|||
} |
|||
|
|||
private getAssetProfileDataUpdate({ |
|||
countries, |
|||
holdings, |
|||
sectors |
|||
}: UpdateAssetProfileDataDto): Pick< |
|||
Prisma.SymbolProfileUpdateInput, |
|||
'countries' | 'holdings' | 'sectors' |
|||
> { |
|||
const data: Pick< |
|||
Prisma.SymbolProfileUpdateInput, |
|||
'countries' | 'holdings' | 'sectors' |
|||
> = {}; |
|||
|
|||
if (countries !== undefined) { |
|||
data.countries = countries as Prisma.JsonArray; |
|||
} |
|||
|
|||
if (holdings !== undefined) { |
|||
data.holdings = holdings as Prisma.JsonArray; |
|||
} |
|||
|
|||
if (sectors !== undefined) { |
|||
data.sectors = sectors as Prisma.JsonArray; |
|||
} |
|||
|
|||
return data; |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
import { Prisma } from '@prisma/client'; |
|||
import { IsArray, IsOptional } from 'class-validator'; |
|||
|
|||
export class UpdateAssetProfileDataDto { |
|||
@IsArray() |
|||
@IsOptional() |
|||
countries?: Prisma.InputJsonArray; |
|||
|
|||
@IsArray() |
|||
@IsOptional() |
|||
holdings?: Prisma.InputJsonArray; |
|||
|
|||
@IsArray() |
|||
@IsOptional() |
|||
sectors?: Prisma.InputJsonArray; |
|||
} |
|||
Loading…
Reference in new issue