mirror of https://github.com/ghostfolio/ghostfolio
committed by
GitHub
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