From ccaf06360ab87e45a21341ea073378185b7b020f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 11 Feb 2024 10:06:07 +0100 Subject: [PATCH] Feature/introduce admin setting to disable data gathering (#2981) * Introduce setting to disable data gathering * Update changelog --- CHANGELOG.md | 4 ++ apps/api/src/app/app.module.ts | 2 + apps/api/src/services/cron.service.ts | 53 ++++++++++++------- .../admin-overview.component.ts | 13 +++++ .../admin-overview/admin-overview.html | 11 ++++ libs/common/src/lib/config.ts | 1 + .../src/lib/interfaces/info-item.interface.ts | 1 + 7 files changed, 66 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b2c8d7d7..646f5808f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Introduced a setting to disable the data gathering in the admin control + ### Changed - Harmonized the environment variables of various API keys diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 03c6a4aaa..9c17585ab 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -6,6 +6,7 @@ import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/dat import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; import { TwitterBotModule } from '@ghostfolio/api/services/twitter-bot/twitter-bot.module'; import { DEFAULT_LANGUAGE_CODE, @@ -73,6 +74,7 @@ import { UserModule } from './user/user.module'; PlatformModule, PortfolioModule, PrismaModule, + PropertyModule, RedisCacheModule, ScheduleModule.forRoot(), ServeStaticModule.forRoot({ diff --git a/apps/api/src/services/cron.service.ts b/apps/api/src/services/cron.service.ts index e3597f049..b896c684f 100644 --- a/apps/api/src/services/cron.service.ts +++ b/apps/api/src/services/cron.service.ts @@ -1,6 +1,7 @@ import { GATHER_ASSET_PROFILE_PROCESS, - GATHER_ASSET_PROFILE_PROCESS_OPTIONS + GATHER_ASSET_PROFILE_PROCESS_OPTIONS, + PROPERTY_IS_DATA_GATHERING_ENABLED } from '@ghostfolio/common/config'; import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { Injectable } from '@nestjs/common'; @@ -8,6 +9,7 @@ import { Cron, CronExpression } from '@nestjs/schedule'; import { DataGatheringService } from './data-gathering/data-gathering.service'; import { ExchangeRateDataService } from './exchange-rate-data/exchange-rate-data.service'; +import { PropertyService } from './property/property.service'; import { TwitterBotService } from './twitter-bot/twitter-bot.service'; @Injectable() @@ -17,12 +19,15 @@ export class CronService { public constructor( private readonly dataGatheringService: DataGatheringService, private readonly exchangeRateDataService: ExchangeRateDataService, + private readonly propertyService: PropertyService, private readonly twitterBotService: TwitterBotService ) {} @Cron(CronExpression.EVERY_HOUR) public async runEveryHour() { - await this.dataGatheringService.gather7Days(); + if (await this.isDataGatheringEnabled()) { + await this.dataGatheringService.gather7Days(); + } } @Cron(CronExpression.EVERY_12_HOURS) @@ -37,22 +42,32 @@ export class CronService { @Cron(CronService.EVERY_SUNDAY_AT_LUNCH_TIME) public async runEverySundayAtTwelvePm() { - const uniqueAssets = await this.dataGatheringService.getUniqueAssets(); - - await this.dataGatheringService.addJobsToQueue( - uniqueAssets.map(({ dataSource, symbol }) => { - return { - data: { - dataSource, - symbol - }, - name: GATHER_ASSET_PROFILE_PROCESS, - opts: { - ...GATHER_ASSET_PROFILE_PROCESS_OPTIONS, - jobId: getAssetProfileIdentifier({ dataSource, symbol }) - } - }; - }) - ); + if (await this.isDataGatheringEnabled()) { + const uniqueAssets = await this.dataGatheringService.getUniqueAssets(); + + await this.dataGatheringService.addJobsToQueue( + uniqueAssets.map(({ dataSource, symbol }) => { + return { + data: { + dataSource, + symbol + }, + name: GATHER_ASSET_PROFILE_PROCESS, + opts: { + ...GATHER_ASSET_PROFILE_PROCESS_OPTIONS, + jobId: getAssetProfileIdentifier({ dataSource, symbol }) + } + }; + }) + ); + } + } + + private async isDataGatheringEnabled() { + return (await this.propertyService.getByKey( + PROPERTY_IS_DATA_GATHERING_ENABLED + )) === false + ? false + : true; } } diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index 4b3e1f125..3c9ec9295 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -7,6 +7,7 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { PROPERTY_COUPONS, PROPERTY_CURRENCIES, + PROPERTY_IS_DATA_GATHERING_ENABLED, PROPERTY_IS_READ_ONLY_MODE, PROPERTY_IS_USER_SIGNUP_ENABLED, PROPERTY_SYSTEM_MESSAGE, @@ -43,6 +44,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { public hasPermissionForSystemMessage: boolean; public hasPermissionToToggleReadOnlyMode: boolean; public info: InfoItem; + public isDataGatheringEnabled: boolean; public permissions = permissions; public systemMessage: SystemMessage; public transactionCount: number; @@ -168,6 +170,13 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { } } + public onEnableDataGatheringChange(aEvent: MatSlideToggleChange) { + this.putAdminSetting({ + key: PROPERTY_IS_DATA_GATHERING_ENABLED, + value: aEvent.checked ? undefined : false + }); + } + public onFlushCache() { const confirmation = confirm( $localize`Do you really want to flush the cache?` @@ -233,6 +242,10 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? []; this.customCurrencies = settings[PROPERTY_CURRENCIES] as string[]; this.exchangeRates = exchangeRates; + this.isDataGatheringEnabled = + settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false + ? false + : true; this.systemMessage = settings[ PROPERTY_SYSTEM_MESSAGE ] as SystemMessage; 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 bdf623bab..b1be5bd89 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -128,6 +128,17 @@ > +
+
Data Gathering
+
+ +
+
System Message
diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index b93d22f45..3bbe0ff8c 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -97,6 +97,7 @@ export const PROPERTY_COUPONS = 'COUPONS'; export const PROPERTY_CURRENCIES = 'CURRENCIES'; export const PROPERTY_DATA_SOURCE_MAPPING = 'DATA_SOURCE_MAPPING'; export const PROPERTY_DEMO_USER_ID = 'DEMO_USER_ID'; +export const PROPERTY_IS_DATA_GATHERING_ENABLED = 'IS_DATA_GATHERING_ENABLED'; export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE'; export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED'; export const PROPERTY_SLACK_COMMUNITY_USERS = 'SLACK_COMMUNITY_USERS'; diff --git a/libs/common/src/lib/interfaces/info-item.interface.ts b/libs/common/src/lib/interfaces/info-item.interface.ts index 1d3624e24..6b8fc665f 100644 --- a/libs/common/src/lib/interfaces/info-item.interface.ts +++ b/libs/common/src/lib/interfaces/info-item.interface.ts @@ -12,6 +12,7 @@ export interface InfoItem { demoAuthToken: string; fearAndGreedDataSource?: string; globalPermissions: string[]; + isDataGatheringEnabled?: string; isReadOnlyMode?: boolean; platforms: Platform[]; statistics: Statistics;