mirror of https://github.com/ghostfolio/ghostfolio
Thomas Kaul
1 year ago
committed by
GitHub
10 changed files with 151 additions and 335 deletions
@ -1,232 +0,0 @@ |
|||
import * as fs from 'fs'; |
|||
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, interpolate } from '@ghostfolio/common/helper'; |
|||
import { Injectable, NestMiddleware } from '@nestjs/common'; |
|||
import { format } from 'date-fns'; |
|||
import { NextFunction, Request, Response } from 'express'; |
|||
|
|||
@Injectable() |
|||
export class FrontendMiddleware implements NestMiddleware { |
|||
public indexHtmlDe = ''; |
|||
public indexHtmlEn = ''; |
|||
public indexHtmlEs = ''; |
|||
public indexHtmlFr = ''; |
|||
public indexHtmlIt = ''; |
|||
public indexHtmlNl = ''; |
|||
public indexHtmlPt = ''; |
|||
|
|||
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.'; |
|||
|
|||
public constructor( |
|||
private readonly configurationService: ConfigurationService |
|||
) { |
|||
try { |
|||
this.indexHtmlDe = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('de'), |
|||
'utf8' |
|||
); |
|||
this.indexHtmlEn = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile(DEFAULT_LANGUAGE_CODE), |
|||
'utf8' |
|||
); |
|||
this.indexHtmlEs = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('es'), |
|||
'utf8' |
|||
); |
|||
this.indexHtmlFr = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('fr'), |
|||
'utf8' |
|||
); |
|||
this.indexHtmlIt = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('it'), |
|||
'utf8' |
|||
); |
|||
this.indexHtmlNl = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('nl'), |
|||
'utf8' |
|||
); |
|||
this.indexHtmlPt = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('pt'), |
|||
'utf8' |
|||
); |
|||
} catch {} |
|||
} |
|||
|
|||
public use(request: Request, response: Response, next: NextFunction) { |
|||
const currentDate = format(new Date(), DATE_FORMAT); |
|||
let featureGraphicPath = 'assets/cover.png'; |
|||
let title = 'Ghostfolio – Open Source Wealth Management Software'; |
|||
|
|||
if (request.path.startsWith('/en/blog/2022/08/500-stars-on-github')) { |
|||
featureGraphicPath = 'assets/images/blog/500-stars-on-github.jpg'; |
|||
title = `500 Stars - ${title}`; |
|||
} else if (request.path.startsWith('/en/blog/2022/10/hacktoberfest-2022')) { |
|||
featureGraphicPath = 'assets/images/blog/hacktoberfest-2022.png'; |
|||
title = `Hacktoberfest 2022 - ${title}`; |
|||
} else if (request.path.startsWith('/en/blog/2022/11/black-friday-2022')) { |
|||
featureGraphicPath = 'assets/images/blog/black-friday-2022.jpg'; |
|||
title = `Black Friday 2022 - ${title}`; |
|||
} else if ( |
|||
request.path.startsWith( |
|||
'/en/blog/2022/12/the-importance-of-tracking-your-personal-finances' |
|||
) |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/20221226.jpg'; |
|||
title = `The importance of tracking your personal finances - ${title}`; |
|||
} else if ( |
|||
request.path.startsWith( |
|||
'/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt' |
|||
) |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/ghostfolio-x-sackgeld.png'; |
|||
title = `Ghostfolio auf Sackgeld.com vorgestellt - ${title}`; |
|||
} else if ( |
|||
request.path.startsWith('/en/blog/2023/02/ghostfolio-meets-umbrel') |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/ghostfolio-x-umbrel.png'; |
|||
title = `Ghostfolio meets Umbrel - ${title}`; |
|||
} else if ( |
|||
request.path.startsWith( |
|||
'/en/blog/2023/03/ghostfolio-reaches-1000-stars-on-github' |
|||
) |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/1000-stars-on-github.jpg'; |
|||
title = `Ghostfolio reaches 1’000 Stars on GitHub - ${title}`; |
|||
} else if ( |
|||
request.path.startsWith( |
|||
'/en/blog/2023/05/unlock-your-financial-potential-with-ghostfolio' |
|||
) |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/20230520.jpg'; |
|||
title = `Unlock your Financial Potential with Ghostfolio - ${title}`; |
|||
} else if ( |
|||
request.path.startsWith('/en/blog/2023/07/exploring-the-path-to-fire') |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/20230701.jpg'; |
|||
title = `Exploring the Path to FIRE - ${title}`; |
|||
} |
|||
|
|||
if ( |
|||
request.path.startsWith('/api/') || |
|||
this.isFileRequest(request.url) || |
|||
!environment.production |
|||
) { |
|||
// Skip
|
|||
next(); |
|||
} else if (request.path === '/de' || request.path.startsWith('/de/')) { |
|||
response.send( |
|||
interpolate(this.indexHtmlDe, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: |
|||
'Mit dem Finanz-Dashboard Ghostfolio können Sie Ihr Vermögen in Form von Aktien, ETFs oder Kryptowährungen verteilt über mehrere Finanzinstitute überwachen.', |
|||
languageCode: 'de', |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else if (request.path === '/es' || request.path.startsWith('/es/')) { |
|||
response.send( |
|||
interpolate(this.indexHtmlEs, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: |
|||
'Ghostfolio es un dashboard de finanzas personales para hacer un seguimiento de tus activos como acciones, ETFs o criptodivisas a través de múltiples plataformas.', |
|||
languageCode: 'es', |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else if (request.path === '/fr' || request.path.startsWith('/fr/')) { |
|||
response.send( |
|||
interpolate(this.indexHtmlFr, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: |
|||
'Ghostfolio est un dashboard de finances personnelles qui permet de suivre vos actifs comme les actions, les ETF ou les crypto-monnaies sur plusieurs plateformes.', |
|||
languageCode: 'fr', |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else if (request.path === '/it' || request.path.startsWith('/it/')) { |
|||
response.send( |
|||
interpolate(this.indexHtmlIt, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: |
|||
'Ghostfolio è un dashboard di finanza personale per tenere traccia delle vostre attività come azioni, ETF o criptovalute su più piattaforme.', |
|||
languageCode: 'it', |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else if (request.path === '/nl' || request.path.startsWith('/nl/')) { |
|||
response.send( |
|||
interpolate(this.indexHtmlNl, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: |
|||
'Ghostfolio is een persoonlijk financieel dashboard om uw activa zoals aandelen, ETF’s of cryptocurrencies over meerdere platforms bij te houden.', |
|||
languageCode: 'nl', |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else if (request.path === '/pt' || request.path.startsWith('/pt/')) { |
|||
response.send( |
|||
interpolate(this.indexHtmlPt, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: |
|||
'Ghostfolio é um dashboard de finanças pessoais para acompanhar os seus activos como acções, ETFs ou criptomoedas em múltiplas plataformas.', |
|||
languageCode: 'pt', |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else { |
|||
response.send( |
|||
interpolate(this.indexHtmlEn, { |
|||
currentDate, |
|||
featureGraphicPath, |
|||
title, |
|||
description: FrontendMiddleware.DEFAULT_DESCRIPTION, |
|||
languageCode: DEFAULT_LANGUAGE_CODE, |
|||
path: request.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} |
|||
} |
|||
|
|||
private getPathOfIndexHtmlFile(aLocale: string) { |
|||
return path.join(__dirname, '..', 'client', aLocale, 'index.html'); |
|||
} |
|||
|
|||
private 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; |
|||
} |
|||
} |
@ -0,0 +1,128 @@ |
|||
import * as fs from 'fs'; |
|||
import { join } from 'path'; |
|||
|
|||
import { environment } from '@ghostfolio/api/environments/environment'; |
|||
import { |
|||
DEFAULT_LANGUAGE_CODE, |
|||
DEFAULT_ROOT_URL, |
|||
SUPPORTED_LANGUAGE_CODES |
|||
} from '@ghostfolio/common/config'; |
|||
import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper'; |
|||
import { format } from 'date-fns'; |
|||
import { NextFunction, Request, Response } from 'express'; |
|||
|
|||
const descriptions = { |
|||
de: 'Mit dem Finanz-Dashboard Ghostfolio können Sie Ihr Vermögen in Form von Aktien, ETFs oder Kryptowährungen verteilt über mehrere Finanzinstitute überwachen.', |
|||
en: 'Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies across multiple platforms.', |
|||
es: 'Ghostfolio es un dashboard de finanzas personales para hacer un seguimiento de tus activos como acciones, ETFs o criptodivisas a través de múltiples plataformas.', |
|||
fr: 'Ghostfolio est un dashboard de finances personnelles qui permet de suivre vos actifs comme les actions, les ETF ou les crypto-monnaies sur plusieurs plateformes.', |
|||
it: 'Ghostfolio è un dashboard di finanza personale per tenere traccia delle vostre attività come azioni, ETF o criptovalute su più piattaforme.', |
|||
nl: 'Ghostfolio is een persoonlijk financieel dashboard om uw activa zoals aandelen, ETF’s of cryptocurrencies over meerdere platforms bij te houden.', |
|||
pt: 'Ghostfolio é um dashboard de finanças pessoais para acompanhar os seus activos como acções, ETFs ou criptomoedas em múltiplas plataformas.' |
|||
}; |
|||
|
|||
const title = 'Ghostfolio – Open Source Wealth Management Software'; |
|||
const titleShort = 'Ghostfolio'; |
|||
|
|||
let indexHtmlMap: { [languageCode: string]: string } = {}; |
|||
|
|||
try { |
|||
indexHtmlMap = SUPPORTED_LANGUAGE_CODES.reduce( |
|||
(map, languageCode) => ({ |
|||
...map, |
|||
[languageCode]: fs.readFileSync( |
|||
join(__dirname, '..', 'client', languageCode, 'index.html'), |
|||
'utf8' |
|||
) |
|||
}), |
|||
{} |
|||
); |
|||
} catch {} |
|||
|
|||
const locales = { |
|||
'/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt': { |
|||
featureGraphicPath: 'assets/images/blog/ghostfolio-x-sackgeld.png', |
|||
title: `Ghostfolio auf Sackgeld.com vorgestellt - ${titleShort}` |
|||
}, |
|||
'/en/blog/2022/08/500-stars-on-github': { |
|||
featureGraphicPath: 'assets/images/blog/500-stars-on-github.jpg', |
|||
title: `500 Stars - ${titleShort}` |
|||
}, |
|||
'/en/blog/2022/10/hacktoberfest-2022': { |
|||
featureGraphicPath: 'assets/images/blog/hacktoberfest-2022.png', |
|||
title: `Hacktoberfest 2022 - ${titleShort}` |
|||
}, |
|||
'/en/blog/2022/12/the-importance-of-tracking-your-personal-finances': { |
|||
featureGraphicPath: 'assets/images/blog/20221226.jpg', |
|||
title: `The importance of tracking your personal finances - ${titleShort}` |
|||
}, |
|||
'/en/blog/2023/02/ghostfolio-meets-umbrel': { |
|||
featureGraphicPath: 'assets/images/blog/ghostfolio-x-umbrel.png', |
|||
title: `Ghostfolio meets Umbrel - ${titleShort}` |
|||
}, |
|||
'/en/blog/2023/03/ghostfolio-reaches-1000-stars-on-github': { |
|||
featureGraphicPath: 'assets/images/blog/1000-stars-on-github.jpg', |
|||
title: `Ghostfolio reaches 1’000 Stars on GitHub - ${titleShort}` |
|||
}, |
|||
'/en/blog/2023/05/unlock-your-financial-potential-with-ghostfolio': { |
|||
featureGraphicPath: 'assets/images/blog/20230520.jpg', |
|||
title: `Unlock your Financial Potential with Ghostfolio - ${titleShort}` |
|||
}, |
|||
'/en/blog/2023/07/exploring-the-path-to-fire': { |
|||
featureGraphicPath: 'assets/images/blog/20230701.jpg', |
|||
title: `Exploring the Path to FIRE - ${titleShort}` |
|||
} |
|||
}; |
|||
|
|||
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 HtmlTemplateMiddleware = async ( |
|||
request: Request, |
|||
response: Response, |
|||
next: NextFunction |
|||
) => { |
|||
const path = request.originalUrl.replace(/\/$/, ''); |
|||
let languageCode = path.substr(1, 2); |
|||
|
|||
if (!SUPPORTED_LANGUAGE_CODES.includes(languageCode)) { |
|||
languageCode = DEFAULT_LANGUAGE_CODE; |
|||
} |
|||
|
|||
const currentDate = format(new Date(), DATE_FORMAT); |
|||
const rootUrl = process.env.ROOT_URL || DEFAULT_ROOT_URL; |
|||
|
|||
if ( |
|||
path.startsWith('/api/') || |
|||
isFileRequest(path) || |
|||
!environment.production |
|||
) { |
|||
// Skip
|
|||
next(); |
|||
} else { |
|||
const indexHtml = interpolate(indexHtmlMap[languageCode], { |
|||
currentDate, |
|||
languageCode, |
|||
path, |
|||
rootUrl, |
|||
description: descriptions[languageCode], |
|||
featureGraphicPath: |
|||
locales[path]?.featureGraphicPath ?? 'assets/cover.png', |
|||
title: locales[path]?.title ?? title |
|||
}); |
|||
|
|||
return response.send(indexHtml); |
|||
} |
|||
}; |
@ -1,63 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html class="h-100 position-relative" lang="${languageCode}"> |
|||
<head> |
|||
<title>${title}</title> |
|||
<base href="/" /> |
|||
<meta charset="utf-8" /> |
|||
<meta content="yes" name="apple-mobile-web-app-capable" /> |
|||
<meta content="${description}" name="description" /> |
|||
<meta |
|||
content="app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3" |
|||
name="keywords" |
|||
/> |
|||
<meta content="yes" name="mobile-web-app-capable" /> |
|||
<meta content="summary_large_image" name="twitter:card" /> |
|||
<meta |
|||
content="Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies" |
|||
name="twitter:description" |
|||
/> |
|||
<meta content="${rootUrl}/${featureGraphicPath}" name="twitter:image" /> |
|||
<meta content="${title}" name="twitter:title" /> |
|||
<meta |
|||
content="initial-scale=1, viewport-fit=cover, width=device-width" |
|||
name="viewport" |
|||
/> |
|||
<meta content="#FFFFFF" name="theme-color" /> |
|||
<meta content="" property="og:description" /> |
|||
<meta content="${title}" property="og:title" /> |
|||
<meta content="website" property="og:type" /> |
|||
<meta content="${rootUrl}${path}" property="og:url" /> |
|||
<meta content="${rootUrl}/${featureGraphicPath}" property="og:image" /> |
|||
<meta content="${currentDate}T00:00:00+00:00" property="og:updated_time" /> |
|||
<meta content="${title}" property="og:site_name" /> |
|||
|
|||
<link |
|||
href="../assets/apple-touch-icon.png" |
|||
rel="apple-touch-icon" |
|||
sizes="180x180" |
|||
/> |
|||
<link |
|||
href="../assets/favicon-32x32.png" |
|||
rel="icon" |
|||
sizes="32x32" |
|||
type="image/png" |
|||
/> |
|||
<link |
|||
href="../assets/favicon-16x16.png" |
|||
rel="icon" |
|||
sizes="16x16" |
|||
type="image/png" |
|||
/> |
|||
<link href="../assets/site.webmanifest" rel="manifest" /> |
|||
</head> |
|||
<body> |
|||
<gf-root></gf-root> |
|||
|
|||
<script src="../ionicons/ionicons.esm.js" type="module"></script> |
|||
<script nomodule="" src="ionicons.js"></script> |
|||
|
|||
<noscript |
|||
>Please enable JavaScript to continue using this application.</noscript |
|||
> |
|||
</body> |
|||
</html> |
Loading…
Reference in new issue