Browse Source

Merge a0bfda518f into 90c90e179e

pull/8270/merge
Thomas Kaul 13 hours ago
committed by GitHub
parent
commit
5aa9de5ff7
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 4
      apps/api/src/app/__snapshots__/app.module.spec.ts.snap
  3. 1
      apps/api/src/app/app.module.spec.ts
  4. 10
      apps/api/src/app/endpoints/asset-profiles/asset.controller.ts
  5. 3
      apps/client/src/app/components/markets/markets.component.ts
  6. 1
      apps/client/src/app/components/markets/markets.html
  7. 2
      libs/ui/src/lib/benchmark/benchmark.component.html
  8. 19
      libs/ui/src/lib/benchmark/benchmark.component.ts

1
CHANGELOG.md

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the market price in the benchmark detail dialog by adding the currency and reducing the precision on mobile
- Improved the style of the close button in the dialog footer component
- Improved the style of the close button in the dialog header component
- Restricted the asset endpoint (`GET api/v1/asset/:dataSource/:symbol`) to authenticated users
- Improved the language localization for German (`de`)
- Upgraded `prettier` from version `3.9.9` to `3.9.10`

4
apps/api/src/app/__snapshots__/app.module.spec.ts.snap

@ -366,7 +366,9 @@ exports[`AppModule should keep the security of each route 1`] = `
],
},
"GET /asset/:dataSource/:symbol": {
"guards": [],
"guards": [
"AuthGuard('jwt')",
],
"interceptors": [
"TransformDataSourceInResponseInterceptor",
"TransformDataSourceInRequestInterceptor",

1
apps/api/src/app/app.module.spec.ts

@ -52,7 +52,6 @@ const AUTHENTICATION_STRATEGIES = ['api-key', 'google', 'jwt', 'oidc'];
* are not served by a controller
*/
const PUBLIC_ROUTES = [
'GET /asset/:dataSource/:symbol',
'GET /assets/:languageCode/site.webmanifest',
'GET /auth/google',
'GET /auth/google/callback',

10
apps/api/src/app/endpoints/asset-profiles/asset.controller.ts

@ -2,7 +2,14 @@ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interce
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor';
import type { AssetResponse } from '@ghostfolio/common/interfaces';
import { Controller, Get, Param, UseInterceptors } from '@nestjs/common';
import {
Controller,
Get,
Param,
UseGuards,
UseInterceptors
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { DataSource } from '@prisma/client';
import { pick } from 'lodash-es';
@ -15,6 +22,7 @@ export class AssetController {
) {}
@Get(':dataSource/:symbol')
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getAsset(

3
apps/client/src/app/components/markets/markets.component.ts

@ -66,6 +66,7 @@ export class GfMarketsComponent implements OnInit {
protected fearAndGreedIndex: number | undefined;
protected fearAndGreedIndexMode: FearAndGreedIndexMode = 'STOCKS';
protected hasPermissionToAccessFearAndGreedIndex: boolean;
protected hasPermissionToOpenBenchmarkDetails = false;
protected hasPermissionToReadMarketDataOfMarkets: boolean;
protected historicalDataItems: LineChartItem[];
protected isLoadingFearAndGreedIndex = true;
@ -99,6 +100,8 @@ export class GfMarketsComponent implements OnInit {
if (state?.user) {
this.user = state.user;
this.hasPermissionToOpenBenchmarkDetails = true;
this.hasPermissionToReadMarketDataOfMarkets = hasPermission(
this.user.permissions,
permissions.readMarketDataOfMarkets

1
apps/client/src/app/components/markets/markets.html

@ -52,6 +52,7 @@
<gf-benchmark
[benchmarks]="benchmarks()"
[deviceType]="deviceType()"
[hasPermissionToOpenDetails]="hasPermissionToOpenBenchmarkDetails"
[locale]="user?.settings?.locale ?? DEFAULT_LOCALE"
[showSymbol]="false"
[user]="user"

2
libs/ui/src/lib/benchmark/benchmark.component.html

@ -200,8 +200,8 @@
<tr *matHeaderRowDef="displayedColumns()" mat-header-row></tr>
<tr
*matRowDef="let row; columns: displayedColumns()"
class="cursor-pointer"
mat-row
[class.cursor-pointer]="hasPermissionToOpenDetails()"
(click)="
onOpenBenchmarkDialog({
dataSource: row.dataSource,

19
libs/ui/src/lib/benchmark/benchmark.component.ts

@ -16,6 +16,7 @@ import {
ChangeDetectionStrategy,
Component,
DestroyRef,
OnInit,
computed,
effect,
inject,
@ -62,10 +63,11 @@ import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interface
styleUrls: ['./benchmark.component.scss'],
templateUrl: './benchmark.component.html'
})
export class GfBenchmarkComponent {
export class GfBenchmarkComponent implements OnInit {
public readonly benchmarks = input<Benchmark[]>();
public readonly deviceType = input.required<string>();
public readonly hasPermissionToDeleteItem = input<boolean>();
public readonly hasPermissionToOpenDetails = input(true);
public readonly locale = input(getLocale());
public readonly showIcon = input(false);
public readonly showSymbol = input(true);
@ -120,10 +122,15 @@ export class GfBenchmarkComponent {
}
});
addIcons({ ellipsisHorizontal, trashOutline });
}
public ngOnInit() {
this.route.queryParams
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((params) => {
if (
this.hasPermissionToOpenDetails() &&
params['benchmarkDetailDialog'] &&
params['dataSource'] &&
params['symbol']
@ -134,8 +141,6 @@ export class GfBenchmarkComponent {
});
}
});
addIcons({ ellipsisHorizontal, trashOutline });
}
protected onDeleteItem({ dataSource, symbol }: AssetProfileIdentifier) {
@ -152,9 +157,11 @@ export class GfBenchmarkComponent {
dataSource,
symbol
}: AssetProfileIdentifier) {
this.router.navigate([], {
queryParams: { dataSource, symbol, benchmarkDetailDialog: true }
});
if (this.hasPermissionToOpenDetails()) {
this.router.navigate([], {
queryParams: { dataSource, symbol, benchmarkDetailDialog: true }
});
}
}
private openBenchmarkDetailDialog({

Loading…
Cancel
Save