From 5391b88c4252dec6cfbd17dcfb77ed07de1f9574 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 14 May 2022 13:53:43 +0200 Subject: [PATCH] Feature/add report data glitch button (#920) * Add report data glitch button * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/user/user.service.ts | 80 +++++++++++++------ .../home-holdings/home-holdings.component.ts | 7 +- .../interfaces/interfaces.ts | 1 + .../position-detail-dialog.component.ts | 2 + .../position-detail-dialog.html | 15 +++- .../allocations/allocations-page.component.ts | 8 +- .../transactions-page.component.ts | 7 +- libs/common/src/lib/permissions.ts | 1 + 9 files changed, 92 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ff7f6342..91bcc8cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Supported enter key press to submit the form of the create or edit transaction dialog +- Added a _Report Data Glitch_ button to the position detail dialog ### Fixed diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 0995ace2f..3fd6f8e1d 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -102,19 +102,69 @@ export class UserService { public async user( userWhereUniqueInput: Prisma.UserWhereUniqueInput ): Promise { - const userFromDatabase = await this.prismaService.user.findUnique({ + const { + accessToken, + Account, + alias, + authChallenge, + createdAt, + id, + provider, + role, + Settings, + Subscription, + thirdPartyId, + updatedAt + } = await this.prismaService.user.findUnique({ include: { Account: true, Settings: true, Subscription: true }, where: userWhereUniqueInput }); - const user: UserWithSettings = userFromDatabase; + const user: UserWithSettings = { + accessToken, + Account, + alias, + authChallenge, + createdAt, + id, + provider, + role, + Settings, + thirdPartyId, + updatedAt + }; + + if (user?.Settings) { + if (!user.Settings.currency) { + // Set default currency if needed + user.Settings.currency = UserService.DEFAULT_CURRENCY; + } + } else if (user) { + // Set default settings if needed + user.Settings = { + currency: UserService.DEFAULT_CURRENCY, + settings: null, + updatedAt: new Date(), + userId: user?.id, + viewMode: ViewMode.DEFAULT + }; + } + + if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { + user.subscription = + this.subscriptionService.getSubscription(Subscription); + } - let currentPermissions = getPermissions(userFromDatabase.role); + let currentPermissions = getPermissions(user.role); if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) { currentPermissions.push(permissions.accessFearAndGreedIndex); } + if (user.subscription?.type === 'Premium') { + currentPermissions.push(permissions.reportDataGlitch); + } + if (this.configurationService.get('ENABLE_FEATURE_READ_ONLY_MODE')) { if (hasRole(user, Role.ADMIN)) { currentPermissions.push(permissions.toggleReadOnlyMode); @@ -135,29 +185,7 @@ export class UserService { } } - user.permissions = currentPermissions; - - if (userFromDatabase?.Settings) { - if (!userFromDatabase.Settings.currency) { - // Set default currency if needed - userFromDatabase.Settings.currency = UserService.DEFAULT_CURRENCY; - } - } else if (userFromDatabase) { - // Set default settings if needed - userFromDatabase.Settings = { - currency: UserService.DEFAULT_CURRENCY, - settings: null, - updatedAt: new Date(), - userId: userFromDatabase?.id, - viewMode: ViewMode.DEFAULT - }; - } - - if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { - user.subscription = this.subscriptionService.getSubscription( - userFromDatabase?.Subscription - ); - } + user.permissions = currentPermissions.sort(); return user; } diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index 7d40a27ef..a1eafcd76 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -17,6 +17,7 @@ import { DataSource } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { PositionDetailDialogParams } from '../position/position-detail-dialog/interfaces/interfaces'; @Component({ selector: 'gf-home-holdings', @@ -126,12 +127,16 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit { const dialogRef = this.dialog.open(PositionDetailDialog, { autoFocus: false, - data: { + data: { dataSource, symbol, baseCurrency: this.user?.settings?.baseCurrency, deviceType: this.deviceType, hasImpersonationId: this.hasImpersonationId, + hasPermissionToReportDataGlitch: hasPermission( + this.user?.permissions, + permissions.reportDataGlitch + ), locale: this.user?.settings?.locale }, height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', diff --git a/apps/client/src/app/components/position/position-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/position/position-detail-dialog/interfaces/interfaces.ts index 791c2b46a..36b4ae45f 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/position/position-detail-dialog/interfaces/interfaces.ts @@ -5,6 +5,7 @@ export interface PositionDetailDialogParams { dataSource: DataSource; deviceType: string; hasImpersonationId: boolean; + hasPermissionToReportDataGlitch: boolean; locale: string; symbol: string; } diff --git a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts index 3baa8c0e5..341b4abc0 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts +++ b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts @@ -44,6 +44,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit { public orders: OrderWithAccount[]; public quantity: number; public quantityPrecision = 2; + public reportDataGlitchMail: string; public sectors: { [name: string]: { name: string; value: number }; }; @@ -91,6 +92,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit { this.averagePrice = averagePrice; this.benchmarkDataItems = []; this.countries = {}; + this.reportDataGlitchMail = `mailto:hi@ghostfol.io?Subject=Ghostfolio Data Glitch Report&body=Hello%0D%0DI would like to report a data glitch for%0D%0DSymbol: ${SymbolProfile?.symbol}%0DData Source: ${SymbolProfile?.dataSource}%0D%0DAdditional notes:%0D%0DCan you please take a look?%0D%0DKind regards`; this.firstBuyDate = firstBuyDate; this.grossPerformance = grossPerformance; this.grossPerformancePercent = grossPerformancePercent; diff --git a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html index 169e47390..64bb56f3f 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html +++ b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -214,13 +214,26 @@
-
+
Tags
{{ tag.name }}
+ +
+ +
diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index b2c63664f..7b4f04e0a 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -1,6 +1,7 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router } from '@angular/router'; +import { PositionDetailDialogParams } from '@ghostfolio/client/components/position/position-detail-dialog/interfaces/interfaces'; import { PositionDetailDialog } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.component'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; @@ -14,6 +15,7 @@ import { UniqueAsset, User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { Market, ToggleOption } from '@ghostfolio/common/types'; import { Account, AssetClass, DataSource } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; @@ -404,12 +406,16 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { const dialogRef = this.dialog.open(PositionDetailDialog, { autoFocus: false, - data: { + data: { dataSource, symbol, baseCurrency: this.user?.settings?.baseCurrency, deviceType: this.deviceType, hasImpersonationId: this.hasImpersonationId, + hasPermissionToReportDataGlitch: hasPermission( + this.user?.permissions, + permissions.reportDataGlitch + ), locale: this.user?.settings?.locale }, height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', diff --git a/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts b/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts index 1717dbbda..65f5da641 100644 --- a/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts +++ b/apps/client/src/app/pages/portfolio/transactions/transactions-page.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { UpdateOrderDto } from '@ghostfolio/api/app/order/update-order.dto'; +import { PositionDetailDialogParams } from '@ghostfolio/client/components/position/position-detail-dialog/interfaces/interfaces'; import { PositionDetailDialog } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.component'; import { DataService } from '@ghostfolio/client/services/data.service'; import { IcsService } from '@ghostfolio/client/services/ics/ics.service'; @@ -406,12 +407,16 @@ export class TransactionsPageComponent implements OnDestroy, OnInit { const dialogRef = this.dialog.open(PositionDetailDialog, { autoFocus: false, - data: { + data: { dataSource, symbol, baseCurrency: this.user?.settings?.baseCurrency, deviceType: this.deviceType, hasImpersonationId: this.hasImpersonationId, + hasPermissionToReportDataGlitch: hasPermission( + this.user?.permissions, + permissions.reportDataGlitch + ), locale: this.user?.settings?.locale }, height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index dc574f7ef..5023369f7 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -20,6 +20,7 @@ export const permissions = { enableStatistics: 'enableStatistics', enableSubscription: 'enableSubscription', enableSystemMessage: 'enableSystemMessage', + reportDataGlitch: 'reportDataGlitch', toggleReadOnlyMode: 'toggleReadOnlyMode', updateAccount: 'updateAccount', updateAuthDevice: 'updateAuthDevice',