From 6e87f34c6fd2f22e14bd760807af1c4fe1bcb302 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 10 Aug 2023 20:49:06 +0200
Subject: [PATCH 01/23] Feature/add more durations in coupon system (#2228)
* Add 90 and 180 days
* Update changelog
---
CHANGELOG.md | 6 ++++++
.../src/app/components/admin-overview/admin-overview.html | 2 ++
2 files changed, 8 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3bf25b404..671f7a85f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Added
+
+- Added more durations in the coupon system
+
## 1.299.1 - 2023-08-10
### Changed
diff --git a/apps/client/src/app/components/admin-overview/admin-overview.html b/apps/client/src/app/components/admin-overview/admin-overview.html
index 0f4127e51..f72c88050 100644
--- a/apps/client/src/app/components/admin-overview/admin-overview.html
+++ b/apps/client/src/app/components/admin-overview/admin-overview.html
@@ -169,6 +169,8 @@
7 Days
14 Days
30 Days
+ 90 Days
+ 180 Days
1 Year
From 5a23cd34ad1d35c29db9f4220acc333008e8ec8b Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Aug 2023 18:29:39 +0200
Subject: [PATCH 02/23] Replace variables (#2229)
---
apps/client/src/index.html | 32 ++++++++++-----
apps/client/src/index.template.html | 63 +++++++++++++++++++++++++++++
2 files changed, 85 insertions(+), 10 deletions(-)
create mode 100644 apps/client/src/index.template.html
diff --git a/apps/client/src/index.html b/apps/client/src/index.html
index 55120ec08..a7d01e481 100644
--- a/apps/client/src/index.html
+++ b/apps/client/src/index.html
@@ -1,11 +1,14 @@
-
+
- ${title}
+ Ghostfolio – Open Source Wealth Management Software
-
+
-
-
+
+
-
+
-
-
-
-
+
+
+
+
+
+
+ ${title}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From b5f01c0d151cd96da47c1cdef4a679c6b748dbb0 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Aug 2023 20:20:35 +0200
Subject: [PATCH 03/23] Feature/migrate requests from bent to got (#2231)
* Migrate requests from bent to got
* Update changelog
---
CHANGELOG.md | 4 ++
apps/api/src/app/info/info.service.ts | 50 +++++++------------
apps/api/src/app/logo/logo.service.ts | 12 ++---
.../coingecko/coingecko.service.ts | 30 ++++-------
.../trackinsight/trackinsight.service.ts | 32 ++++++------
.../financial-modeling-prep.service.ts | 32 ++++--------
.../data-provider/manual/manual.service.ts | 7 ++-
.../rapid-api/rapid-api.service.ts | 18 +++----
package.json | 1 -
yarn.lock | 14 ------
10 files changed, 74 insertions(+), 126 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 671f7a85f..5aae4e412 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added more durations in the coupon system
+### Changed
+
+- Migrated the remaining requests from `bent` to `got`
+
## 1.299.1 - 2023-08-10
### Changed
diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts
index 187135a35..7eba432f5 100644
--- a/apps/api/src/app/info/info.service.ts
+++ b/apps/api/src/app/info/info.service.ts
@@ -30,9 +30,9 @@ import { permissions } from '@ghostfolio/common/permissions';
import { SubscriptionOffer } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
-import * as bent from 'bent';
import * as cheerio from 'cheerio';
import { format, subDays } from 'date-fns';
+import got from 'got';
@Injectable()
export class InfoService {
@@ -172,17 +172,13 @@ export class InfoService {
private async countDockerHubPulls(): Promise {
try {
- const get = bent(
+ const { pull_count } = await got(
`https://hub.docker.com/v2/repositories/ghostfolio/ghostfolio`,
- 'GET',
- 'json',
- 200,
{
- 'User-Agent': 'request'
+ headers: { 'User-Agent': 'request' }
}
- );
+ ).json();
- const { pull_count } = await get();
return pull_count;
} catch (error) {
Logger.error(error, 'InfoService');
@@ -193,16 +189,9 @@ export class InfoService {
private async countGitHubContributors(): Promise {
try {
- const get = bent(
- 'https://github.com/ghostfolio/ghostfolio',
- 'GET',
- 'string',
- 200,
- {}
- );
+ const { body } = await got('https://github.com/ghostfolio/ghostfolio');
- const html = await get();
- const $ = cheerio.load(html);
+ const $ = cheerio.load(body);
return extractNumberFromString(
$(
@@ -218,17 +207,13 @@ export class InfoService {
private async countGitHubStargazers(): Promise {
try {
- const get = bent(
+ const { stargazers_count } = await got(
`https://api.github.com/repos/ghostfolio/ghostfolio`,
- 'GET',
- 'json',
- 200,
{
- 'User-Agent': 'request'
+ headers: { 'User-Agent': 'request' }
}
- );
+ ).json();
- const { stargazers_count } = await get();
return stargazers_count;
} catch (error) {
Logger.error(error, 'InfoService');
@@ -346,22 +331,21 @@ export class InfoService {
PROPERTY_BETTER_UPTIME_MONITOR_ID
)) as string;
- const get = bent(
+ const { data } = await got(
`https://betteruptime.com/api/v2/monitors/${monitorId}/sla?from=${format(
subDays(new Date(), 90),
DATE_FORMAT
)}&to${format(new Date(), DATE_FORMAT)}`,
- 'GET',
- 'json',
- 200,
+
{
- Authorization: `Bearer ${this.configurationService.get(
- 'BETTER_UPTIME_API_KEY'
- )}`
+ headers: {
+ Authorization: `Bearer ${this.configurationService.get(
+ 'BETTER_UPTIME_API_KEY'
+ )}`
+ }
}
- );
+ ).json();
- const { data } = await get();
return data.attributes.availability / 100;
} catch (error) {
Logger.error(error, 'InfoService');
diff --git a/apps/api/src/app/logo/logo.service.ts b/apps/api/src/app/logo/logo.service.ts
index d2e377fc0..166143a75 100644
--- a/apps/api/src/app/logo/logo.service.ts
+++ b/apps/api/src/app/logo/logo.service.ts
@@ -2,7 +2,7 @@ import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/sy
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { HttpException, Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client';
-import * as bent from 'bent';
+import got from 'got';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@Injectable()
@@ -41,15 +41,11 @@ export class LogoService {
}
private getBuffer(aUrl: string) {
- const get = bent(
+ return got(
`https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${aUrl}&size=64`,
- 'GET',
- 'buffer',
- 200,
{
- 'User-Agent': 'request'
+ headers: { 'User-Agent': 'request' }
}
- );
- return get();
+ ).buffer();
}
}
diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts
index 35083e810..492664393 100644
--- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts
+++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts
@@ -15,8 +15,8 @@ import {
DataSource,
SymbolProfile
} from '@prisma/client';
-import bent from 'bent';
import { format, fromUnixTime, getUnixTime } from 'date-fns';
+import got from 'got';
@Injectable()
export class CoinGeckoService implements DataProviderInterface {
@@ -45,8 +45,7 @@ export class CoinGeckoService implements DataProviderInterface {
};
try {
- const get = bent(`${this.URL}/coins/${aSymbol}`, 'GET', 'json', 200);
- const { name } = await get();
+ const { name } = await got(`${this.URL}/coins/${aSymbol}`).json();
response.name = name;
} catch (error) {
@@ -79,17 +78,13 @@ export class CoinGeckoService implements DataProviderInterface {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> {
try {
- const get = bent(
+ const { prices } = await got(
`${
this.URL
}/coins/${aSymbol}/market_chart/range?vs_currency=${this.baseCurrency.toLowerCase()}&from=${getUnixTime(
from
- )}&to=${getUnixTime(to)}`,
- 'GET',
- 'json',
- 200
- );
- const { prices } = await get();
+ )}&to=${getUnixTime(to)}`
+ ).json();
const result: {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
@@ -132,15 +127,11 @@ export class CoinGeckoService implements DataProviderInterface {
}
try {
- const get = bent(
+ const response = await got(
`${this.URL}/simple/price?ids=${aSymbols.join(
','
- )}&vs_currencies=${this.baseCurrency.toLowerCase()}`,
- 'GET',
- 'json',
- 200
- );
- const response = await get();
+ )}&vs_currencies=${this.baseCurrency.toLowerCase()}`
+ ).json();
for (const symbol in response) {
if (Object.prototype.hasOwnProperty.call(response, symbol)) {
@@ -174,8 +165,9 @@ export class CoinGeckoService implements DataProviderInterface {
let items: LookupItem[] = [];
try {
- const get = bent(`${this.URL}/search?query=${query}`, 'GET', 'json', 200);
- const { coins } = await get();
+ const { coins } = await got(
+ `${this.URL}/search?query=${query}`
+ ).json();
items = coins.map(({ id: symbol, name }) => {
return {
diff --git a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts
index ec68dd2eb..a18d82449 100644
--- a/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts
+++ b/apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts
@@ -3,9 +3,7 @@ import { Country } from '@ghostfolio/common/interfaces/country.interface';
import { Sector } from '@ghostfolio/common/interfaces/sector.interface';
import { Injectable } from '@nestjs/common';
import { SymbolProfile } from '@prisma/client';
-import bent from 'bent';
-
-const getJSON = bent('json');
+import got from 'got';
@Injectable()
export class TrackinsightDataEnhancerService implements DataEnhancerInterface {
@@ -34,11 +32,13 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface {
return response;
}
- const profile = await getJSON(
+ const profile = await got(
`${TrackinsightDataEnhancerService.baseUrl}/data-api/funds/${symbol}.json`
- ).catch(() => {
- return {};
- });
+ )
+ .json()
+ .catch(() => {
+ return {};
+ });
const isin = profile.isin?.split(';')?.[0];
@@ -46,15 +46,17 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface {
response.isin = isin;
}
- const holdings = await getJSON(
+ const holdings = await got(
`${TrackinsightDataEnhancerService.baseUrl}/holdings/${symbol}.json`
- ).catch(() => {
- return getJSON(
- `${TrackinsightDataEnhancerService.baseUrl}/holdings/${
- symbol.split('.')?.[0]
- }.json`
- );
- });
+ )
+ .json()
+ .catch(() => {
+ return got(
+ `${TrackinsightDataEnhancerService.baseUrl}/holdings/${
+ symbol.split('.')?.[0]
+ }.json`
+ );
+ });
if (holdings?.weight < 0.95) {
// Skip if data is inaccurate
diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
index ed65c3f65..3d7ba65f4 100644
--- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
+++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
@@ -10,8 +10,8 @@ import { DataProviderInfo } from '@ghostfolio/common/interfaces';
import { Granularity } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client';
-import bent from 'bent';
import { format, isAfter, isBefore, isSameDay } from 'date-fns';
+import got from 'got';
@Injectable()
export class FinancialModelingPrepService implements DataProviderInterface {
@@ -64,13 +64,9 @@ export class FinancialModelingPrepService implements DataProviderInterface {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> {
try {
- const get = bent(
- `${this.URL}/historical-price-full/${aSymbol}?apikey=${this.apiKey}`,
- 'GET',
- 'json',
- 200
- );
- const { historical } = await get();
+ const { historical } = await got(
+ `${this.URL}/historical-price-full/${aSymbol}?apikey=${this.apiKey}`
+ ).json();
const result: {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
@@ -115,13 +111,9 @@ export class FinancialModelingPrepService implements DataProviderInterface {
}
try {
- const get = bent(
- `${this.URL}/quote/${aSymbols.join(',')}?apikey=${this.apiKey}`,
- 'GET',
- 'json',
- 200
- );
- const response = await get();
+ const response = await got(
+ `${this.URL}/quote/${aSymbols.join(',')}?apikey=${this.apiKey}`
+ ).json();
for (const { price, symbol } of response) {
results[symbol] = {
@@ -153,13 +145,9 @@ export class FinancialModelingPrepService implements DataProviderInterface {
let items: LookupItem[] = [];
try {
- const get = bent(
- `${this.URL}/search?query=${query}&apikey=${this.apiKey}`,
- 'GET',
- 'json',
- 200
- );
- const result = await get();
+ const result = await got(
+ `${this.URL}/search?query=${query}&apikey=${this.apiKey}`
+ ).json();
items = result.map(({ currency, name, symbol }) => {
return {
diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts
index 7b3933532..adf14e43f 100644
--- a/apps/api/src/services/data-provider/manual/manual.service.ts
+++ b/apps/api/src/services/data-provider/manual/manual.service.ts
@@ -14,10 +14,10 @@ import {
import { Granularity } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client';
-import bent from 'bent';
import * as cheerio from 'cheerio';
import { isUUID } from 'class-validator';
import { addDays, format, isBefore } from 'date-fns';
+import got from 'got';
@Injectable()
export class ManualService implements DataProviderInterface {
@@ -95,10 +95,9 @@ export class ManualService implements DataProviderInterface {
return {};
}
- const get = bent(url, 'GET', 'string', 200, headers);
+ const { body } = await got(url, { headers });
- const html = await get();
- const $ = cheerio.load(html);
+ const $ = cheerio.load(body);
const value = extractNumberFromString($(selector).text());
diff --git a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts
index 053391a8a..307855aaf 100644
--- a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts
+++ b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts
@@ -10,8 +10,8 @@ import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper';
import { Granularity } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client';
-import bent from 'bent';
import { format } from 'date-fns';
+import got from 'got';
@Injectable()
export class RapidApiService implements DataProviderInterface {
@@ -135,19 +135,17 @@ export class RapidApiService implements DataProviderInterface {
oneYearAgo: { value: number; valueText: string };
}> {
try {
- const get = bent(
+ const { fgi } = await got(
`https://fear-and-greed-index.p.rapidapi.com/v1/fgi`,
- 'GET',
- 'json',
- 200,
{
- useQueryString: true,
- 'x-rapidapi-host': 'fear-and-greed-index.p.rapidapi.com',
- 'x-rapidapi-key': this.configurationService.get('RAPID_API_API_KEY')
+ headers: {
+ useQueryString: 'true',
+ 'x-rapidapi-host': 'fear-and-greed-index.p.rapidapi.com',
+ 'x-rapidapi-key': this.configurationService.get('RAPID_API_API_KEY')
+ }
}
- );
+ ).json();
- const { fgi } = await get();
return fgi;
} catch (error) {
Logger.error(error, 'RapidApiService');
diff --git a/package.json b/package.json
index 20f28fa44..9057f4328 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,6 @@
"@simplewebauthn/server": "5.2.1",
"@stripe/stripe-js": "1.47.0",
"alphavantage": "2.2.0",
- "bent": "7.3.12",
"big.js": "6.2.1",
"body-parser": "1.20.1",
"bootstrap": "4.6.0",
diff --git a/yarn.lock b/yarn.lock
index 44a88e311..fddf81de8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7339,15 +7339,6 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
-bent@7.3.12:
- version "7.3.12"
- resolved "https://registry.yarnpkg.com/bent/-/bent-7.3.12.tgz#e0a2775d4425e7674c64b78b242af4f49da6b035"
- integrity sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==
- dependencies:
- bytesish "^0.4.1"
- caseless "~0.12.0"
- is-stream "^2.0.0"
-
better-opn@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/better-opn/-/better-opn-2.1.1.tgz#94a55b4695dc79288f31d7d0e5f658320759f7c6"
@@ -7646,11 +7637,6 @@ bytes@3.1.2:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
-bytesish@^0.4.1:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/bytesish/-/bytesish-0.4.4.tgz#f3b535a0f1153747427aee27256748cff92347e6"
- integrity sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==
-
cacache@17.1.3, cacache@^17.0.0:
version "17.1.3"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-17.1.3.tgz#c6ac23bec56516a7c0c52020fd48b4909d7c7044"
From f7c04e469a039852884a78a143991ce45871c24e Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Aug 2023 20:24:23 +0200
Subject: [PATCH 04/23] Release 1.300.0 (#2232)
---
CHANGELOG.md | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5aae4e412..0db0895aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## Unreleased
+## 1.300.0 - 2023-08-11
### Added
diff --git a/package.json b/package.json
index 9057f4328..77dcdb269 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ghostfolio",
- "version": "1.299.1",
+ "version": "1.300.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {
From 9036f53e7d351a687a6cc5b9ba3a0456e528ac28 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 12 Aug 2023 21:50:01 +0200
Subject: [PATCH 05/23] Reset benchmark in user settings (#2233)
---
apps/api/src/app/user/user.service.ts | 14 +++++++++-----
.../configuration/configuration.service.ts | 3 ++-
libs/common/src/lib/config.ts | 1 +
3 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts
index 3c1e42abf..bbb17b69c 100644
--- a/apps/api/src/app/user/user.service.ts
+++ b/apps/api/src/app/user/user.service.ts
@@ -4,7 +4,11 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { TagService } from '@ghostfolio/api/services/tag/tag.service';
-import { PROPERTY_IS_READ_ONLY_MODE, locale } from '@ghostfolio/common/config';
+import {
+ DEFAULT_CURRENCY,
+ PROPERTY_IS_READ_ONLY_MODE,
+ locale
+} from '@ghostfolio/common/config';
import { User as IUser, UserSettings } from '@ghostfolio/common/interfaces';
import {
getPermissions,
@@ -21,8 +25,6 @@ const crypto = require('crypto');
@Injectable()
export class UserService {
- public static DEFAULT_CURRENCY = 'USD';
-
private baseCurrency: string;
public constructor(
@@ -145,8 +147,7 @@ export class UserService {
// Set default value for base currency
if (!(user.Settings.settings as UserSettings)?.baseCurrency) {
- (user.Settings.settings as UserSettings).baseCurrency =
- UserService.DEFAULT_CURRENCY;
+ (user.Settings.settings as UserSettings).baseCurrency = DEFAULT_CURRENCY;
}
// Set default value for date range
@@ -186,6 +187,9 @@ export class UserService {
if (Analytics?.activityCount % frequency === 1) {
currentPermissions.push(permissions.enableSubscriptionInterstitial);
}
+
+ // Reset benchmark
+ user.Settings.settings.benchmark = undefined;
}
if (user.subscription?.type === 'Premium') {
diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts
index e522aeccd..fa9ada3d7 100644
--- a/apps/api/src/services/configuration/configuration.service.ts
+++ b/apps/api/src/services/configuration/configuration.service.ts
@@ -1,4 +1,5 @@
import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface';
+import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
import { Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client';
import { bool, cleanEnv, host, json, num, port, str } from 'envalid';
@@ -13,7 +14,7 @@ export class ConfigurationService {
ALPHA_VANTAGE_API_KEY: str({ default: '' }),
BASE_CURRENCY: str({
choices: ['AUD', 'CAD', 'CNY', 'EUR', 'GBP', 'JPY', 'RUB', 'USD'],
- default: 'USD'
+ default: DEFAULT_CURRENCY
}),
BETTER_UPTIME_API_KEY: str({ default: '' }),
CACHE_QUOTES_TTL: num({ default: 1 }),
diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts
index 7977a2628..c5c627de8 100644
--- a/libs/common/src/lib/config.ts
+++ b/libs/common/src/lib/config.ts
@@ -35,6 +35,7 @@ export const DATA_GATHERING_QUEUE = 'DATA_GATHERING_QUEUE';
export const DATA_GATHERING_QUEUE_PRIORITY_LOW = Number.MAX_SAFE_INTEGER;
export const DATA_GATHERING_QUEUE_PRIORITY_HIGH = 1;
+export const DEFAULT_CURRENCY = 'USD';
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
export const DEFAULT_LANGUAGE_CODE = 'en';
export const DEFAULT_PAGE_SIZE = 50;
From 183ac8fa2b976992eb25ec2bbf646f5c1175a4c8 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 12 Aug 2023 21:51:35 +0200
Subject: [PATCH 06/23] Feature/add data export to user account page (#2234)
* Add data export
* Update changelog
---
CHANGELOG.md | 20 ++++++++-----
.../pages/account/account-page.component.ts | 23 ++++++++++++++-
.../src/app/pages/account/account-page.html | 8 ++++++
apps/client/src/locales/messages.de.xlf | 28 ++++++++++++-------
apps/client/src/locales/messages.es.xlf | 28 ++++++++++++-------
apps/client/src/locales/messages.fr.xlf | 28 ++++++++++++-------
apps/client/src/locales/messages.it.xlf | 28 ++++++++++++-------
apps/client/src/locales/messages.nl.xlf | 28 ++++++++++++-------
apps/client/src/locales/messages.pt.xlf | 28 ++++++++++++-------
apps/client/src/locales/messages.xlf | 27 +++++++++++-------
10 files changed, 168 insertions(+), 78 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0db0895aa..9cd9ed8c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Added
+
+- Added the data export feature to the user account page
+
## 1.300.0 - 2023-08-11
### Added
@@ -611,7 +617,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- Changed the slide toggles to checkboxes on the account page
+- Changed the slide toggles to checkboxes on the user account page
- Changed the slide toggles to checkboxes in the admin control panel
- Increased the density of the theme
- Migrated the style of various components to `@angular/material` `15` (mdc)
@@ -1173,7 +1179,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- Improved the language selector on the account page
+- Improved the language selector on the user account page
- Improved the wording in the _X-ray_ section (net worth instead of investment)
- Extended the asset profile details dialog in the admin control panel
- Updated the browserslist database
@@ -1591,7 +1597,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Added a language selector to the account page
+- Added a language selector to the user account page
- Added support for translated labels in the value component
### Changed
@@ -1920,7 +1926,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Added the user id to the account page
+- Added the user id to the user account page
- Added a new view with jobs of the queue to the admin control panel
### Changed
@@ -3575,7 +3581,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Respected the cash balance on the analysis page
-- Improved the settings selectors on the account page
+- Improved the settings selectors on the user account page
- Harmonized the slogan to "Open Source Wealth Management Software"
### Fixed
@@ -4041,7 +4047,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added a gradient to the line charts
-- Added a selector to set the base currency on the account page
+- Added a selector to set the base currency on the user account page
## 0.81.0 - 06.04.2021
@@ -4355,7 +4361,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- Added the membership status to the account page
+- Added the membership status to the user account page
### Fixed
diff --git a/apps/client/src/app/pages/account/account-page.component.ts b/apps/client/src/app/pages/account/account-page.component.ts
index 5ab140265..0e4527eeb 100644
--- a/apps/client/src/app/pages/account/account-page.component.ts
+++ b/apps/client/src/app/pages/account/account-page.component.ts
@@ -21,7 +21,7 @@ import {
} from '@ghostfolio/client/services/settings-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service';
-import { getDateFormatString } from '@ghostfolio/common/helper';
+import { downloadAsFile, getDateFormatString } from '@ghostfolio/common/helper';
import { Access, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { uniq } from 'lodash';
@@ -31,6 +31,7 @@ import { EMPTY, Subject } from 'rxjs';
import { catchError, switchMap, takeUntil } from 'rxjs/operators';
import { CreateOrUpdateAccessDialog } from './create-or-update-access-dialog/create-or-update-access-dialog.component';
+import { format, parseISO } from 'date-fns';
@Component({
host: { class: 'page' },
@@ -237,6 +238,26 @@ export class AccountPageComponent implements OnDestroy, OnInit {
});
}
+ public onExport() {
+ this.dataService
+ .fetchExport()
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe((data) => {
+ for (const activity of data.activities) {
+ delete activity.id;
+ }
+
+ downloadAsFile({
+ content: data,
+ fileName: `ghostfolio-export-${format(
+ parseISO(data.meta.date),
+ 'yyyyMMddHHmm'
+ )}.json`,
+ format: 'json'
+ });
+ });
+ }
+
public onRedeemCoupon() {
let couponCode = prompt($localize`Please enter your coupon code:`);
couponCode = couponCode?.trim();
diff --git a/apps/client/src/app/pages/account/account-page.html b/apps/client/src/app/pages/account/account-page.html
index fbf14544a..aeba71320 100644
--- a/apps/client/src/app/pages/account/account-page.html
+++ b/apps/client/src/app/pages/account/account-page.html
@@ -273,6 +273,14 @@
User ID
{{ user?.id }}
+
+
+
+
+
+
diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf
index 683bc61b8..c5eb2bdd8 100644
--- a/apps/client/src/locales/messages.de.xlf
+++ b/apps/client/src/locales/messages.de.xlf
@@ -622,7 +622,7 @@
Hinzufügen
apps/client/src/app/components/admin-overview/admin-overview.html
- 181
+ 183
@@ -630,7 +630,7 @@
Verwaltung
apps/client/src/app/components/admin-overview/admin-overview.html
- 188
+ 190
@@ -638,7 +638,7 @@
Cache leeren
apps/client/src/app/components/admin-overview/admin-overview.html
- 192
+ 194
@@ -1570,7 +1570,7 @@
Bitte gebe deinen Gutscheincode ein:
apps/client/src/app/pages/account/account-page.component.ts
- 241
+ 262
@@ -1578,7 +1578,7 @@
Gutscheincode konnte nicht eingelöst werden
apps/client/src/app/pages/account/account-page.component.ts
- 251
+ 272
@@ -1586,7 +1586,7 @@
Gutscheincode wurde eingelöst
apps/client/src/app/pages/account/account-page.component.ts
- 263
+ 284
@@ -1594,7 +1594,7 @@
Neu laden
apps/client/src/app/pages/account/account-page.component.ts
- 264
+ 285
@@ -1602,7 +1602,7 @@
Möchtest du diese Anmeldemethode wirklich löschen?
apps/client/src/app/pages/account/account-page.component.ts
- 310
+ 331
@@ -1726,7 +1726,7 @@
Zugangsberechtigung
apps/client/src/app/pages/account/account-page.html
- 282
+ 290
@@ -2878,7 +2878,7 @@
Automatisch
apps/client/src/app/pages/account/account-page.component.ts
- 46
+ 47
@@ -7249,6 +7249,14 @@
128
+
+ Export Data
+ Daten exportieren
+
+ apps/client/src/app/pages/account/account-page.html
+ 280
+
+
diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf
index 2bdc4bc6d..532ad66a2 100644
--- a/apps/client/src/locales/messages.es.xlf
+++ b/apps/client/src/locales/messages.es.xlf
@@ -623,7 +623,7 @@
Añadir
apps/client/src/app/components/admin-overview/admin-overview.html
- 181
+ 183
@@ -631,7 +631,7 @@
Tareas domésticas
apps/client/src/app/components/admin-overview/admin-overview.html
- 188
+ 190
@@ -639,7 +639,7 @@
Limpiar caché
apps/client/src/app/components/admin-overview/admin-overview.html
- 192
+ 194
@@ -1571,7 +1571,7 @@
Por favor, ingresa tu código de cupón:
apps/client/src/app/pages/account/account-page.component.ts
- 241
+ 262
@@ -1579,7 +1579,7 @@
No se puede canjear este código de cupón
apps/client/src/app/pages/account/account-page.component.ts
- 251
+ 272
@@ -1587,7 +1587,7 @@
El codigo de cupón ha sido canjeado
apps/client/src/app/pages/account/account-page.component.ts
- 263
+ 284
@@ -1595,7 +1595,7 @@
Refrescar
apps/client/src/app/pages/account/account-page.component.ts
- 264
+ 285
@@ -1603,7 +1603,7 @@
¿Estás seguro de eliminar este método de acceso?
apps/client/src/app/pages/account/account-page.component.ts
- 310
+ 331
@@ -1727,7 +1727,7 @@
Acceso concedido
apps/client/src/app/pages/account/account-page.html
- 282
+ 290
@@ -2879,7 +2879,7 @@
Automático
apps/client/src/app/pages/account/account-page.component.ts
- 46
+ 47
@@ -7250,6 +7250,14 @@
128
+
+ Export Data
+ Export Data
+
+ apps/client/src/app/pages/account/account-page.html
+ 280
+
+
diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf
index 5af9678fc..1a3c726c0 100644
--- a/apps/client/src/locales/messages.fr.xlf
+++ b/apps/client/src/locales/messages.fr.xlf
@@ -870,7 +870,7 @@
Ajouter
apps/client/src/app/components/admin-overview/admin-overview.html
- 181
+ 183
@@ -878,7 +878,7 @@
Maintenance
apps/client/src/app/components/admin-overview/admin-overview.html
- 188
+ 190
@@ -886,7 +886,7 @@
Vider le Cache
apps/client/src/app/components/admin-overview/admin-overview.html
- 192
+ 194
@@ -1854,7 +1854,7 @@
Auto
apps/client/src/app/pages/account/account-page.component.ts
- 46
+ 47
@@ -1862,7 +1862,7 @@
Veuillez entrer votre code promotionnel :
apps/client/src/app/pages/account/account-page.component.ts
- 241
+ 262
@@ -1870,7 +1870,7 @@
Le code promotionnel n'a pas pu être appliqué
apps/client/src/app/pages/account/account-page.component.ts
- 251
+ 272
@@ -1878,7 +1878,7 @@
Le code promotionnel a été appliqué
apps/client/src/app/pages/account/account-page.component.ts
- 263
+ 284
@@ -1886,7 +1886,7 @@
Rafraîchir
apps/client/src/app/pages/account/account-page.component.ts
- 264
+ 285
@@ -1894,7 +1894,7 @@
Voulez-vous vraiment supprimer cette méthode de connexion ?
apps/client/src/app/pages/account/account-page.component.ts
- 310
+ 331
@@ -2098,7 +2098,7 @@
Accès donné
apps/client/src/app/pages/account/account-page.html
- 282
+ 290
@@ -7249,6 +7249,14 @@
128
+
+ Export Data
+ Export Data
+
+ apps/client/src/app/pages/account/account-page.html
+ 280
+
+
diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf
index 07462d173..0850040b4 100644
--- a/apps/client/src/locales/messages.it.xlf
+++ b/apps/client/src/locales/messages.it.xlf
@@ -623,7 +623,7 @@
Aggiungi
apps/client/src/app/components/admin-overview/admin-overview.html
- 181
+ 183
@@ -631,7 +631,7 @@
Bilancio domestico
apps/client/src/app/components/admin-overview/admin-overview.html
- 188
+ 190
@@ -639,7 +639,7 @@
Svuota la cache
apps/client/src/app/components/admin-overview/admin-overview.html
- 192
+ 194
@@ -1571,7 +1571,7 @@
Inserisci il tuo codice del buono:
apps/client/src/app/pages/account/account-page.component.ts
- 241
+ 262
@@ -1579,7 +1579,7 @@
Impossibile riscattare il codice del buono
apps/client/src/app/pages/account/account-page.component.ts
- 251
+ 272
@@ -1587,7 +1587,7 @@
Il codice del buono è stato riscattato
apps/client/src/app/pages/account/account-page.component.ts
- 263
+ 284
@@ -1595,7 +1595,7 @@
Ricarica
apps/client/src/app/pages/account/account-page.component.ts
- 264
+ 285
@@ -1603,7 +1603,7 @@
Vuoi davvero rimuovere questo metodo di accesso?
apps/client/src/app/pages/account/account-page.component.ts
- 310
+ 331
@@ -1727,7 +1727,7 @@
Accesso concesso
apps/client/src/app/pages/account/account-page.html
- 282
+ 290
@@ -2879,7 +2879,7 @@
Auto
apps/client/src/app/pages/account/account-page.component.ts
- 46
+ 47
@@ -7250,6 +7250,14 @@
128
+
+ Export Data
+ Export Data
+
+ apps/client/src/app/pages/account/account-page.html
+ 280
+
+