Browse Source

Task/refactor asset profile deletion permissions (#6940)

Refactor permissions
main
Thomas Kaul 1 day ago
committed by GitHub
parent
commit
5689326b12
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      apps/client/src/app/components/admin-market-data/admin-market-data.component.ts
  2. 4
      apps/client/src/app/components/admin-market-data/admin-market-data.html
  3. 30
      apps/client/src/app/components/admin-market-data/admin-market-data.service.ts
  4. 2
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  5. 2
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  6. 30
      libs/common/src/lib/helper.ts

7
apps/client/src/app/components/admin-market-data/admin-market-data.component.ts

@ -4,7 +4,10 @@ import {
DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE,
locale locale
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { getDateFormatString } from '@ghostfolio/common/helper'; import {
canDeleteAssetProfile,
getDateFormatString
} from '@ghostfolio/common/helper';
import { import {
AssetProfileIdentifier, AssetProfileIdentifier,
Filter, Filter,
@ -101,6 +104,7 @@ import { CreateAssetProfileDialogParams } from './create-asset-profile-dialog/in
}) })
export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { export class GfAdminMarketDataComponent implements AfterViewInit, OnInit {
protected readonly adminMarketDataService = inject(AdminMarketDataService); protected readonly adminMarketDataService = inject(AdminMarketDataService);
protected readonly allFilters: Filter[] = [ protected readonly allFilters: Filter[] = [
...Object.keys(AssetSubClass) ...Object.keys(AssetSubClass)
.filter((assetSubClass) => { .filter((assetSubClass) => {
@ -146,6 +150,7 @@ export class GfAdminMarketDataComponent implements AfterViewInit, OnInit {
type: 'PRESET_ID' as Filter['type'] type: 'PRESET_ID' as Filter['type']
} }
]; ];
protected readonly canDeleteAssetProfile = canDeleteAssetProfile;
protected dataSource = new MatTableDataSource<AdminMarketDataItem>(); protected dataSource = new MatTableDataSource<AdminMarketDataItem>();
protected defaultDateFormat: string; protected defaultDateFormat: string;
protected readonly displayedColumns: string[] = []; protected readonly displayedColumns: string[] = [];

4
apps/client/src/app/components/admin-market-data/admin-market-data.html

@ -52,7 +52,7 @@
<th *matHeaderCellDef class="px-1" mat-header-cell></th> <th *matHeaderCellDef class="px-1" mat-header-cell></th>
<td *matCellDef="let element" class="px-1" mat-cell> <td *matCellDef="let element" class="px-1" mat-cell>
@if ( @if (
adminMarketDataService.hasPermissionToDeleteAssetProfile({ canDeleteAssetProfile({
activitiesCount: element.activitiesCount, activitiesCount: element.activitiesCount,
isBenchmark: element.isBenchmark, isBenchmark: element.isBenchmark,
symbol: element.symbol, symbol: element.symbol,
@ -271,7 +271,7 @@
<button <button
mat-menu-item mat-menu-item
[disabled]=" [disabled]="
!adminMarketDataService.hasPermissionToDeleteAssetProfile({ !canDeleteAssetProfile({
activitiesCount: element.activitiesCount, activitiesCount: element.activitiesCount,
isBenchmark: element.isBenchmark, isBenchmark: element.isBenchmark,
symbol: element.symbol symbol: element.symbol

30
apps/client/src/app/components/admin-market-data/admin-market-data.service.ts

@ -1,14 +1,5 @@
import { ghostfolioScraperApiSymbolPrefix } from '@ghostfolio/common/config';
import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import { import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
getCurrencyFromSymbol,
isDerivedCurrency,
isRootCurrency
} from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
AdminMarketDataItem
} from '@ghostfolio/common/interfaces';
import { NotificationService } from '@ghostfolio/ui/notifications'; import { NotificationService } from '@ghostfolio/ui/notifications';
import { AdminService } from '@ghostfolio/ui/services'; import { AdminService } from '@ghostfolio/ui/services';
@ -68,23 +59,4 @@ export class AdminMarketDataService {
title: $localize`Do you really want to delete these profiles?` title: $localize`Do you really want to delete these profiles?`
}); });
} }
public hasPermissionToDeleteAssetProfile({
activitiesCount,
isBenchmark,
symbol,
watchedByCount
}: Pick<
AdminMarketDataItem,
'activitiesCount' | 'isBenchmark' | 'symbol' | 'watchedByCount'
>) {
return (
activitiesCount === 0 &&
!isBenchmark &&
!isDerivedCurrency(getCurrencyFromSymbol(symbol)) &&
!isRootCurrency(getCurrencyFromSymbol(symbol)) &&
!symbol.startsWith(ghostfolioScraperApiSymbolPrefix) &&
watchedByCount === 0
);
}
} }

2
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -6,6 +6,7 @@ import {
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { UpdateAssetProfileDto } from '@ghostfolio/common/dtos'; import { UpdateAssetProfileDto } from '@ghostfolio/common/dtos';
import { import {
canDeleteAssetProfile,
DATE_FORMAT, DATE_FORMAT,
getCurrencyFromSymbol, getCurrencyFromSymbol,
isCurrency isCurrency
@ -188,6 +189,7 @@ export class GfAssetProfileDialogComponent implements OnInit {
} }
); );
protected readonly canDeleteAssetProfile = canDeleteAssetProfile;
protected canEditAssetProfile = true; protected canEditAssetProfile = true;
protected countries: { protected countries: {

2
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -70,7 +70,7 @@
mat-menu-item mat-menu-item
type="button" type="button"
[disabled]=" [disabled]="
!adminMarketDataService.hasPermissionToDeleteAssetProfile({ !canDeleteAssetProfile({
activitiesCount: assetProfile?.activitiesCount, activitiesCount: assetProfile?.activitiesCount,
isBenchmark: isBenchmark, isBenchmark: isBenchmark,
symbol: data.symbol, symbol: data.symbol,

30
libs/common/src/lib/helper.ts

@ -30,10 +30,17 @@ import { get, isNil, isString } from 'lodash';
import { import {
DEFAULT_CURRENCY, DEFAULT_CURRENCY,
DERIVED_CURRENCIES, DERIVED_CURRENCIES,
ghostfolioFearAndGreedIndexSymbol,
ghostfolioFearAndGreedIndexSymbolCryptocurrencies,
ghostfolioFearAndGreedIndexSymbolStocks,
ghostfolioScraperApiSymbolPrefix, ghostfolioScraperApiSymbolPrefix,
locale locale
} from './config'; } from './config';
import { AssetProfileIdentifier, Benchmark } from './interfaces'; import {
AdminMarketDataItem,
AssetProfileIdentifier,
Benchmark
} from './interfaces';
import { BenchmarkTrend, ColorScheme } from './types'; import { BenchmarkTrend, ColorScheme } from './types';
export const DATE_FORMAT = 'yyyy-MM-dd'; export const DATE_FORMAT = 'yyyy-MM-dd';
@ -93,6 +100,27 @@ export function calculateMovingAverage({
.toNumber(); .toNumber();
} }
export function canDeleteAssetProfile({
activitiesCount,
isBenchmark,
symbol,
watchedByCount
}: Pick<
AdminMarketDataItem,
'activitiesCount' | 'isBenchmark' | 'symbol' | 'watchedByCount'
>): boolean {
return (
activitiesCount === 0 &&
!isBenchmark &&
!isDerivedCurrency(getCurrencyFromSymbol(symbol)) &&
!isRootCurrency(getCurrencyFromSymbol(symbol)) &&
symbol !== ghostfolioFearAndGreedIndexSymbol &&
symbol !== ghostfolioFearAndGreedIndexSymbolCryptocurrencies &&
symbol !== ghostfolioFearAndGreedIndexSymbolStocks &&
watchedByCount === 0
);
}
export function capitalize(aString: string) { export function capitalize(aString: string) {
return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase(); return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase();
} }

Loading…
Cancel
Save