Browse Source

Merge 6a6459c4a8 into 80e81a36a9

pull/7010/merge
Akash Negi 2 weeks ago
committed by GitHub
parent
commit
c3b190c9e3
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 29
      apps/api/src/app/import/import-data.dto.ts
  2. 12
      apps/api/src/app/import/import.controller.ts
  3. 43
      apps/api/src/app/import/import.service.ts
  4. 4
      apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts
  5. 13
      apps/client/src/app/services/import-activities.service.ts

29
apps/api/src/app/import/import-data.dto.ts

@ -6,9 +6,36 @@ import {
} from '@ghostfolio/common/dtos';
import { Type } from 'class-transformer';
import { IsArray, IsOptional, ValidateNested } from 'class-validator';
import {
IsArray,
IsOptional,
ValidateNested,
IsString,
IsUrl
} from 'class-validator';
export class ImportPlatformDto {
@IsOptional()
@IsString()
id?: string;
@IsString()
name: string;
@IsUrl({
protocols: ['http', 'https'],
require_protocol: true
})
url: string;
}
export class ImportDataDto {
@IsArray()
@IsOptional()
@Type(() => ImportPlatformDto)
@ValidateNested({ each: true })
platforms?: ImportPlatformDto[];
@IsArray()
@IsOptional()
@Type(() => CreateAccountWithBalancesDto)

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

@ -5,7 +5,7 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { SubscriptionType } from '@ghostfolio/common/enums';
import { ImportResponse } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
@ -50,15 +50,6 @@ export class ImportController {
): Promise<ImportResponse> {
const isDryRun = isDryRunParam === 'true';
if (
!hasPermission(this.request.user.permissions, permissions.createAccount)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
let maxActivitiesToImport = this.configurationService.get(
'MAX_ACTIVITIES_TO_IMPORT'
);
@ -77,6 +68,7 @@ export class ImportController {
accountsWithBalancesDto: importData.accounts ?? [],
activitiesDto: importData.activities,
assetProfilesWithMarketDataDto: importData.assetProfiles ?? [],
platformsDto: importData.platforms ?? [],
tagsDto: importData.tags ?? [],
user: this.request.user
});

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

@ -179,6 +179,7 @@ export class ImportService {
assetProfilesWithMarketDataDto,
isDryRun = false,
maxActivitiesToImport,
platformsDto,
tagsDto,
user
}: {
@ -187,11 +188,13 @@ export class ImportService {
assetProfilesWithMarketDataDto: ImportDataDto['assetProfiles'];
isDryRun?: boolean;
maxActivitiesToImport: number;
platformsDto: ImportDataDto['platforms'];
tagsDto: ImportDataDto['tags'];
user: UserWithSettings;
}): Promise<Activity[]> {
const accountIdMapping: { [oldAccountId: string]: string } = {};
const assetProfileSymbolMapping: { [oldSymbol: string]: string } = {};
const platformIdMapping: { [oldPlatformId: string]: string } = {};
const tagIdMapping: { [oldTagId: string]: string } = {};
const userCurrency = user.settings.settings.baseCurrency;
@ -209,6 +212,37 @@ export class ImportService {
this.platformService.getPlatforms()
]);
const canCreatePlatform = hasPermission(
user.permissions,
permissions.createPlatform
);
for (const platform of platformsDto ?? []) {
const existingPlatform = existingPlatforms.find(({ url }) => {
return url === platform.url;
});
if (existingPlatform) {
if (platform.id && platform.id !== existingPlatform.id) {
platformIdMapping[platform.id] = existingPlatform.id;
}
continue;
}
if (!canCreatePlatform) {
continue;
}
const newPlatform = await this.platformService.createPlatform({
...(platform.id && { id: platform.id }),
name: platform.name,
url: platform.url
});
existingPlatforms.push(newPlatform);
}
for (const accountWithBalances of accountsWithBalancesDto) {
// Check if there is any existing account with the same ID
const accountWithSameId = existingAccounts.find((existingAccount) => {
@ -240,14 +274,19 @@ export class ImportService {
user: { connect: { id: user.id } }
};
const resolvedPlatformId = platformId
? (platformIdMapping[platformId] ?? platformId)
: undefined;
if (
resolvedPlatformId &&
existingPlatforms.some(({ id }) => {
return id === platformId;
return id === resolvedPlatformId;
})
) {
accountObject = {
...accountObject,
platform: { connect: { id: platformId } }
platform: { connect: { id: resolvedPlatformId } }
};
}

4
apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts

@ -109,6 +109,7 @@ export class GfImportActivitiesDialogComponent {
private accounts: CreateAccountWithBalancesDto[] = [];
private activities: Activity[] = [];
private assetProfiles: CreateAssetProfileWithMarketDataDto[] = [];
private platforms: { id?: string; name: string; url: string }[] = [];
private tags: CreateTagDto[] = [];
private readonly changeDetectorRef = inject(ChangeDetectorRef);
@ -175,6 +176,7 @@ export class GfImportActivitiesDialogComponent {
accounts: this.accounts,
activities: this.selectedActivities,
assetProfiles: this.assetProfiles,
platforms: this.platforms,
tags: this.tags
});
@ -306,6 +308,7 @@ export class GfImportActivitiesDialogComponent {
this.accounts = content.accounts;
this.assetProfiles = content.assetProfiles;
this.platforms = content.platforms ?? [];
this.tags = content.tags;
if (!isArray(content.activities)) {
@ -339,6 +342,7 @@ export class GfImportActivitiesDialogComponent {
activities: content.activities,
assetProfiles: content.assetProfiles,
isDryRun: true,
platforms: content.platforms ?? [],
tags: content.tags
});

13
apps/client/src/app/services/import-activities.service.ts

@ -14,6 +14,12 @@ import { isFinite, isNumber, isString } from 'lodash';
import { parse as csvToJson } from 'papaparse';
import { firstValueFrom } from 'rxjs';
interface ImportPlatform {
id?: string;
name: string;
url: string;
}
@Injectable({
providedIn: 'root'
})
@ -115,12 +121,14 @@ export class ImportActivitiesService {
activities,
assetProfiles,
isDryRun = false,
platforms,
tags
}: {
activities: CreateOrderDto[];
accounts?: CreateAccountWithBalancesDto[];
assetProfiles?: CreateAssetProfileWithMarketDataDto[];
isDryRun?: boolean;
platforms?: ImportPlatform[];
tags?: CreateTagDto[];
}): Promise<{
activities: Activity[];
@ -131,6 +139,7 @@ export class ImportActivitiesService {
accounts,
activities,
assetProfiles,
platforms,
tags
},
isDryRun
@ -142,11 +151,13 @@ export class ImportActivitiesService {
accounts,
activities,
assetProfiles,
platforms,
tags
}: {
accounts?: CreateAccountWithBalancesDto[];
activities: Activity[];
assetProfiles?: CreateAssetProfileWithMarketDataDto[];
platforms?: ImportPlatform[];
tags?: CreateTagDto[];
}): Promise<{
activities: Activity[];
@ -158,6 +169,7 @@ export class ImportActivitiesService {
return this.importJson({
accounts,
assetProfiles,
platforms,
tags,
activities: importData
});
@ -457,6 +469,7 @@ export class ImportActivitiesService {
accounts?: CreateAccountWithBalancesDto[];
activities: CreateOrderDto[];
assetProfiles?: CreateAssetProfileWithMarketDataDto[];
platforms?: ImportPlatform[];
tags?: CreateTagDto[];
},
aIsDryRun = false

Loading…
Cancel
Save