Browse Source

Refactor currency and view mode in the user user settings

pull/1239/head
Thomas 3 years ago
parent
commit
b931762b45
  1. 6
      apps/api/src/app/portfolio/portfolio.service.ts
  2. 3
      apps/api/src/app/portfolio/rules.service.ts
  3. 7
      apps/api/src/app/user/interfaces/user-settings-params.interface.ts
  4. 11
      apps/api/src/app/user/update-user-setting.dto.ts
  5. 10
      apps/api/src/app/user/update-user-settings.dto.ts
  6. 31
      apps/api/src/app/user/user.controller.ts
  7. 67
      apps/api/src/app/user/user.service.ts
  8. 2
      apps/api/src/models/interfaces/rule.interface.ts
  9. 3
      apps/api/src/models/interfaces/user-settings.interface.ts
  10. 3
      apps/api/src/models/rule.ts
  11. 4
      apps/api/src/models/rules/account-cluster-risk/current-investment.ts
  12. 4
      apps/api/src/models/rules/account-cluster-risk/initial-investment.ts
  13. 3
      apps/api/src/models/rules/account-cluster-risk/single-account.ts
  14. 2
      apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
  15. 2
      apps/api/src/models/rules/currency-cluster-risk/base-currency-initial-investment.ts
  16. 2
      apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
  17. 2
      apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts
  18. 2
      apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
  19. 23
      apps/client/src/app/pages/account/account-page.component.ts
  20. 4
      apps/client/src/app/pages/account/account-page.html
  21. 5
      apps/client/src/app/services/data.service.ts

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

@ -1045,7 +1045,7 @@ export class PortfolioService {
accounts accounts
) )
], ],
{ baseCurrency: currency } <UserSettings>this.request.user.Settings.settings
), ),
currencyClusterRisk: await this.rulesService.evaluate( currencyClusterRisk: await this.rulesService.evaluate(
[ [
@ -1066,7 +1066,7 @@ export class PortfolioService {
currentPositions currentPositions
) )
], ],
{ baseCurrency: currency } <UserSettings>this.request.user.Settings.settings
), ),
fees: await this.rulesService.evaluate( fees: await this.rulesService.evaluate(
[ [
@ -1076,7 +1076,7 @@ export class PortfolioService {
this.getFees(orders).toNumber() this.getFees(orders).toNumber()
) )
], ],
{ baseCurrency: currency } <UserSettings>this.request.user.Settings.settings
) )
} }
}; };

3
apps/api/src/app/portfolio/rules.service.ts

