Browse Source

Feature/add hacktoberfest 2025 blog post (#5584)

* Add blog post: Hacktoberfest 2025

* Update changelog
pull/5596/head
Thomas Kaul 3 weeks ago
committed by GitHub
parent
commit
90b28ea74f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 1
      apps/api/src/app/endpoints/sitemap/sitemap.controller.ts
  3. 138
      apps/api/src/app/endpoints/sitemap/sitemap.service.ts
  4. 1
      apps/api/src/assets/sitemap.xml
  5. 4
      apps/api/src/middlewares/html-template.middleware.ts
  6. 17
      apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component.ts
  7. 202
      apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.html
  8. 9
      apps/client/src/app/pages/blog/blog-page-routing.module.ts
  9. 24
      apps/client/src/app/pages/blog/blog-page.html
  10. BIN
      apps/client/src/assets/images/blog/hacktoberfest-2025.png

4
CHANGELOG.md

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Added a blog post: _Hacktoberfest 2025_
### Changed
- Removed the deprecated `ITEM` activity type

1
apps/api/src/app/endpoints/sitemap/sitemap.controller.ts

@ -37,6 +37,7 @@ export class SitemapController {
response.setHeader('content-type', 'application/xml');
response.send(
interpolate(this.sitemapXml, {
blogPosts: this.sitemapService.getBlogPosts({ currentDate }),
personalFinanceTools: this.configurationService.get(
'ENABLE_FEATURE_SUBSCRIPTION'
)

138
apps/api/src/app/endpoints/sitemap/sitemap.service.ts

@ -17,6 +17,121 @@ export class SitemapService {
private readonly i18nService: I18nService
) {}
public getBlogPosts({ currentDate }: { currentDate: string }) {
const rootUrl = this.configurationService.get('ROOT_URL');
return [
{
languageCode: 'de',
routerLink: ['2021', '07', 'hallo-ghostfolio']
},
{
languageCode: 'en',
routerLink: ['2021', '07', 'hello-ghostfolio']
},
{
languageCode: 'en',
routerLink: ['2022', '01', 'ghostfolio-first-months-in-open-source']
},
{
languageCode: 'en',
routerLink: ['2022', '07', 'ghostfolio-meets-internet-identity']
},
{
languageCode: 'en',
routerLink: ['2022', '07', 'how-do-i-get-my-finances-in-order']
},
{
languageCode: 'en',
routerLink: ['2022', '08', '500-stars-on-github']
},
{
languageCode: 'en',
routerLink: ['2022', '10', 'hacktoberfest-2022']
},
{
languageCode: 'en',
routerLink: ['2022', '11', 'black-friday-2022']
},
{
languageCode: 'en',
routerLink: [
'2022',
'12',
'the-importance-of-tracking-your-personal-finances'
]
},
{
languageCode: 'de',
routerLink: ['2023', '01', 'ghostfolio-auf-sackgeld-vorgestellt']
},
{
languageCode: 'en',
routerLink: ['2023', '02', 'ghostfolio-meets-umbrel']
},
{
languageCode: 'en',
routerLink: ['2023', '03', 'ghostfolio-reaches-1000-stars-on-github']
},
{
languageCode: 'en',
routerLink: [
'2023',
'05',
'unlock-your-financial-potential-with-ghostfolio'
]
},
{
languageCode: 'en',
routerLink: ['2023', '07', 'exploring-the-path-to-fire']
},
{
languageCode: 'en',
routerLink: ['2023', '08', 'ghostfolio-joins-oss-friends']
},
{
languageCode: 'en',
routerLink: ['2023', '09', 'ghostfolio-2']
},
{
languageCode: 'en',
routerLink: ['2023', '09', 'hacktoberfest-2023']
},
{
languageCode: 'en',
routerLink: ['2023', '11', 'black-week-2023']
},
{
languageCode: 'en',
routerLink: ['2023', '11', 'hacktoberfest-2023-debriefing']
},
{
languageCode: 'en',
routerLink: ['2024', '09', 'hacktoberfest-2024']
},
{
languageCode: 'en',
routerLink: ['2024', '11', 'black-weeks-2024']
},
{
languageCode: 'en',
routerLink: ['2025', '09', 'hacktoberfest-2025']
}
]
.map(({ languageCode, routerLink }) => {
return this.createRouteSitemapUrl({
currentDate,
languageCode,
rootUrl,
route: {
routerLink: ['blog', ...routerLink],
path: undefined
}
});
})
.join('\n');
}
public getPersonalFinanceTools({ currentDate }: { currentDate: string }) {
const rootUrl = this.configurationService.get('ROOT_URL');
@ -43,20 +158,21 @@ export class SitemapService {
});
return personalFinanceTools.map(({ alias, key }) => {
const location = [
rootUrl,
languageCode,
const routerLink = [
resourcesPath,
personalFinanceToolsPath,
`${productPath}-${alias ?? key}`
].join('/');
return [
' <url>',
` <loc>${location}</loc>`,
` <lastmod>${currentDate}T00:00:00+00:00</lastmod>`,
' </url>'
].join('\n');
];
return this.createRouteSitemapUrl({
currentDate,
languageCode,
rootUrl,
route: {
routerLink,
path: undefined
}
});
});
}).join('\n');
}

1
apps/api/src/assets/sitemap.xml

@ -5,5 +5,6 @@
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
${publicRoutes}
${blogPosts}
${personalFinanceTools}
</urlset>

4
apps/api/src/middlewares/html-template.middleware.ts

@ -75,6 +75,10 @@ const locales = {
'/en/blog/2024/11/black-weeks-2024': {
featureGraphicPath: 'assets/images/blog/black-weeks-2024.jpg',
title: `Black Weeks 2024 - ${title}`
},
'/en/blog/2025/09/hacktoberfest-2025': {
featureGraphicPath: 'assets/images/blog/hacktoberfest-2025.png',
title: `Hacktoberfest 2025 - ${title}`
}
};

17
apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component.ts

@ -0,0 +1,17 @@
import { publicRoutes } from '@ghostfolio/common/routes/routes';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@Component({
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hacktoberfest-2025-page',
templateUrl: './hacktoberfest-2025-page.html'
})
export class Hacktoberfest2025PageComponent {
public routerLinkAbout = publicRoutes.about.routerLink;
public routerLinkBlog = publicRoutes.blog.routerLink;
public routerLinkOpenStartup = publicRoutes.openStartup.routerLink;
}

202
apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.html

@ -0,0 +1,202 @@
<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">Hacktoberfest 2025</h1>
<div class="mb-3 text-muted"><small>2025-09-27</small></div>
<img
alt="Hacktoberfest 2025 with Ghostfolio Teaser"
class="rounded w-100"
src="../assets/images/blog/hacktoberfest-2025.png"
title="Hacktoberfest 2025 with Ghostfolio"
/>
</div>
<section class="mb-4">
<p>
Ghostfolio is joining
<a href="https://hacktoberfest.com">Hacktoberfest</a> for the fourth
time and <a [routerLink]="routerLinkAbout">we</a> are looking
forward to meeting new open-source contributors along the way. Every
year in October, Hacktoberfest celebrates open source by
highlighting projects, maintainers, and contributors worldwide. Open
source maintainers around the globe dedicate extra time to support
new contributors while guiding them through their first pull
requests on
<a href="https://github.com/ghostfolio/ghostfolio">GitHub</a>.
</p>
</section>
<section class="mb-4">
<h2 class="h4">
Meet Ghostfolio: a modern Dashboard for Personal Finance
</h2>
<p>
<a href="https://ghostfol.io">Ghostfolio</a> is a web application
that makes it easy to manage your personal finances. It aggregates
your assets and helps you make informed decisions to balance your
portfolio or plan future investments.
</p>
<p>
The software is fully written in
<a href="https://www.typescriptlang.org">TypeScript</a> and
organized as an <a href="https://nx.dev">Nx</a> workspace, utilizing
the latest framework releases. The backend is based on
<a href="https://nestjs.com">NestJS</a> in combination with
<a href="https://www.postgresql.org">PostgreSQL</a> as a database
together with <a href="https://www.prisma.io">Prisma</a> and
<a href="https://redis.io">Redis</a> for caching. The frontend is
developed with <a href="https://angular.dev">Angular</a>.
</p>
<p>
With over 200 contributors, the OSS project is used daily by a
growing global community. Ghostfolio counts more than
<a [routerLink]="routerLinkOpenStartup">6’600 stars on GitHub</a>
and
<a [routerLink]="routerLinkOpenStartup"
>1’600’000+ pulls on Docker Hub</a
>, standing out for its simple and user-friendly experience.
</p>
</section>
<section class="mb-4">
<h2 class="h4">How you can make an impact</h2>
<p>
Every contribution makes a difference. Whether it is implementing
new features, resolving bugs, refactoring code, enhancing
documentation, adding unit tests, or translating content into
another language, you can actively shape our project.
</p>
<p>
New to our codebase? No worries! We have labeled a few
<a
href="https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3Ahacktoberfest"
>issues</a
>
with <code>hacktoberfest</code> that are ideal for newcomers.
</p>
<p>
The official Hacktoberfest website provides some valuable
<a
href="https://hacktoberfest.com/participation/#beginner-resources"
>resources for beginners</a
>
to start contributing in open source.
</p>
</section>
<section class="mb-4">
<h2 class="h4">Connect with us</h2>
<p>
If you have further questions or ideas, please join our
<a
href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg"
>Slack</a
>
community or get in touch on X
<a href="https://x.com/ghostfolio_">&#64;ghostfolio_</a>.
</p>
<p>
We look forward to collaborating.<br />
Thomas from Ghostfolio
</p>
</section>
<section class="mb-4">
<ul class="list-inline">
<li class="list-inline-item">
<span class="badge badge-light">Angular</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">Dashboard</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Docker</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">Ghostfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">GitHub</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Hacktoberfest</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Hacktoberfest 2025</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">NestJS</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Nx</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">October</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">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">Prisma</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Redis</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">TypeScript</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">UX</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">Web Application</span>
</li>
</ul>
</section>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a i18n [routerLink]="routerLinkBlog">Blog</a>
</li>
<li
aria-current="page"
class="active breadcrumb-item text-truncate"
>
Hacktoberfest 2025
</li>
</ol>
</nav>
</article>
</div>
</div>
</div>

9
apps/client/src/app/pages/blog/blog-page-routing.module.ts

@ -201,6 +201,15 @@ const routes: Routes = [
(c) => c.BlackWeeks2024PageComponent
),
title: 'Black Weeks 2024'
},
{
canActivate: [AuthGuard],
path: '2025/09/hacktoberfest-2025',
loadComponent: () =>
import(
'./2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component'
).then((c) => c.Hacktoberfest2025PageComponent),
title: 'Hacktoberfest 2025'
}
];

24
apps/client/src/app/pages/blog/blog-page.html

@ -8,6 +8,30 @@
finance</small
>
</h1>
<mat-card appearance="outlined" class="mb-3">
<mat-card-content class="p-0">
<div class="container p-0">
<div class="flex-nowrap no-gutters row">
<a
class="d-flex overflow-hidden p-3 w-100"
href="../en/blog/2025/09/hacktoberfest-2025"
>
<div class="flex-grow-1 overflow-hidden">
<div class="h6 m-0 text-truncate">Hacktoberfest 2025</div>
<div class="d-flex text-muted">2025-09-27</div>
</div>
<div class="align-items-center d-flex">
<ion-icon
class="chevron text-muted"
name="chevron-forward-outline"
size="small"
/>
</div>
</a>
</div>
</div>
</mat-card-content>
</mat-card>
@if (hasPermissionForSubscription) {
<mat-card appearance="outlined" class="mb-3">
<mat-card-content class="p-0">

BIN
apps/client/src/assets/images/blog/hacktoberfest-2025.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Loading…
Cancel
Save