Browse Source

Bugfix/base currency in impersonation mode (#6964)

* Fix base currency in impersonation mode

* Update changelog
pull/6980/head
Thomas Kaul 3 hours ago
committed by GitHub
parent
commit
9996d8a8d2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 11
      apps/api/src/app/account/account.controller.ts
  3. 4
      apps/api/src/app/account/account.module.ts
  4. 11
      apps/api/src/app/portfolio/portfolio.controller.ts
  5. 7
      apps/api/src/app/portfolio/portfolio.service.ts
  6. 31
      apps/api/src/app/user/user.service.ts

1
CHANGELOG.md

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Resolved an issue in the impersonation mode where the values did not match the owner’s currency
- Fixed the environment variable expansion in the `.env` file when debugging via _Visual Studio Code_
## 3.6.0 - 2026-05-28

11
apps/api/src/app/account/account.controller.ts

@ -1,5 +1,6 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor';
@ -50,7 +51,8 @@ export class AccountController {
private readonly apiService: ApiService,
private readonly impersonationService: ImpersonationService,
private readonly portfolioService: PortfolioService,
@Inject(REQUEST) private readonly request: RequestWithUser
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly userService: UserService
) {}
@Delete(':id')
@ -137,11 +139,14 @@ export class AccountController {
): Promise<AccountBalancesResponse> {
const impersonationUserId =
await this.impersonationService.validateImpersonationId(impersonationId);
const userId = impersonationUserId || this.request.user.id;
const { settings } = await this.userService.user({ id: userId });
return this.accountBalanceService.getAccountBalances({
userId,
filters: [{ id, type: 'ACCOUNT' }],
userCurrency: this.request.user.settings.settings.baseCurrency,
userId: impersonationUserId || this.request.user.id
userCurrency: settings.settings.baseCurrency
});
}

4
apps/api/src/app/account/account.module.ts

@ -1,5 +1,6 @@
import { AccountBalanceModule } from '@ghostfolio/api/app/account-balance/account-balance.module';
import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
@ -23,7 +24,8 @@ import { AccountService } from './account.service';
ImpersonationModule,
PortfolioModule,
PrismaModule,
RedactValuesInResponseModule
RedactValuesInResponseModule,
UserModule
],
providers: [AccountService]
})

11
apps/api/src/app/portfolio/portfolio.controller.ts

@ -1,4 +1,5 @@
import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import {
@ -70,7 +71,8 @@ export class PortfolioController {
private readonly configurationService: ConfigurationService,
private readonly impersonationService: ImpersonationService,
private readonly portfolioService: PortfolioService,
@Inject(REQUEST) private readonly request: RequestWithUser
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly userService: UserService
) {}
@Get('details')
@ -340,7 +342,10 @@ export class PortfolioController {
const impersonationUserId =
await this.impersonationService.validateImpersonationId(impersonationId);
const userCurrency = this.request.user.settings.settings.baseCurrency;
const userId = impersonationUserId || this.request.user.id;
const { settings } = await this.userService.user({ id: userId });
const userCurrency = settings.settings.baseCurrency;
const { endDate, startDate } = getIntervalFromDateRange({ dateRange });
@ -349,7 +354,7 @@ export class PortfolioController {
filters,
startDate,
userCurrency,
userId: impersonationUserId || this.request.user.id,
userId,
types: ['DIVIDEND']
});

7
apps/api/src/app/portfolio/portfolio.service.ts

@ -164,7 +164,7 @@ export class PortfolioService {
};
}
const [accounts, details] = await Promise.all([
const [accounts, details, user] = await Promise.all([
this.accountService.accounts({
where,
include: {
@ -178,10 +178,11 @@ export class PortfolioService {
withExcludedAccounts,
impersonationId: userId,
userId: this.request.user.id
})
}),
this.userService.user({ id: userId })
]);
const userCurrency = this.request.user.settings.settings.baseCurrency;
const userCurrency = this.getUserCurrency(user);
return Promise.all(
accounts.map(async (account) => {

31
apps/api/src/app/user/user.service.ts

@ -49,7 +49,7 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance
import { Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Prisma, Role, User } from '@prisma/client';
import { Prisma, Role, Settings, User } from '@prisma/client';
import { differenceInDays, subDays } from 'date-fns';
import { without } from 'lodash';
import { createHmac } from 'node:crypto';
@ -109,7 +109,14 @@ export class UserService {
}): Promise<IUser> {
const { id, permissions, settings, subscription } = user;
const userData = await Promise.all([
const [
access,
accounts,
activitiesCount,
firstActivity,
impersonationUserSettings,
tagsForUser
] = await Promise.all([
this.prismaService.access.findMany({
include: {
user: true
@ -134,16 +141,17 @@ export class UserService {
},
where: { userId: impersonationUserId || user.id }
}),
impersonationUserId
? this.prismaService.settings.findUnique({
where: { userId: impersonationUserId }
})
: Promise.resolve<Settings>(null),
this.tagService.getTagsForUser(impersonationUserId || user.id)
]);
const access = userData[0];
const accounts = userData[1];
const activitiesCount = userData[2];
const firstActivity = userData[3];
let tags = userData[4].filter((tag) => {
return tag.id !== TAG_ID_EXCLUDE_FROM_ANALYSIS;
});
const baseCurrency =
(impersonationUserSettings?.settings as UserSettings)?.baseCurrency ??
(settings.settings as UserSettings)?.baseCurrency;
let systemMessage: SystemMessage;
@ -156,6 +164,10 @@ export class UserService {
systemMessage = systemMessageProperty;
}
let tags = tagsForUser.filter((tag) => {
return tag.id !== TAG_ID_EXCLUDE_FROM_ANALYSIS;
});
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
subscription.type === SubscriptionType.Basic
@ -183,6 +195,7 @@ export class UserService {
dateOfFirstActivity: firstActivity?.date ?? new Date(),
settings: {
...(settings.settings as UserSettings),
baseCurrency,
locale: (settings.settings as UserSettings)?.locale ?? locale
}
};

Loading…
Cancel
Save