Browse Source

Improve activities validation

pull/2958/head
Thomas Kaul 2 years ago
parent
commit
139001bc8b
  1. 2
      apps/api/src/app/import/import.controller.ts
  2. 47
      apps/api/src/app/import/import.service.ts
  3. 50
      apps/api/src/services/data-provider/data-provider.service.ts

2
apps/api/src/app/import/import.controller.ts

@ -73,7 +73,7 @@ export class ImportController {
userCurrency, userCurrency,
accountsDto: importData.accounts ?? [], accountsDto: importData.accounts ?? [],
activitiesDto: importData.activities, activitiesDto: importData.activities,
userId: this.request.user.id user: this.request.user
}); });
return { activities }; return { activities };

47
apps/api/src/app/import/import.service.ts

@ -21,7 +21,8 @@ import {
import { UniqueAsset } from '@ghostfolio/common/interfaces'; import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { import {
AccountWithPlatform, AccountWithPlatform,
OrderWithAccount OrderWithAccount,
UserWithSettings
} from '@ghostfolio/common/types'; } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource, Prisma, SymbolProfile } from '@prisma/client'; import { DataSource, Prisma, SymbolProfile } from '@prisma/client';
@ -139,14 +140,14 @@ export class ImportService {
isDryRun = false, isDryRun = false,
maxActivitiesToImport, maxActivitiesToImport,
userCurrency, userCurrency,
userId user
}: { }: {
accountsDto: Partial<CreateAccountDto>[]; accountsDto: Partial<CreateAccountDto>[];
activitiesDto: Partial<CreateOrderDto>[]; activitiesDto: Partial<CreateOrderDto>[];
isDryRun?: boolean; isDryRun?: boolean;
maxActivitiesToImport: number; maxActivitiesToImport: number;
userCurrency: string; userCurrency: string;
userId: string; user: UserWithSettings;
}): Promise<Activity[]> { }): Promise<Activity[]> {
const accountIdMapping: { [oldAccountId: string]: string } = {}; const accountIdMapping: { [oldAccountId: string]: string } = {};
@ -171,7 +172,7 @@ export class ImportService {
); );
// If there is no account or if the account belongs to a different user then create a new account // If there is no account or if the account belongs to a different user then create a new account
if (!accountWithSameId || accountWithSameId.userId !== userId) { if (!accountWithSameId || accountWithSameId.userId !== user.id) {
let oldAccountId: string; let oldAccountId: string;
const platformId = account.platformId; const platformId = account.platformId;
@ -184,7 +185,7 @@ export class ImportService {
let accountObject: Prisma.AccountCreateInput = { let accountObject: Prisma.AccountCreateInput = {
...account, ...account,
User: { connect: { id: userId } } User: { connect: { id: user.id } }
}; };
if ( if (
@ -200,7 +201,7 @@ export class ImportService {
const newAccount = await this.accountService.createAccount( const newAccount = await this.accountService.createAccount(
accountObject, accountObject,
userId user.id
); );
// Store the new to old account ID mappings for updating activities // Store the new to old account ID mappings for updating activities
@ -231,16 +232,17 @@ export class ImportService {
const assetProfiles = await this.validateActivities({ const assetProfiles = await this.validateActivities({
activitiesDto, activitiesDto,
maxActivitiesToImport maxActivitiesToImport,
user
}); });
const activitiesExtendedWithErrors = await this.extendActivitiesWithErrors({ const activitiesExtendedWithErrors = await this.extendActivitiesWithErrors({
activitiesDto, activitiesDto,
userCurrency, userCurrency,
userId userId: user.id
}); });
const accounts = (await this.accountService.getAccounts(userId)).map( const accounts = (await this.accountService.getAccounts(user.id)).map(
({ id, name }) => { ({ id, name }) => {
return { id, name }; return { id, name };
} }
@ -345,7 +347,6 @@ export class ImportService {
quantity, quantity,
type, type,
unitPrice, unitPrice,
userId,
accountId: validatedAccount?.id, accountId: validatedAccount?.id,
accountUserId: undefined, accountUserId: undefined,
createdAt: new Date(), createdAt: new Date(),
@ -374,7 +375,8 @@ export class ImportService {
}, },
Account: validatedAccount, Account: validatedAccount,
symbolProfileId: undefined, symbolProfileId: undefined,
updatedAt: new Date() updatedAt: new Date(),
userId: user.id
}; };
} else { } else {
if (error) { if (error) {
@ -388,7 +390,6 @@ export class ImportService {
quantity, quantity,
type, type,
unitPrice, unitPrice,
userId,
accountId: validatedAccount?.id, accountId: validatedAccount?.id,
SymbolProfile: { SymbolProfile: {
connectOrCreate: { connectOrCreate: {
@ -405,8 +406,9 @@ export class ImportService {
} }
} }
}, },
userId: user.id,
updateAccountBalance: false, updateAccountBalance: false,
User: { connect: { id: userId } } User: { connect: { id: user.id } }
}); });
} }
@ -553,10 +555,12 @@ export class ImportService {
private async validateActivities({ private async validateActivities({
activitiesDto, activitiesDto,
maxActivitiesToImport maxActivitiesToImport,
user
}: { }: {
activitiesDto: Partial<CreateOrderDto>[]; activitiesDto: Partial<CreateOrderDto>[];
maxActivitiesToImport: number; maxActivitiesToImport: number;
user: UserWithSettings;
}) { }) {
if (activitiesDto?.length > maxActivitiesToImport) { if (activitiesDto?.length > maxActivitiesToImport) {
throw new Error(`Too many activities (${maxActivitiesToImport} at most)`); throw new Error(`Too many activities (${maxActivitiesToImport} at most)`);
@ -583,6 +587,21 @@ export class ImportService {
); );
} }
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
user.subscription.type === 'Basic'
) {
const dataProvider = this.dataProviderService.getDataProvider(
DataSource[dataSource]
);
if (dataProvider.getDataProviderInfo().isPremium) {
throw new Error(
`activities.${index}.dataSource ("${dataSource}") is not valid`
);
}
}
const assetProfile = { const assetProfile = {
currency, currency,
...( ...(

50
apps/api/src/services/data-provider/data-provider.service.ts

@ -107,6 +107,31 @@ export class DataProviderService {
return response; return response;
} }
public getDataProvider(providerName: DataSource) {
for (const dataProviderInterface of this.dataProviderInterfaces) {
if (this.dataProviderMapping[dataProviderInterface.getName()]) {
const mappedDataProviderInterface = this.dataProviderInterfaces.find(
(currentDataProviderInterface) => {
return (
currentDataProviderInterface.getName() ===
this.dataProviderMapping[dataProviderInterface.getName()]
);
}
);
if (mappedDataProviderInterface) {
return mappedDataProviderInterface;
}
}
if (dataProviderInterface.getName() === providerName) {
return dataProviderInterface;
}
}
throw new Error('No data provider has been found.');
}
public getDataSourceForExchangeRates(): DataSource { public getDataSourceForExchangeRates(): DataSource {
return DataSource[ return DataSource[
this.configurationService.get('DATA_SOURCE_EXCHANGE_RATES') this.configurationService.get('DATA_SOURCE_EXCHANGE_RATES')
@ -567,31 +592,6 @@ export class DataProviderService {
}; };
} }
private getDataProvider(providerName: DataSource) {
for (const dataProviderInterface of this.dataProviderInterfaces) {
if (this.dataProviderMapping[dataProviderInterface.getName()]) {
const mappedDataProviderInterface = this.dataProviderInterfaces.find(
(currentDataProviderInterface) => {
return (
currentDataProviderInterface.getName() ===
this.dataProviderMapping[dataProviderInterface.getName()]
);
}
);
if (mappedDataProviderInterface) {
return mappedDataProviderInterface;
}
}
if (dataProviderInterface.getName() === providerName) {
return dataProviderInterface;
}
}
throw new Error('No data provider has been found.');
}
private hasCurrency({ private hasCurrency({
currency, currency,
dataGatheringItems dataGatheringItems

Loading…
Cancel
Save