Skip to content

Commit a9c3224

Browse files
aRonnieAlsopdtslvr
andauthored
Feature/add endpoint to localize site.webmanifest (ghostfolio#4450)
* Add endpoint to localize site.webmanifest * Refactor rootUrl * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
1 parent 198f73d commit a9c3224

File tree

15 files changed

+96
-28
lines changed

15 files changed

+96
-28
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Added support for filtering in the _Copy AI prompt to clipboard_ actions on the analysis page (experimental)
13+
- Added an endpoint to localize the `site.webmanifest`
1314
- Added the _Storybook_ path to the `sitemap.xml` file
1415

1516
### Changed

Diff for: apps/api/src/app/app.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { AuthModule } from './auth/auth.module';
3232
import { CacheModule } from './cache/cache.module';
3333
import { AiModule } from './endpoints/ai/ai.module';
3434
import { ApiKeysModule } from './endpoints/api-keys/api-keys.module';
35+
import { AssetsModule } from './endpoints/assets/assets.module';
3536
import { BenchmarksModule } from './endpoints/benchmarks/benchmarks.module';
3637
import { GhostfolioModule } from './endpoints/data-providers/ghostfolio/ghostfolio.module';
3738
import { MarketDataModule } from './endpoints/market-data/market-data.module';
@@ -61,6 +62,7 @@ import { UserModule } from './user/user.module';
6162
AiModule,
6263
ApiKeysModule,
6364
AssetModule,
65+
AssetsModule,
6466
AuthDeviceModule,
6567
AuthModule,
6668
BenchmarksModule,
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
2+
import { interpolate } from '@ghostfolio/common/helper';
3+
4+
import {
5+
Controller,
6+
Get,
7+
Param,
8+
Res,
9+
Version,
10+
VERSION_NEUTRAL
11+
} from '@nestjs/common';
12+
import { Response } from 'express';
13+
import { readFileSync } from 'fs';
14+
import { join } from 'path';
15+
16+
@Controller('assets')
17+
export class AssetsController {
18+
private webManifest = '';
19+
20+
public constructor(
21+
public readonly configurationService: ConfigurationService
22+
) {
23+
try {
24+
this.webManifest = readFileSync(
25+
join(__dirname, 'assets', 'site.webmanifest'),
26+
'utf8'
27+
);
28+
} catch {}
29+
}
30+
31+
@Get('/:languageCode/site.webmanifest')
32+
@Version(VERSION_NEUTRAL)
33+
public getWebManifest(
34+
@Param('languageCode') languageCode: string,
35+
@Res() response: Response
36+
): void {
37+
const rootUrl = this.configurationService.get('ROOT_URL');
38+
const webManifest = interpolate(this.webManifest, {
39+
languageCode,
40+
rootUrl
41+
});
42+
43+
response.setHeader('Content-Type', 'application/json');
44+
response.send(webManifest);
45+
}
46+
}

Diff for: apps/api/src/app/endpoints/assets/assets.module.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
2+
3+
import { Module } from '@nestjs/common';
4+
5+
import { AssetsController } from './assets.controller';
6+
7+
@Module({
8+
controllers: [AssetsController],
9+
providers: [ConfigurationService]
10+
})
11+
export class AssetsModule {}

Diff for: apps/api/src/app/sitemap/sitemap.controller.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'
99
import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common';
1010
import { format } from 'date-fns';
1111
import { Response } from 'express';
12-
import * as fs from 'fs';
13-
import * as path from 'path';
12+
import { readFileSync } from 'fs';
13+
import { join } from 'path';
1414

1515
@Controller('sitemap.xml')
1616
export class SitemapController {
@@ -20,8 +20,8 @@ export class SitemapController {
2020
private readonly configurationService: ConfigurationService
2121
) {
2222
try {
23-
this.sitemapXml = fs.readFileSync(
24-
path.join(__dirname, 'assets', 'sitemap.xml'),
23+
this.sitemapXml = readFileSync(
24+
join(__dirname, 'assets', 'sitemap.xml'),
2525
'utf8'
2626
);
2727
} catch {}

Diff for: apps/client/src/assets/site.webmanifest renamed to apps/api/src/assets/site.webmanifest

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"name": "Ghostfolio",
2626
"orientation": "portrait",
2727
"short_name": "Ghostfolio",
28-
"start_url": "/en/",
28+
"start_url": "/${languageCode}/",
2929
"theme_color": "#FFFFFF",
30-
"url": "https://ghostfol.io"
30+
"url": "${rootUrl}"
3131
}

Diff for: apps/api/src/environments/environment.prod.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { DEFAULT_HOST, DEFAULT_PORT } from '@ghostfolio/common/config';
2+
13
export const environment = {
24
production: true,
5+
rootUrl: `http://${DEFAULT_HOST}:${DEFAULT_PORT}`,
36
version: `${require('../../../../package.json').version}`
47
};

Diff for: apps/api/src/environments/environment.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { DEFAULT_HOST } from '@ghostfolio/common/config';
2+
13
export const environment = {
24
production: false,
5+
rootUrl: `https://${DEFAULT_HOST}:4200`,
36
version: 'dev'
47
};

Diff for: apps/api/src/main.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { STORYBOOK_PATH } from '@ghostfolio/common/config';
1+
import {
2+
DEFAULT_HOST,
3+
DEFAULT_PORT,
4+
STORYBOOK_PATH
5+
} from '@ghostfolio/common/config';
26

37
import {
48
Logger,
@@ -75,8 +79,8 @@ async function bootstrap() {
7579

7680
app.use(HtmlTemplateMiddleware);
7781

78-
const HOST = configService.get<string>('HOST') || '0.0.0.0';
79-
const PORT = configService.get<number>('PORT') || 3333;
82+
const HOST = configService.get<string>('HOST') || DEFAULT_HOST;
83+
const PORT = configService.get<number>('PORT') || DEFAULT_PORT;
8084

8185
await app.listen(PORT, HOST, () => {
8286
logLogo();

Diff for: apps/api/src/middlewares/html-template.middleware.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { environment } from '@ghostfolio/api/environments/environment';
22
import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service';
33
import {
44
DEFAULT_LANGUAGE_CODE,
5-
DEFAULT_ROOT_URL,
65
STORYBOOK_PATH,
76
SUPPORTED_LANGUAGE_CODES
87
} from '@ghostfolio/common/config';
@@ -126,7 +125,7 @@ export const HtmlTemplateMiddleware = async (
126125
}
127126

128127
const currentDate = format(new Date(), DATE_FORMAT);
129-
const rootUrl = process.env.ROOT_URL || DEFAULT_ROOT_URL;
128+
const rootUrl = process.env.ROOT_URL || environment.rootUrl;
130129

131130
if (
132131
path.startsWith('/api/') ||

Diff for: apps/api/src/services/configuration/configuration.service.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
import { environment } from '@ghostfolio/api/environments/environment';
12
import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface';
23
import {
34
CACHE_TTL_NO_CACHE,
5+
DEFAULT_HOST,
6+
DEFAULT_PORT,
47
DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY,
58
DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY,
69
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY,
7-
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT,
8-
DEFAULT_ROOT_URL
10+
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT
911
} from '@ghostfolio/common/config';
1012

1113
import { Injectable } from '@nestjs/common';
@@ -49,11 +51,11 @@ export class ConfigurationService {
4951
GOOGLE_SHEETS_ACCOUNT: str({ default: '' }),
5052
GOOGLE_SHEETS_ID: str({ default: '' }),
5153
GOOGLE_SHEETS_PRIVATE_KEY: str({ default: '' }),
52-
HOST: host({ default: '0.0.0.0' }),
54+
HOST: host({ default: DEFAULT_HOST }),
5355
JWT_SECRET_KEY: str({}),
5456
MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }),
5557
MAX_CHART_ITEMS: num({ default: 365 }),
56-
PORT: port({ default: 3333 }),
58+
PORT: port({ default: DEFAULT_PORT }),
5759
PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY: num({
5860
default: DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY
5961
}),
@@ -71,7 +73,9 @@ export class ConfigurationService {
7173
REDIS_PASSWORD: str({ default: '' }),
7274
REDIS_PORT: port({ default: 6379 }),
7375
REQUEST_TIMEOUT: num({ default: ms('3 seconds') }),
74-
ROOT_URL: url({ default: DEFAULT_ROOT_URL }),
76+
ROOT_URL: url({
77+
default: environment.rootUrl
78+
}),
7579
STRIPE_PUBLIC_KEY: str({ default: '' }),
7680
STRIPE_SECRET_KEY: str({ default: '' }),
7781
TWITTER_ACCESS_TOKEN: str({ default: 'dummyAccessToken' }),

Diff for: apps/client/ngsw-config.json

+1-7
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,7 @@
66
"name": "app",
77
"installMode": "prefetch",
88
"resources": {
9-
"files": [
10-
"/favicon.ico",
11-
"/index.html",
12-
"/assets/site.webmanifest",
13-
"/*.css",
14-
"/*.js"
15-
]
9+
"files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
1610
}
1711
},
1812
{

Diff for: apps/client/project.json

-3
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@
146146
{
147147
"command": "shx cp apps/client/src/assets/robots.txt dist/apps/client"
148148
},
149-
{
150-
"command": "shx cp apps/client/src/assets/site.webmanifest dist/apps/client"
151-
},
152149
{
153150
"command": "shx cp node_modules/ionicons/dist/index.js dist/apps/client"
154151
},

Diff for: apps/client/src/index.html

+4-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@
4545
sizes="16x16"
4646
type="image/png"
4747
/>
48-
<link href="../assets/site.webmanifest" rel="manifest" />
48+
<link
49+
href="../api/assets/${languageCode}/site.webmanifest"
50+
rel="manifest"
51+
/>
4952
</head>
5053
<body>
5154
<gf-root></gf-root>

Diff for: libs/common/src/lib/config.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW =
4848

4949
export const DEFAULT_CURRENCY = 'USD';
5050
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
51+
export const DEFAULT_HOST = '0.0.0.0';
5152
export const DEFAULT_LANGUAGE_CODE = 'en';
5253
export const DEFAULT_PAGE_SIZE = 50;
54+
export const DEFAULT_PORT = 3333;
5355
export const DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY = 1;
5456
export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY = 1;
5557
export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY = 1;
5658
export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000;
57-
export const DEFAULT_ROOT_URL = 'https://localhost:4200';
5859

5960
// USX is handled separately
6061
export const DERIVED_CURRENCIES = [

0 commit comments

Comments
 (0)