diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 14f24360f..78ac8c98b 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -448,24 +448,45 @@ export class AdminController { ); } - await this.adminService.patchAssetProfileData({ - dataSource, - symbol, - tags: { - set: [] - } - }); + if (dataSource == 'MANUAL') { + await this.adminService.patchAssetProfileData({ + dataSource, + symbol, + tags: { + set: [] + } + }); - return this.adminService.patchAssetProfileData({ - ...assetProfileData, - dataSource, - symbol, - tags: { - connect: assetProfileData.tags?.map(({ id }) => { - return { id }; - }) - } - }); + return this.adminService.patchAssetProfileData({ + ...assetProfileData, + dataSource, + symbol, + tags: { + connect: assetProfileData.tags?.map(({ id }) => { + return { id }; + }) + } + }); + } else { + await this.adminService.patchAssetProfileData({ + dataSource, + symbol, + tags: { + set: [] + } + }); + + return this.adminService.patchAssetProfileData({ + ...assetProfileData, + dataSource, + symbol, + tags: { + connect: assetProfileData.tags?.map(({ id }) => { + return { id }; + }) + } + }); + } } @Put('settings/:key') diff --git a/apps/api/src/app/admin/admin.module.ts b/apps/api/src/app/admin/admin.module.ts index 079af87fa..c018d8615 100644 --- a/apps/api/src/app/admin/admin.module.ts +++ b/apps/api/src/app/admin/admin.module.ts @@ -13,6 +13,7 @@ import { Module } from '@nestjs/common'; import { AdminController } from './admin.controller'; import { AdminService } from './admin.service'; import { QueueModule } from './queue/queue.module'; +import { SymbolProfileOverwriteModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile-overwrite.module'; @Module({ imports: [ @@ -26,7 +27,8 @@ import { QueueModule } from './queue/queue.module'; PropertyModule, QueueModule, SubscriptionModule, - SymbolProfileModule + SymbolProfileModule, + SymbolProfileOverwriteModule ], controllers: [AdminController], providers: [AdminService], diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 5cd14930b..58e5469a0 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -6,6 +6,7 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { SymbolProfileOverwriteService } from '@ghostfolio/api/services/symbol-profile/symbol-profile-overwrite.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { DEFAULT_CURRENCY, @@ -29,7 +30,8 @@ import { Property, SymbolProfile, DataSource, - Tag + Tag, + SymbolProfileOverrides } from '@prisma/client'; import { differenceInDays } from 'date-fns'; import { groupBy } from 'lodash'; @@ -44,7 +46,8 @@ export class AdminService { private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly subscriptionService: SubscriptionService, - private readonly symbolProfileService: SymbolProfileService + private readonly symbolProfileService: SymbolProfileService, + private readonly symbolProfileOverwriteService: SymbolProfileOverwriteService ) {} public async addAssetProfile({ @@ -331,17 +334,65 @@ export class AdminService { symbol, symbolMapping }: Prisma.SymbolProfileUpdateInput & UniqueAsset) { - await this.symbolProfileService.updateSymbolProfile({ - assetClass, - assetSubClass, - comment, - dataSource, - name, - tags, - scraperConfiguration, - symbol, - symbolMapping - }); + if (dataSource === 'MANUAL') { + await this.symbolProfileService.updateSymbolProfile({ + assetClass, + assetSubClass, + comment, + dataSource, + name, + tags, + scraperConfiguration, + symbol, + symbolMapping + }); + } else { + await this.symbolProfileService.updateSymbolProfile({ + comment, + dataSource, + name, + tags, + scraperConfiguration, + symbol, + symbolMapping + }); + + let symbolProfileId = + await this.symbolProfileOverwriteService.GetSymbolProfileId( + symbol, + dataSource + ); + if (symbolProfileId) { + await this.symbolProfileOverwriteService.updateSymbolProfileOverrides({ + assetClass, + assetSubClass, + symbolProfileId + }); + } else { + symbolProfileId = await this.symbolProfileService.getSymbolProfiles([ + { + dataSource, + symbol + } + ])[0]; + + await this.symbolProfileOverwriteService.add({ + SymbolProfile: { + connect: { + dataSource_symbol: { + dataSource, + symbol + } + } + } + }); + await this.symbolProfileOverwriteService.updateSymbolProfileOverrides({ + assetClass, + assetSubClass, + symbolProfileId + }); + } + } const [symbolProfile] = await this.symbolProfileService.getSymbolProfiles([ { diff --git a/apps/api/src/services/symbol-profile/symbol-profile-overwrite.module.ts b/apps/api/src/services/symbol-profile/symbol-profile-overwrite.module.ts new file mode 100644 index 000000000..3015b268c --- /dev/null +++ b/apps/api/src/services/symbol-profile/symbol-profile-overwrite.module.ts @@ -0,0 +1,11 @@ +import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { Module } from '@nestjs/common'; + +import { SymbolProfileOverwriteService } from './symbol-profile-overwrite.service'; + +@Module({ + imports: [PrismaModule], + providers: [SymbolProfileOverwriteService], + exports: [SymbolProfileOverwriteService] +}) +export class SymbolProfileOverwriteModule {} diff --git a/apps/api/src/services/symbol-profile/symbol-profile-overwrite.service.ts b/apps/api/src/services/symbol-profile/symbol-profile-overwrite.service.ts new file mode 100644 index 000000000..1b1326849 --- /dev/null +++ b/apps/api/src/services/symbol-profile/symbol-profile-overwrite.service.ts @@ -0,0 +1,68 @@ +import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { Injectable } from '@nestjs/common'; +import { DataSource, Prisma, SymbolProfileOverrides } from '@prisma/client'; + +@Injectable() +export class SymbolProfileOverwriteService { + public constructor(private readonly prismaService: PrismaService) {} + + public async add( + assetProfileOverwrite: Prisma.SymbolProfileOverridesCreateInput + ): Promise { + return this.prismaService.symbolProfileOverrides.create({ + data: assetProfileOverwrite + }); + } + + public async delete(symbolProfileId: string) { + return this.prismaService.symbolProfileOverrides.delete({ + where: { symbolProfileId: symbolProfileId } + }); + } + + public updateSymbolProfileOverrides({ + assetClass, + assetSubClass, + name, + countries, + sectors, + url, + symbolProfileId + }: Prisma.SymbolProfileOverridesUpdateInput & { symbolProfileId: string }) { + return this.prismaService.symbolProfileOverrides.update({ + data: { + assetClass, + assetSubClass, + name, + countries, + sectors, + url + }, + where: { symbolProfileId: symbolProfileId } + }); + } + + public async GetSymbolProfileId( + Symbol: string, + datasource: DataSource + ): Promise { + let SymbolProfileId = await this.prismaService.symbolProfile + .findFirst({ + where: { + symbol: Symbol, + dataSource: datasource + } + }) + .then((s) => s.id); + + let symbolProfileIdSaved = await this.prismaService.symbolProfileOverrides + .findFirst({ + where: { + symbolProfileId: SymbolProfileId + } + }) + .then((s) => s?.symbolProfileId); + + return symbolProfileIdSaved; + } +}