diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 4b78a1e7c..20f1fde58 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -12,7 +12,9 @@ import { SUPPORTED_LANGUAGE_CODES } from '@ghostfolio/common/config'; import { BullModule } from '@nestjs/bull'; -import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'; +import { + /*MiddlewareConsumer,*/ Module /*RequestMethod*/ +} from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { ScheduleModule } from '@nestjs/schedule'; import { ServeStaticModule } from '@nestjs/serve-static'; @@ -28,7 +30,7 @@ import { BenchmarkModule } from './benchmark/benchmark.module'; import { CacheModule } from './cache/cache.module'; import { ExchangeRateModule } from './exchange-rate/exchange-rate.module'; import { ExportModule } from './export/export.module'; -import { FrontendMiddleware } from './frontend.middleware'; +// import { FrontendMiddleware } from './frontend.middleware'; import { HealthModule } from './health/health.module'; import { ImportModule } from './import/import.module'; import { InfoModule } from './info/info.module'; @@ -75,12 +77,12 @@ import { UserModule } from './user/user.module'; PrismaModule, RedisCacheModule, ScheduleModule.forRoot(), - ...SUPPORTED_LANGUAGE_CODES.map((languageCode) => { + /*...SUPPORTED_LANGUAGE_CODES.map((languageCode) => { return ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'client', languageCode), serveRoot: `/${languageCode}` }); - }), + }),*/ ServeStaticModule.forRoot({ exclude: ['/api*', '/sitemap.xml'], rootPath: join(__dirname, '..', 'client'), @@ -115,9 +117,9 @@ import { UserModule } from './user/user.module'; providers: [CronService] }) export class AppModule { - configure(consumer: MiddlewareConsumer) { + /*configure(consumer: MiddlewareConsumer) { consumer .apply(FrontendMiddleware) .forRoutes({ path: '*', method: RequestMethod.ALL }); - } + }*/ } diff --git a/apps/api/src/app/frontend.middleware.ts b/apps/api/src/app/frontend.middleware.ts index 9996445a5..1617339c8 100644 --- a/apps/api/src/app/frontend.middleware.ts +++ b/apps/api/src/app/frontend.middleware.ts @@ -1,3 +1,5 @@ +// TODO: Remove + import * as fs from 'fs'; import * as path from 'path'; diff --git a/apps/api/src/app/static.middleware.ts b/apps/api/src/app/static.middleware.ts new file mode 100644 index 000000000..b2b244dc3 --- /dev/null +++ b/apps/api/src/app/static.middleware.ts @@ -0,0 +1,82 @@ +import * as fs from 'fs'; + +import { NextFunction, Request, Response } from 'express'; +import { join } from 'path'; +import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper'; +import { environment } from '@ghostfolio/api/environments/environment'; +import { SUPPORTED_LANGUAGE_CODES } from '@ghostfolio/common/config'; +import { format } from 'date-fns'; + +const title = 'Ghostfolio – Open Source Wealth Management Software'; + +// TODO +const descriptions = { + en: 'Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies across multiple platforms.' +}; + +// TODO +const locales = { + '/en/blog/2022/08/500-stars-on-github': { + featureGraphicPath: 'assets/images/blog/500-stars-on-github.jpg', + title: `500 Stars - ${title}` + } +}; + +const getPathOfIndexHtmlFile = (aLocale: string) => { + return join(__dirname, '..', 'client', aLocale, 'index.html'); +}; + +const isFileRequest = (filename: string) => { + if (filename === '/assets/LICENSE') { + return true; + } else if ( + filename.includes('auth/ey') || + filename.includes( + 'personal-finance-tools/open-source-alternative-to-markets.sh' + ) + ) { + return false; + } + + return filename.split('.').pop() !== filename; +}; + +export const StaticMiddleware = async ( + request: Request, + response: Response, + next: NextFunction +) => { + const path = request.originalUrl.replace(/\/$/, ''); + const languageCode = path.substr(1, 2); + + const currentDate = format(new Date(), DATE_FORMAT); + const rootUrl = 'https://ghostfol.io'; + + if ( + path.startsWith('/api/') || + isFileRequest(path) /*|| + !environment.production*/ + ) { + // Skip + next(); + } else if (SUPPORTED_LANGUAGE_CODES.includes(languageCode)) { + // TODO: Only load once + const indexHtml = interpolate( + fs.readFileSync(getPathOfIndexHtmlFile(languageCode), 'utf8'), + { + currentDate, + languageCode, + path, + rootUrl, + description: descriptions[languageCode], + featureGraphicPath: + locales[path]?.featureGraphicPath ?? 'assets/cover.png', + title: locales[path]?.title ?? title + } + ); + + return response.send(indexHtml); + } else { + // TODO + } +}; diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 5d76776a1..c3b3f2752 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -6,6 +6,7 @@ import * as bodyParser from 'body-parser'; import helmet from 'helmet'; import { AppModule } from './app/app.module'; +import { StaticMiddleware } from './app/static.middleware'; import { environment } from './environments/environment'; async function bootstrap() { @@ -52,6 +53,8 @@ async function bootstrap() { ); } + app.use(StaticMiddleware); + const BASE_CURRENCY = configService.get('BASE_CURRENCY'); const HOST = configService.get('HOST') || '0.0.0.0'; const PORT = configService.get('PORT') || 3333; diff --git a/apps/client/project.json b/apps/client/project.json index 76da6bd1a..0c59bf0e0 100644 --- a/apps/client/project.json +++ b/apps/client/project.json @@ -110,9 +110,6 @@ { "command": "cp apps/client/src/assets/favicon.ico dist/apps/client" }, - { - "command": "cp apps/client/src/assets/index.html dist/apps/client" - }, { "command": "cp apps/client/src/assets/robots.txt dist/apps/client" }, diff --git a/apps/client/src/assets/index.html b/apps/client/src/assets/index.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/client/src/index.html b/apps/client/src/index.html index a7d01e481..55120ec08 100644 --- a/apps/client/src/index.html +++ b/apps/client/src/index.html @@ -1,14 +1,11 @@ - + - Ghostfolio – Open Source Wealth Management Software + ${title} - + - - + + - + - - - - + + + + - - - ${title} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -