From 42274917e02042c3e9b33ce65266ff181e442579 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 5 Aug 2023 19:57:39 +0200 Subject: [PATCH] Release 1.297.4 (#2209) --- CHANGELOG.md | 2 +- apps/api/src/app/app.module.ts | 14 ++++--- apps/api/src/app/frontend.middleware.ts | 39 ++++--------------- .../api/src/app/sitemap/sitemap.controller.ts | 36 +++++++++++++++++ apps/api/src/app/sitemap/sitemap.module.ts | 24 ++++++++++++ apps/api/src/main.ts | 2 +- libs/common/src/lib/helper.ts | 10 +++++ package.json | 2 +- 8 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 apps/api/src/app/sitemap/sitemap.controller.ts create mode 100644 apps/api/src/app/sitemap/sitemap.module.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f91ec2042..3ffe64edc 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). -## 1.297.3 - 2023-08-05 +## 1.297.4 - 2023-08-05 ### Added diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index ce6c67c2b..4b78a1e7c 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -7,11 +7,16 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data- import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { TwitterBotModule } from '@ghostfolio/api/services/twitter-bot/twitter-bot.module'; +import { + DEFAULT_LANGUAGE_CODE, + SUPPORTED_LANGUAGE_CODES +} from '@ghostfolio/common/config'; import { BullModule } from '@nestjs/bull'; import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { ScheduleModule } from '@nestjs/schedule'; import { ServeStaticModule } from '@nestjs/serve-static'; +import { StatusCodes } from 'http-status-codes'; import { AccessModule } from './access/access.module'; import { AccountModule } from './account/account.module'; @@ -32,14 +37,10 @@ import { OrderModule } from './order/order.module'; import { PlatformModule } from './platform/platform.module'; import { PortfolioModule } from './portfolio/portfolio.module'; import { RedisCacheModule } from './redis-cache/redis-cache.module'; +import { SitemapModule } from './sitemap/sitemap.module'; import { SubscriptionModule } from './subscription/subscription.module'; import { SymbolModule } from './symbol/symbol.module'; import { UserModule } from './user/user.module'; -import { - DEFAULT_LANGUAGE_CODE, - SUPPORTED_LANGUAGE_CODES -} from '@ghostfolio/common/config'; -import { StatusCodes } from 'http-status-codes'; @Module({ imports: [ @@ -81,7 +82,7 @@ import { StatusCodes } from 'http-status-codes'; }); }), ServeStaticModule.forRoot({ - exclude: ['/api*'], + exclude: ['/api*', '/sitemap.xml'], rootPath: join(__dirname, '..', 'client'), serveStaticOptions: { setHeaders: (res) => { @@ -104,6 +105,7 @@ import { StatusCodes } from 'http-status-codes'; } } }), + SitemapModule, SubscriptionModule, SymbolModule, TwitterBotModule, diff --git a/apps/api/src/app/frontend.middleware.ts b/apps/api/src/app/frontend.middleware.ts index 8c723e9c8..9996445a5 100644 --- a/apps/api/src/app/frontend.middleware.ts +++ b/apps/api/src/app/frontend.middleware.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import { environment } from '@ghostfolio/api/environments/environment'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; -import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; +import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper'; import { Injectable, NestMiddleware } from '@nestjs/common'; import { format } from 'date-fns'; import { NextFunction, Request, Response } from 'express'; @@ -18,7 +18,6 @@ export class FrontendMiddleware implements NestMiddleware { public indexHtmlIt = ''; public indexHtmlNl = ''; public indexHtmlPt = ''; - public sitemapXml = ''; private static readonly DEFAULT_DESCRIPTION = 'Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies across multiple platforms.'; @@ -55,10 +54,6 @@ export class FrontendMiddleware implements NestMiddleware { this.getPathOfIndexHtmlFile('pt'), 'utf8' ); - this.sitemapXml = fs.readFileSync( - path.join(__dirname, 'assets', 'sitemap.xml'), - 'utf8' - ); } catch {} } @@ -123,16 +118,9 @@ export class FrontendMiddleware implements NestMiddleware { ) { // Skip next(); - } else if (request.path === '/sitemap.xml') { - response.setHeader('content-type', 'application/xml'); - response.send( - this.interpolate(this.sitemapXml, { - currentDate: format(getYesterday(), DATE_FORMAT) - }) - ); } else if (request.path === '/de' || request.path.startsWith('/de/')) { response.send( - this.interpolate(this.indexHtmlDe, { + interpolate(this.indexHtmlDe, { currentDate, featureGraphicPath, title, @@ -145,7 +133,7 @@ export class FrontendMiddleware implements NestMiddleware { ); } else if (request.path === '/es' || request.path.startsWith('/es/')) { response.send( - this.interpolate(this.indexHtmlEs, { + interpolate(this.indexHtmlEs, { currentDate, featureGraphicPath, title, @@ -158,7 +146,7 @@ export class FrontendMiddleware implements NestMiddleware { ); } else if (request.path === '/fr' || request.path.startsWith('/fr/')) { response.send( - this.interpolate(this.indexHtmlFr, { + interpolate(this.indexHtmlFr, { currentDate, featureGraphicPath, title, @@ -171,7 +159,7 @@ export class FrontendMiddleware implements NestMiddleware { ); } else if (request.path === '/it' || request.path.startsWith('/it/')) { response.send( - this.interpolate(this.indexHtmlIt, { + interpolate(this.indexHtmlIt, { currentDate, featureGraphicPath, title, @@ -184,7 +172,7 @@ export class FrontendMiddleware implements NestMiddleware { ); } else if (request.path === '/nl' || request.path.startsWith('/nl/')) { response.send( - this.interpolate(this.indexHtmlNl, { + interpolate(this.indexHtmlNl, { currentDate, featureGraphicPath, title, @@ -197,7 +185,7 @@ export class FrontendMiddleware implements NestMiddleware { ); } else if (request.path === '/pt' || request.path.startsWith('/pt/')) { response.send( - this.interpolate(this.indexHtmlPt, { + interpolate(this.indexHtmlPt, { currentDate, featureGraphicPath, title, @@ -210,7 +198,7 @@ export class FrontendMiddleware implements NestMiddleware { ); } else { response.send( - this.interpolate(this.indexHtmlEn, { + interpolate(this.indexHtmlEn, { currentDate, featureGraphicPath, title, @@ -227,21 +215,10 @@ export class FrontendMiddleware implements NestMiddleware { return path.join(__dirname, '..', 'client', aLocale, 'index.html'); } - private interpolate(template: string, context: any) { - return template.replace(/[$]{([^}]+)}/g, (_, objectPath) => { - const properties = objectPath.split('.'); - return properties.reduce( - (previous, current) => previous?.[current], - context - ); - }); - } - private isFileRequest(filename: string) { if (filename === '/assets/LICENSE') { return true; } else if ( - filename === '/sitemap.xml' || filename.includes('auth/ey') || filename.includes( 'personal-finance-tools/open-source-alternative-to-markets.sh' diff --git a/apps/api/src/app/sitemap/sitemap.controller.ts b/apps/api/src/app/sitemap/sitemap.controller.ts new file mode 100644 index 000000000..59448d06f --- /dev/null +++ b/apps/api/src/app/sitemap/sitemap.controller.ts @@ -0,0 +1,36 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +import { + DATE_FORMAT, + getYesterday, + interpolate +} from '@ghostfolio/common/helper'; +import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common'; +import { format } from 'date-fns'; +import { Response } from 'express'; + +@Controller('/sitemap.xml') +export class SitemapController { + public sitemapXml = ''; + + public constructor() { + try { + this.sitemapXml = fs.readFileSync( + path.join(__dirname, 'assets', 'sitemap.xml'), + 'utf8' + ); + } catch {} + } + + @Get() + @Version(VERSION_NEUTRAL) + public async flushCache(@Res() response: Response): Promise { + response.setHeader('content-type', 'application/xml'); + response.send( + interpolate(this.sitemapXml, { + currentDate: format(getYesterday(), DATE_FORMAT) + }) + ); + } +} diff --git a/apps/api/src/app/sitemap/sitemap.module.ts b/apps/api/src/app/sitemap/sitemap.module.ts new file mode 100644 index 000000000..2fe7358d4 --- /dev/null +++ b/apps/api/src/app/sitemap/sitemap.module.ts @@ -0,0 +1,24 @@ +import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; +import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; +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 { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; +import { Module } from '@nestjs/common'; + +import { SitemapController } from './sitemap.controller'; + +@Module({ + controllers: [SitemapController], + imports: [ + ConfigurationModule, + DataGatheringModule, + DataProviderModule, + ExchangeRateDataModule, + PrismaModule, + RedisCacheModule, + SymbolProfileModule + ] +}) +export class SitemapModule {} diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 45e7a987d..d759c1d87 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -23,7 +23,7 @@ async function bootstrap() { defaultVersion: '1', type: VersioningType.URI }); - app.setGlobalPrefix('api'); + app.setGlobalPrefix('api', { exclude: ['sitemap.xml'] }); app.useGlobalPipes( new ValidationPipe({ forbidNonWhitelisted: true, diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 02b0cc08d..40933e19d 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -234,6 +234,16 @@ export function isCurrency(aSymbol = '') { return currencies[aSymbol]; } +export function interpolate(template: string, context: any) { + return template.replace(/[$]{([^}]+)}/g, (_, objectPath) => { + const properties = objectPath.split('.'); + return properties.reduce( + (previous, current) => previous?.[current], + context + ); + }); +} + export function resetHours(aDate: Date) { const year = getYear(aDate); const month = getMonth(aDate); diff --git a/package.json b/package.json index cf63bdbf6..005df9371 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "1.297.3", + "version": "1.297.4", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "scripts": {