mirror of https://github.com/ghostfolio/ghostfolio
125 changed files with 6023 additions and 549 deletions
@ -0,0 +1,81 @@ |
|||
import * as fs from 'fs'; |
|||
import * as path from 'path'; |
|||
|
|||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; |
|||
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; |
|||
import { Injectable, NestMiddleware } from '@nestjs/common'; |
|||
import { NextFunction, Request, Response } from 'express'; |
|||
|
|||
@Injectable() |
|||
export class FrontendMiddleware implements NestMiddleware { |
|||
public indexHtmlDe = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile('de'), |
|||
'utf8' |
|||
); |
|||
public indexHtmlEn = fs.readFileSync( |
|||
this.getPathOfIndexHtmlFile(DEFAULT_LANGUAGE_CODE), |
|||
'utf8' |
|||
); |
|||
|
|||
public constructor( |
|||
private readonly configurationService: ConfigurationService |
|||
) {} |
|||
|
|||
public use(req: Request, res: Response, next: NextFunction) { |
|||
let featureGraphicPath = 'assets/cover.png'; |
|||
|
|||
if ( |
|||
req.path === '/en/blog/2022/08/500-stars-on-github' || |
|||
req.path === '/en/blog/2022/08/500-stars-on-github/' |
|||
) { |
|||
featureGraphicPath = 'assets/images/blog/500-stars-on-github.jpg'; |
|||
} |
|||
|
|||
if (req.path.startsWith('/api/') || this.isFileRequest(req.url)) { |
|||
// Skip
|
|||
next(); |
|||
} else if (req.path === '/de' || req.path.startsWith('/de/')) { |
|||
res.send( |
|||
this.interpolate(this.indexHtmlDe, { |
|||
featureGraphicPath, |
|||
languageCode: 'de', |
|||
path: req.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} else { |
|||
res.send( |
|||
this.interpolate(this.indexHtmlEn, { |
|||
featureGraphicPath, |
|||
languageCode: DEFAULT_LANGUAGE_CODE, |
|||
path: req.path, |
|||
rootUrl: this.configurationService.get('ROOT_URL') |
|||
}) |
|||
); |
|||
} |
|||
} |
|||
|
|||
private getPathOfIndexHtmlFile(aLocale: string) { |
|||
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.includes('auth/ey')) { |
|||
return false; |
|||
} |
|||
|
|||
return filename.split('.').pop() !== filename; |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; |
|||
|
|||
import { FiveHundredStarsOnGitHubPageComponent } from './500-stars-on-github-page.component'; |
|||
|
|||
const routes: Routes = [ |
|||
{ |
|||
canActivate: [AuthGuard], |
|||
component: FiveHundredStarsOnGitHubPageComponent, |
|||
path: '', |
|||
title: '500 Stars on GitHub' |
|||
} |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule] |
|||
}) |
|||
export class FiveHundredStarsOnGitHubRoutingModule {} |
@ -0,0 +1,9 @@ |
|||
import { Component } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
host: { class: 'page' }, |
|||
selector: 'gf-500-stars-on-github-page', |
|||
styleUrls: ['./500-stars-on-github-page.scss'], |
|||
templateUrl: './500-stars-on-github-page.html' |
|||
}) |
|||
export class FiveHundredStarsOnGitHubPageComponent {} |
@ -0,0 +1,195 @@ |
|||
<div class="blog container"> |
|||
<div class="row"> |
|||
<div class="col-md-8 offset-md-2"> |
|||
<article> |
|||
<div class="mb-4 text-center"> |
|||
<h1 class="mb-1">500 Stars</h1> |
|||
<div class="mb-3 text-muted"><small>2022-08-18</small></div> |
|||
<img |
|||
alt="500 Stars on GitHub Teaser" |
|||
class="rounded w-100" |
|||
src="../assets/images/blog/500-stars-on-github.jpg" |
|||
title="500 Stars on GitHub" |
|||
/> |
|||
</div> |
|||
<section class="mb-4"> |
|||
<p> |
|||
<a href="https://ghostfol.io">Ghostfolio</a>, the web-based personal |
|||
finance management software, is celebrating 500 stars on |
|||
<a href="https://github.com/ghostfolio/ghostfolio">GitHub</a>. This |
|||
is a major milestone for this open source project and a good time |
|||
for another |
|||
<a href="../en/blog/2022/01/ghostfolio-first-months-in-open-source" |
|||
>recap</a |
|||
>. |
|||
</p> |
|||
</section> |
|||
<section class="mb-4"> |
|||
<h2 class="h4">Growing Community</h2> |
|||
<p> |
|||
The Ghostfolio community is growing on various platforms and has |
|||
recently passed 100 members on |
|||
<a |
|||
href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg" |
|||
>Slack</a |
|||
> |
|||
as well as 100 followers on |
|||
<a href="https://twitter.com/ghostfolio_">Twitter</a>. If you have |
|||
not joined yet, this is a good time to make sure you do not miss out |
|||
on any future updates. |
|||
</p> |
|||
</section> |
|||
<section class="mb-4"> |
|||
<h2 class="h4">Message Queue: Asynchronous Processing</h2> |
|||
<p> |
|||
Overall |
|||
<a href="https://status.ghostfol.io">stability and robustness</a> |
|||
has increased significantly since the introduction of a |
|||
<a href="https://github.com/OptimalBits/bull">message queue</a>. The |
|||
workers of this robust queue system process jobs, namely gathering |
|||
historical market data, asynchronously in the background to not |
|||
bother the main service. |
|||
</p> |
|||
</section> |
|||
<section class="mb-4"> |
|||
<h2 class="h4">Ready for Web 3.0</h2> |
|||
<p> |
|||
The |
|||
<a href="../en/blog/2022/07/ghostfolio-meets-internet-identity" |
|||
>recent integration of Internet Identity</a |
|||
>, a blockchain authentication system, makes Ghostfolio ready for |
|||
Web3. This third iteration of the World Wide Web is the vision of a |
|||
new and better Internet based on decentralized blockchains to give |
|||
power back to the users. <i>Internet Identity</i> created by the |
|||
<a href="https://dfinity.org">Dfinity Foundation</a> enables you to |
|||
sign in securely and anonymously to Ghostfolio without an email |
|||
address, username, or a password. All you need is your device with |
|||
built-in biometric authentication. |
|||
</p> |
|||
</section> |
|||
<section class="mb-4"> |
|||
<h2 class="h4">Break-even Point</h2> |
|||
<p> |
|||
Despite the complicated |
|||
<a [routerLink]="['/markets']">economic situation</a> at this time, |
|||
the goal set at the beginning of the year to build a sustainable |
|||
business and reach break-even with the SaaS offering (<a |
|||
[routerLink]="['/markets']" |
|||
>Ghostfolio Premium</a |
|||
>) has been achieved. We will continue to leverage the revenue to |
|||
further improve the fully managed cloud offering for our paying |
|||
customers. A new goal we have set for ourselves is to become |
|||
profitable. |
|||
</p> |
|||
</section> |
|||
<section class="mb-4"> |
|||
<h2 class="h4">Outlook</h2> |
|||
<p> |
|||
Besides all the positive accomplishments during the last months, |
|||
there is still a lot of room for improvement. It would be great to |
|||
onboard more contributors who are actively involved in software |
|||
engineering to realize the full potential of open source software. |
|||
If you are a web developer and interested in personal finance, |
|||
please get in touch by email via |
|||
<a href="mailto:hi@ghostfol.io">hi@ghostfol.io</a> or on Twitter |
|||
<a href="https://twitter.com/ghostfolio_">@ghostfolio_</a>. We are |
|||
happy to discuss ideas. |
|||
</p> |
|||
<p> |
|||
We would like to say thank you for all your feedback and support |
|||
since the beginning of this project. |
|||
</p> |
|||
<p> |
|||
Off to the next 500 stars!<br /> |
|||
Thomas from Ghostfolio |
|||
</p> |
|||
</section> |
|||
<section class="mb-4"> |
|||
<ul class="list-inline"> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Blockchain</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">BuildInPublic</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Cloud</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Community</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Finance</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Fintech</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Future</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Goal</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Internet Identity</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Investment</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Message Queue</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">OpenSaaS</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Open Source</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">OSS</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Personal Finance</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Planning</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Portfolio</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Portfolio Tracker</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Progress</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">SaaS</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Software</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">User Feedback</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Wealth</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Wealth Management</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Web3</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Web 3.0</span> |
|||
</li> |
|||
<li class="list-inline-item"> |
|||
<span class="badge badge-light">Worker</span> |
|||
</li> |
|||
</ul> |
|||
</section> |
|||
</article> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,13 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; |
|||
import { RouterModule } from '@angular/router'; |
|||
|
|||
import { FiveHundredStarsOnGitHubRoutingModule } from './500-stars-on-github-page-routing.module'; |
|||
import { FiveHundredStarsOnGitHubPageComponent } from './500-stars-on-github-page.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [FiveHundredStarsOnGitHubPageComponent], |
|||
imports: [CommonModule, FiveHundredStarsOnGitHubRoutingModule, RouterModule], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class FiveHundredStarsOnGitHubPageModule {} |
@ -0,0 +1,3 @@ |
|||
:host { |
|||
display: block; |
|||
} |
After Width: | Height: | Size: 197 KiB |
@ -1,6 +1,6 @@ |
|||
User-agent: * |
|||
Allow: / |
|||
Disallow: /about/privacy-policy |
|||
Disallow: /p/* |
|||
Disallow: /en/about/privacy-policy |
|||
Disallow: /en/p/* |
|||
|
|||
Sitemap: https://ghostfol.io/sitemap.xml |
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue