Browse Source

Feature/clean up user database schema (#1242)

* Clean up user database schema

* Update changelog
pull/1244/head
Thomas Kaul 2 years ago
committed by GitHub
parent
commit
4f8fe83a16
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CHANGELOG.md
  2. 2
      apps/api/src/app/order/order.controller.ts
  3. 8
      apps/api/src/app/portfolio/portfolio.controller.ts
  4. 30
      apps/api/src/app/portfolio/portfolio.service.ts
  5. 3
      apps/api/src/app/user/update-user-setting.dto.ts
  6. 15
      apps/api/src/app/user/user.service.ts
  7. 15
      apps/api/src/services/exchange-rate-data.service.ts
  8. 7
      apps/client/src/app/core/auth.guard.ts
  9. 3
      libs/common/src/lib/interfaces/user-settings.interface.ts
  10. 3
      libs/common/src/lib/interfaces/user-with-settings.ts
  11. 4
      libs/common/src/lib/types/index.ts
  12. 1
      libs/common/src/lib/types/view-mode.type.ts
  13. 3
      prisma/migrations/20220910135140_removed_currency_and_view_mode_from_user/migration.sql
  14. 2
      prisma/schema.prisma

4
CHANGELOG.md

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Changed
- Removed the `currency` and `viewMode` from the `User` database schema
### Fixed ### Fixed
- Allowed the date range change for the demo user - Allowed the date range change for the demo user

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

@ -103,7 +103,7 @@ export class OrderController {
impersonationId, impersonationId,
this.request.user.id this.request.user.id
); );
const userCurrency = this.request.user.Settings.currency; const userCurrency = this.request.user.Settings.settings.baseCurrency;
let activities = await this.orderService.getOrders({ let activities = await this.orderService.getOrders({
filters, filters,

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

@ -40,7 +40,6 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { ViewMode } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { PortfolioPositionDetail } from './interfaces/portfolio-position-detail.interface'; import { PortfolioPositionDetail } from './interfaces/portfolio-position-detail.interface';
@ -196,7 +195,7 @@ export class PortfolioController {
return this.exchangeRateDataService.toCurrency( return this.exchangeRateDataService.toCurrency(
portfolioPosition.quantity * portfolioPosition.marketPrice, portfolioPosition.quantity * portfolioPosition.marketPrice,
portfolioPosition.currency, portfolioPosition.currency,
this.request.user.Settings.currency this.request.user.Settings.settings.baseCurrency
); );
}) })
.reduce((a, b) => a + b, 0); .reduce((a, b) => a + b, 0);
@ -299,7 +298,7 @@ export class PortfolioController {
if ( if (
impersonationId || impersonationId ||
this.request.user.Settings.viewMode === ViewMode.ZEN || this.request.user.Settings.settings.viewMode === 'ZEN' ||
this.userService.isRestrictedView(this.request.user) this.userService.isRestrictedView(this.request.user)
) { ) {
performanceInformation.performance = nullifyValuesInObject( performanceInformation.performance = nullifyValuesInObject(
@ -379,7 +378,8 @@ export class PortfolioController {
return this.exchangeRateDataService.toCurrency( return this.exchangeRateDataService.toCurrency(
portfolioPosition.quantity * portfolioPosition.marketPrice, portfolioPosition.quantity * portfolioPosition.marketPrice,
portfolioPosition.currency, portfolioPosition.currency,
this.request.user?.Settings?.currency ?? this.baseCurrency this.request.user?.Settings?.settings.baseCurrency ??
this.baseCurrency
); );
}) })
.reduce((a, b) => a + b, 0); .reduce((a, b) => a + b, 0);

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

@ -124,7 +124,7 @@ export class PortfolioService {
this.getDetails(aUserId, aUserId, undefined, aFilters) this.getDetails(aUserId, aUserId, undefined, aFilters)
]); ]);
const userCurrency = this.request.user.Settings.currency; const userCurrency = this.request.user.Settings.settings.baseCurrency;
return accounts.map((account) => { return accounts.map((account) => {
let transactionCount = 0; let transactionCount = 0;
@ -199,7 +199,7 @@ export class PortfolioService {
}); });
const portfolioCalculator = new PortfolioCalculator({ const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency, currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
orders: portfolioOrders orders: portfolioOrders
}); });
@ -279,7 +279,7 @@ export class PortfolioService {
}); });
const portfolioCalculator = new PortfolioCalculator({ const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency, currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
orders: portfolioOrders orders: portfolioOrders
}); });
@ -368,7 +368,7 @@ export class PortfolioService {
}); });
const portfolioCalculator = new PortfolioCalculator({ const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency, currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
orders: portfolioOrders orders: portfolioOrders
}); });
@ -441,8 +441,8 @@ export class PortfolioService {
(user.Settings?.settings as UserSettings)?.emergencyFund ?? 0 (user.Settings?.settings as UserSettings)?.emergencyFund ?? 0
); );
const userCurrency = const userCurrency =
user.Settings?.currency ?? user.Settings?.settings.baseCurrency ??
this.request.user?.Settings?.currency ?? this.request.user?.Settings?.settings.baseCurrency ??
this.baseCurrency; this.baseCurrency;
const { orders, portfolioOrders, transactionPoints } = const { orders, portfolioOrders, transactionPoints } =
@ -602,7 +602,7 @@ export class PortfolioService {
aImpersonationId: string, aImpersonationId: string,
aSymbol: string aSymbol: string
): Promise<PortfolioPositionDetail> { ): Promise<PortfolioPositionDetail> {
const userCurrency = this.request.user.Settings.currency; const userCurrency = this.request.user.Settings.settings.baseCurrency;
const userId = await this.getUserId(aImpersonationId, this.request.user.id); const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const orders = ( const orders = (
@ -855,7 +855,7 @@ export class PortfolioService {
}); });
const portfolioCalculator = new PortfolioCalculator({ const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency, currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
orders: portfolioOrders orders: portfolioOrders
}); });
@ -931,7 +931,7 @@ export class PortfolioService {
}); });
const portfolioCalculator = new PortfolioCalculator({ const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.currency, currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
orders: portfolioOrders orders: portfolioOrders
}); });
@ -991,7 +991,7 @@ export class PortfolioService {
} }
public async getReport(impersonationId: string): Promise<PortfolioReport> { public async getReport(impersonationId: string): Promise<PortfolioReport> {
const currency = this.request.user.Settings.currency; const currency = this.request.user.Settings.settings.baseCurrency;
const userId = await this.getUserId(impersonationId, this.request.user.id); const userId = await this.getUserId(impersonationId, this.request.user.id);
const { orders, portfolioOrders, transactionPoints } = const { orders, portfolioOrders, transactionPoints } =
@ -1083,7 +1083,7 @@ export class PortfolioService {
} }
public async getSummary(aImpersonationId: string): Promise<PortfolioSummary> { public async getSummary(aImpersonationId: string): Promise<PortfolioSummary> {
const userCurrency = this.request.user.Settings.currency; const userCurrency = this.request.user.Settings.settings.baseCurrency;
const userId = await this.getUserId(aImpersonationId, this.request.user.id); const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId }); const user = await this.userService.user({ id: userId });
@ -1257,7 +1257,7 @@ export class PortfolioService {
return this.exchangeRateDataService.toCurrency( return this.exchangeRateDataService.toCurrency(
new Big(order.quantity).mul(order.unitPrice).toNumber(), new Big(order.quantity).mul(order.unitPrice).toNumber(),
order.SymbolProfile.currency, order.SymbolProfile.currency,
this.request.user.Settings.currency this.request.user.Settings.settings.baseCurrency
); );
}) })
.reduce( .reduce(
@ -1276,7 +1276,7 @@ export class PortfolioService {
return this.exchangeRateDataService.toCurrency( return this.exchangeRateDataService.toCurrency(
order.fee, order.fee,
order.SymbolProfile.currency, order.SymbolProfile.currency,
this.request.user.Settings.currency this.request.user.Settings.settings.baseCurrency
); );
}) })
.reduce( .reduce(
@ -1298,7 +1298,7 @@ export class PortfolioService {
return this.exchangeRateDataService.toCurrency( return this.exchangeRateDataService.toCurrency(
new Big(order.quantity).mul(order.unitPrice).toNumber(), new Big(order.quantity).mul(order.unitPrice).toNumber(),
order.SymbolProfile.currency, order.SymbolProfile.currency,
this.request.user.Settings.currency this.request.user.Settings.settings.baseCurrency
); );
}) })
.reduce( .reduce(
@ -1339,7 +1339,7 @@ export class PortfolioService {
portfolioOrders: PortfolioOrder[]; portfolioOrders: PortfolioOrder[];
}> { }> {
const userCurrency = const userCurrency =
this.request.user?.Settings?.currency ?? this.baseCurrency; this.request.user?.Settings?.settings.baseCurrency ?? this.baseCurrency;
const orders = await this.orderService.getOrders({ const orders = await this.orderService.getOrders({
filters, filters,

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

@ -1,6 +1,5 @@
import { UniqueAsset } from '@ghostfolio/common/interfaces'; import { UniqueAsset } from '@ghostfolio/common/interfaces';
import type { DateRange } from '@ghostfolio/common/types'; import type { DateRange, ViewMode } from '@ghostfolio/common/types';
import { ViewMode } from '@prisma/client';
import { import {
IsBoolean, IsBoolean,
IsIn, IsIn,

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

@ -69,8 +69,8 @@ export class UserService {
}), }),
accounts: Account, accounts: Account,
settings: { settings: {
...(<UserSettings>(<unknown>Settings.settings)), ...(<UserSettings>Settings.settings),
locale: (<UserSettings>(<unknown>Settings.settings))?.locale ?? aLocale locale: (<UserSettings>Settings.settings)?.locale ?? aLocale
} }
}; };
} }
@ -88,10 +88,7 @@ export class UserService {
} }
public isRestrictedView(aUser: UserWithSettings) { public isRestrictedView(aUser: UserWithSettings) {
return ( return aUser.Settings.settings.isRestrictedView ?? false;
(aUser.Settings.settings as unknown as UserSettings)?.isRestrictedView ??
false
);
} }
public async user( public async user(
@ -134,11 +131,9 @@ export class UserService {
} else if (user) { } else if (user) {
// Set default settings if needed // Set default settings if needed
user.Settings = { user.Settings = {
currency: null,
settings: {}, settings: {},
updatedAt: new Date(), updatedAt: new Date(),
userId: user?.id, userId: user?.id
viewMode: 'DEFAULT'
}; };
} }
@ -239,10 +234,12 @@ export class UserService {
}, },
Settings: { Settings: {
create: { create: {
settings: {
currency: this.baseCurrency currency: this.baseCurrency
} }
} }
} }
}
}); });
if (data.provider === 'ANONYMOUS') { if (data.provider === 'ANONYMOUS') {

15
apps/api/src/services/exchange-rate-data.service.ts

@ -166,21 +166,6 @@ export class ExchangeRateDataService {
currencies.push(account.currency); currencies.push(account.currency);
}); });
(
await this.prismaService.settings.findMany({
distinct: ['currency'],
orderBy: [{ currency: 'asc' }],
select: { currency: true },
where: {
currency: {
not: null
}
}
})
).forEach((userSettings) => {
currencies.push(userSettings.currency);
});
( (
await this.prismaService.symbolProfile.findMany({ await this.prismaService.symbolProfile.findMany({
distinct: ['currency'], distinct: ['currency'],

7
apps/client/src/app/core/auth.guard.ts

@ -7,7 +7,6 @@ import {
} from '@angular/router'; } from '@angular/router';
import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service'; import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { ViewMode } from '@prisma/client';
import { EMPTY } from 'rxjs'; import { EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
@ -80,13 +79,13 @@ export class AuthGuard implements CanActivate {
return; return;
} else if ( } else if (
state.url.startsWith('/home') && state.url.startsWith('/home') &&
user.settings.viewMode === ViewMode.ZEN user.settings.viewMode === 'ZEN'
) { ) {
this.router.navigate(['/zen']); this.router.navigate(['/zen']);
resolve(false); resolve(false);
return; return;
} else if (state.url.startsWith('/start')) { } else if (state.url.startsWith('/start')) {
if (user.settings.viewMode === ViewMode.ZEN) { if (user.settings.viewMode === 'ZEN') {
this.router.navigate(['/zen']); this.router.navigate(['/zen']);
} else { } else {
this.router.navigate(['/home']); this.router.navigate(['/home']);
@ -96,7 +95,7 @@ export class AuthGuard implements CanActivate {
return; return;
} else if ( } else if (
state.url.startsWith('/zen') && state.url.startsWith('/zen') &&
user.settings.viewMode === ViewMode.DEFAULT user.settings.viewMode === 'DEFAULT'
) { ) {
this.router.navigate(['/home']); this.router.navigate(['/home']);
resolve(false); resolve(false);

3
libs/common/src/lib/interfaces/user-settings.interface.ts

@ -1,5 +1,4 @@
import { DateRange } from '@ghostfolio/common/types'; import { DateRange, ViewMode } from '@ghostfolio/common/types';
import { ViewMode } from '@prisma/client';
import { UniqueAsset } from './unique-asset.interface'; import { UniqueAsset } from './unique-asset.interface';

3
libs/common/src/lib/interfaces/user-with-settings.ts

@ -1,10 +1,11 @@
import { SubscriptionType } from '@ghostfolio/common/types/subscription.type'; import { SubscriptionType } from '@ghostfolio/common/types/subscription.type';
import { Account, Settings, User } from '@prisma/client'; import { Account, Settings, User } from '@prisma/client';
import { UserSettings } from './user-settings.interface';
export type UserWithSettings = User & { export type UserWithSettings = User & {
Account: Account[]; Account: Account[];
permissions?: string[]; permissions?: string[];
Settings: Settings; Settings: Settings & { settings: UserSettings };
subscription?: { subscription?: {
expiresAt?: Date; expiresAt?: Date;
type: SubscriptionType; type: SubscriptionType;

4
libs/common/src/lib/types/index.ts

@ -8,6 +8,7 @@ import { Market } from './market.type';
import type { OrderWithAccount } from './order-with-account.type'; import type { OrderWithAccount } from './order-with-account.type';
import type { RequestWithUser } from './request-with-user.type'; import type { RequestWithUser } from './request-with-user.type';
import { ToggleOption } from './toggle-option.type'; import { ToggleOption } from './toggle-option.type';
import type { ViewMode } from './view-mode.type';
export type { export type {
AccessWithGranteeUser, AccessWithGranteeUser,
@ -19,5 +20,6 @@ export type {
MarketState, MarketState,
OrderWithAccount, OrderWithAccount,
RequestWithUser, RequestWithUser,
ToggleOption ToggleOption,
ViewMode
}; };

1
libs/common/src/lib/types/view-mode.type.ts

@ -0,0 +1 @@
export type ViewMode = 'DEFAULT' | 'ZEN';

3
prisma/migrations/20220910135140_removed_currency_and_view_mode_from_user/migration.sql

@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "Settings" DROP COLUMN "currency",
DROP COLUMN "viewMode";

2
prisma/schema.prisma

@ -102,10 +102,8 @@ model Property {
} }
model Settings { model Settings {
currency String? /// @deprecated
settings Json? settings Json?
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
viewMode ViewMode? /// @deprecated
userId String @id userId String @id
User User @relation(fields: [userId], references: [id]) User User @relation(fields: [userId], references: [id])
} }

Loading…
Cancel
Save