@ -1,5 +1,6 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { Rule } from '@ghostfolio/api/models/rule'; import { Rule } from '@ghostfolio/api/models/rule';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
@ -8,7 +9,7 @@ export class RulesService {
public async evaluate<T extends RuleSettings>( public async evaluate<T extends RuleSettings>(
aRules: Rule<T>[], aRules: Rule<T>[],
aUserSettings: { baseCurrency: string } aUserSettings: UserSettings
) { ) {
return aRules return aRules
.filter((rule) => { .filter((rule) => {

7
apps/api/src/app/user/interfaces/user-settings-params.interface.ts

@ -1,7 +0,0 @@
import { ViewMode } from '@prisma/client';
export interface UserSettingsParams {
currency?: string;
userId: string;
viewMode?: ViewMode;
}

11
apps/api/src/app/user/update-user-setting.dto.ts

@ -1,4 +1,5 @@
import { DateRange } from '@ghostfolio/common/types'; import type { DateRange } from '@ghostfolio/common/types';
import { ViewMode } from '@prisma/client';
import { import {
IsBoolean, IsBoolean,
IsIn, IsIn,
@ -8,6 +9,10 @@ import {
} from 'class-validator'; } from 'class-validator';
export class UpdateUserSettingDto { export class UpdateUserSettingDto {
@IsOptional()
@IsString()
baseCurrency?: string;
@IsIn(<DateRange[]>['1d', '1y', '5y', 'max', 'ytd']) @IsIn(<DateRange[]>['1d', '1y', '5y', 'max', 'ytd'])
@IsOptional() @IsOptional()
dateRange?: DateRange; dateRange?: DateRange;
@ -35,4 +40,8 @@ export class UpdateUserSettingDto {
@IsNumber() @IsNumber()
@IsOptional() @IsOptional()
savingsRate?: number; savingsRate?: number;
@IsIn(<ViewMode[]>['DEFAULT', 'ZEN'])
@IsOptional()
viewMode?: ViewMode;
} }

10
apps/api/src/app/user/update-user-settings.dto.ts

@ -1,10 +0,0 @@
import { ViewMode } from '@prisma/client';
import { IsString } from 'class-validator';
export class UpdateUserSettingsDto {
@IsString()
baseCurrency: string;
@IsString()
viewMode: ViewMode;
}

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

@ -24,9 +24,7 @@ import { User as UserModel } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { UserItem } from './interfaces/user-item.interface'; import { UserItem } from './interfaces/user-item.interface';
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
import { UpdateUserSettingDto } from './update-user-setting.dto'; import { UpdateUserSettingDto } from './update-user-setting.dto';
import { UpdateUserSettingsDto } from './update-user-settings.dto';
import { UserService } from './user.service'; import { UserService } from './user.service';
@Controller('user') @Controller('user')
@ -129,33 +127,4 @@ export class UserController {
userId: this.request.user.id userId: this.request.user.id
}); });
} }
@Put('settings')
@UseGuards(AuthGuard('jwt'))
public async updateUserSettings(@Body() data: UpdateUserSettingsDto) {
if (
!hasPermission(
this.request.user.permissions,
permissions.updateUserSettings
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const userSettings: UserSettingsParams = {
currency: data.baseCurrency,
userId: this.request.user.id
};
if (
hasPermission(this.request.user.permissions, permissions.updateViewMode)
) {
userSettings.viewMode = data.viewMode;
}
return await this.userService.updateUserSettings(userSettings);
}
} }

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

@ -15,11 +15,9 @@ import {
permissions permissions
} from '@ghostfolio/common/permissions'; } from '@ghostfolio/common/permissions';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Prisma, Role, User, ViewMode } from '@prisma/client'; import { Prisma, Role, User } from '@prisma/client';
import { sortBy } from 'lodash'; import { sortBy } from 'lodash';
import { UserSettingsParams } from './interfaces/user-settings-params.interface';
const crypto = require('crypto'); const crypto = require('crypto');
@Injectable() @Injectable()
@ -72,13 +70,7 @@ export class UserService {
accounts: Account, accounts: Account,
settings: { settings: {
...(<UserSettings>(<unknown>Settings.settings)), ...(<UserSettings>(<unknown>Settings.settings)),
baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY, locale: (<UserSettings>(<unknown>Settings.settings))?.locale ?? aLocale
dateRange:
Settings?.viewMode === 'ZEN'
? 'max'
: (<UserSettings>(<unknown>Settings.settings))?.dateRange ?? 'max',
locale: (<UserSettings>(<unknown>Settings.settings))?.locale ?? aLocale,
viewMode: Settings?.viewMode ?? ViewMode.DEFAULT
} }
}; };
} }
@ -136,21 +128,37 @@ export class UserService {
}; };
if (user?.Settings) { if (user?.Settings) {
if (!user.Settings.currency) { if (!user.Settings.settings) {
// Set default currency if needed user.Settings.settings = {};
user.Settings.currency = UserService.DEFAULT_CURRENCY;
} }
} else if (user) { } else if (user) {
// Set default settings if needed // Set default settings if needed
user.Settings = { user.Settings = {
currency: UserService.DEFAULT_CURRENCY, currency: null,
settings: null, settings: {},
updatedAt: new Date(), updatedAt: new Date(),
userId: user?.id, userId: user?.id,
viewMode: ViewMode.DEFAULT viewMode: 'DEFAULT'
}; };
} }
// Set default value for base currency
if (!(user.Settings.settings as UserSettings)?.baseCurrency) {
(user.Settings.settings as UserSettings).baseCurrency =
UserService.DEFAULT_CURRENCY;
}
// Set default value for date range
(user.Settings.settings as UserSettings).dateRange =
(user.Settings.settings as UserSettings).viewMode === 'ZEN'
? 'max'
: (user.Settings.settings as UserSettings)?.dateRange ?? 'max';
// Set default value for view mode
if (!(user.Settings.settings as UserSettings).viewMode) {
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
}
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
user.subscription = user.subscription =
this.subscriptionService.getSubscription(Subscription); this.subscriptionService.getSubscription(Subscription);
@ -327,33 +335,6 @@ export class UserService {
return; return;
} }
public async updateUserSettings({
currency,
userId,
viewMode
}: UserSettingsParams) {
await this.prismaService.settings.upsert({
create: {
currency,
User: {
connect: {
id: userId
}
},
viewMode
},
update: {
currency,
viewMode
},
where: {
userId: userId
}
});
return;
}
private getRandomString(length: number) { private getRandomString(length: number) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const result = []; const result = [];

2
apps/api/src/models/interfaces/rule.interface.ts

@ -1,5 +1,5 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface'; import { UserSettings } from '@ghostfolio/common/interfaces';
import { EvaluationResult } from './evaluation-result.interface'; import { EvaluationResult } from './evaluation-result.interface';

3
apps/api/src/models/interfaces/user-settings.interface.ts

@ -1,3 +0,0 @@
export interface UserSettings {
baseCurrency: string;
}

3
apps/api/src/models/rule.ts

@ -1,8 +1,7 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { groupBy } from '@ghostfolio/common/helper'; import { groupBy } from '@ghostfolio/common/helper';
import { TimelinePosition } from '@ghostfolio/common/interfaces'; import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces';
import { EvaluationResult } from './interfaces/evaluation-result.interface'; import { EvaluationResult } from './interfaces/evaluation-result.interface';
import { RuleInterface } from './interfaces/rule.interface'; import { RuleInterface } from './interfaces/rule.interface';

4
apps/api/src/models/rules/account-cluster-risk/current-investment.ts

@ -1,9 +1,9 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { import {
PortfolioDetails, PortfolioDetails,
PortfolioPosition PortfolioPosition,
UserSettings
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

4
apps/api/src/models/rules/account-cluster-risk/initial-investment.ts

@ -1,9 +1,9 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { import {
PortfolioDetails, PortfolioDetails,
PortfolioPosition PortfolioPosition,
UserSettings
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

3
apps/api/src/models/rules/account-cluster-risk/single-account.ts

@ -1,7 +1,6 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { PortfolioDetails } from '@ghostfolio/common/interfaces'; import { PortfolioDetails, UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

2
apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts

@ -1,7 +1,7 @@
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface'; import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

2
apps/api/src/models/rules/currency-cluster-risk/base-currency-initial-investment.ts

@ -1,7 +1,7 @@
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface'; import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

2
apps/api/src/models/rules/currency-cluster-risk/current-investment.ts

@ -1,7 +1,7 @@
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface'; import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

2
apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts

@ -1,7 +1,7 @@
import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface'; import { CurrentPositions } from '@ghostfolio/api/app/portfolio/interfaces/current-positions.interface';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

2
apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts

@ -1,6 +1,6 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule'; import { Rule } from '../../rule';

23
apps/client/src/app/pages/account/account-page.component.ts

@ -175,29 +175,6 @@ export class AccountPageComponent implements OnDestroy, OnInit {
}); });
} }
public onChangeUserSettings(aKey: string, aValue: string) {
const settings = { ...this.user.settings, [aKey]: aValue };
this.dataService
.putUserSettings({
baseCurrency: settings?.baseCurrency,
viewMode: settings?.viewMode
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.userService.remove();
this.userService
.get()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((user) => {
this.user = user;
this.changeDetectorRef.markForCheck();
});
});
}
public onCheckout() { public onCheckout() {
this.dataService this.dataService
.createCheckoutSession({ couponId: this.couponId, priceId: this.priceId }) .createCheckoutSession({ couponId: this.couponId, priceId: this.priceId })

4
apps/client/src/app/pages/account/account-page.html

@ -99,7 +99,7 @@
name="baseCurrency" name="baseCurrency"
[disabled]="!hasPermissionToUpdateUserSettings" [disabled]="!hasPermissionToUpdateUserSettings"
[value]="user.settings.baseCurrency" [value]="user.settings.baseCurrency"
(selectionChange)="onChangeUserSettings('baseCurrency', $event.value)" (selectionChange)="onChangeUserSetting('baseCurrency', $event.value)"
> >
<mat-option <mat-option
*ngFor="let currency of currencies" *ngFor="let currency of currencies"
@ -166,7 +166,7 @@
name="viewMode" name="viewMode"
[disabled]="!hasPermissionToUpdateViewMode" [disabled]="!hasPermissionToUpdateViewMode"
[value]="user.settings.viewMode" [value]="user.settings.viewMode"
(selectionChange)="onChangeUserSettings('viewMode', $event.value)" (selectionChange)="onChangeUserSetting('viewMode', $event.value)"
> >
<mat-option value="DEFAULT">Default</mat-option> <mat-option value="DEFAULT">Default</mat-option>
<mat-option value="ZEN">Zen</mat-option> <mat-option value="ZEN">Zen</mat-option>

5
apps/client/src/app/services/data.service.ts

@ -12,7 +12,6 @@ import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.in
import { SymbolItem } from '@ghostfolio/api/app/symbol/interfaces/symbol-item.interface'; import { SymbolItem } from '@ghostfolio/api/app/symbol/interfaces/symbol-item.interface';
import { UserItem } from '@ghostfolio/api/app/user/interfaces/user-item.interface'; import { UserItem } from '@ghostfolio/api/app/user/interfaces/user-item.interface';
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto'; import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
import { UpdateUserSettingsDto } from '@ghostfolio/api/app/user/update-user-settings.dto';
import { PropertyDto } from '@ghostfolio/api/services/property/property.dto'; import { PropertyDto } from '@ghostfolio/api/services/property/property.dto';
import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { import {
@ -448,10 +447,6 @@ export class DataService {
return this.http.put<User>(`/api/v1/user/setting`, aData); return this.http.put<User>(`/api/v1/user/setting`, aData);
} }
public putUserSettings(aData: UpdateUserSettingsDto) {
return this.http.put<User>(`/api/v1/user/settings`, aData);
}
public redeemCoupon(couponCode: string) { public redeemCoupon(couponCode: string) {
return this.http.post('/api/v1/subscription/redeem-coupon', { return this.http.post('/api/v1/subscription/redeem-coupon', {
couponCode couponCode

Loading…
Cancel
Save