Feature/improve validation of currency management in admin control panel (#4334)

* Improve validation of currency management

* Update changelog
pull/4342/head
Thomas Kaul 3 days ago committed by GitHub
parent da79cf406f
commit b2698fccbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Reloaded the available tags after creating a custom tag in the holding detail dialog (experimental)
- Improved the validation of the currency management in the admin control panel
- Migrated the `@ghostfolio/client` components to control flow
- Migrated the `@ghostfolio/ui` components to control flow

@ -1,6 +1,7 @@
import { AdminService } from '@ghostfolio/api/app/admin/admin.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { getCurrencyFromSymbol, isCurrency } from '@ghostfolio/common/helper';
import { MarketDataDetailsResponse } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { RequestWithUser } from '@ghostfolio/common/types';
@ -42,7 +43,7 @@ export class MarketDataController {
{ dataSource, symbol }
]);
if (!assetProfile) {
if (!assetProfile && !isCurrency(getCurrencyFromSymbol(symbol))) {
throw new HttpException(
getReasonPhrase(StatusCodes.NOT_FOUND),
StatusCodes.NOT_FOUND
@ -55,7 +56,7 @@ export class MarketDataController {
);
const canReadOwnAssetProfile =
assetProfile.userId === this.request.user.id &&
assetProfile?.userId === this.request.user.id &&
hasPermission(
this.request.user.permissions,
permissions.readMarketDataOfOwnAssetProfile

@ -15,9 +15,11 @@ import {
FormControl,
FormGroup,
ValidationErrors,
ValidatorFn,
Validators
} from '@angular/forms';
import { MatDialogRef } from '@angular/material/dialog';
import { isISO4217CurrencyCode } from 'class-validator';
import { uniq } from 'lodash';
import { Subject, takeUntil } from 'rxjs';
@ -52,9 +54,7 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy {
this.createAssetProfileForm = this.formBuilder.group(
{
addCurrency: new FormControl(null, [
Validators.maxLength(3),
Validators.minLength(3),
Validators.required
this.iso4217CurrencyCodeValidator()
]),
addSymbol: new FormControl(null, [Validators.required]),
searchSymbol: new FormControl(null, [Validators.required])
@ -83,11 +83,11 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy {
symbol: this.createAssetProfileForm.get('searchSymbol').value.symbol
});
} else if (this.mode === 'currency') {
const currency = this.createAssetProfileForm
.get('addCurrency')
.value.toUpperCase();
const currency = (
this.createAssetProfileForm.get('addCurrency').value as string
).toUpperCase();
const currencies = uniq([...this.customCurrencies, currency]);
const currencies = uniq([...this.customCurrencies, currency]).sort();
this.dataService
.putAdminSetting(PROPERTY_CURRENCIES, {
@ -109,10 +109,7 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy {
const addCurrencyFormControl =
this.createAssetProfileForm.get('addCurrency');
if (
addCurrencyFormControl.hasError('maxlength') ||
addCurrencyFormControl.hasError('minlength')
) {
if (addCurrencyFormControl.hasError('invalidCurrency')) {
return true;
}
@ -161,4 +158,14 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy {
this.changeDetectorRef.markForCheck();
});
}
private iso4217CurrencyCodeValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!isISO4217CurrencyCode(control.value?.toUpperCase())) {
return { invalidCurrency: true };
}
return null;
};
}
}

@ -28,7 +28,6 @@ import {
formatDistanceToNowStrict,
parseISO
} from 'date-fns';
import { uniq } from 'lodash';
import { StringValue } from 'ms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@ -122,24 +121,6 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
this.putAdminSetting({ key: PROPERTY_COUPONS, value: coupons });
}
public onAddCurrency() {
const currency = prompt($localize`Please add a currency:`);
if (currency) {
if (currency.length === 3) {
const currencies = uniq([
...this.customCurrencies,
currency.toUpperCase()
]);
this.putAdminSetting({ key: PROPERTY_CURRENCIES, value: currencies });
} else {
this.notificationService.alert({
title: $localize`${currency} is an invalid currency!`
});
}
}
}
public onChangeCouponDuration(aCouponDuration: StringValue) {
this.couponDuration = aCouponDuration;
}

@ -95,16 +95,6 @@
</tr>
}
</table>
<div class="mt-2">
<button
color="primary"
mat-flat-button
(click)="onAddCurrency()"
>
<ion-icon class="mr-1" name="add-outline" />
<span i18n>Add Currency</span>
</button>
</div>
</div>
</div>
<div class="d-flex my-3">

@ -56,6 +56,11 @@
<li>Click on the <i>+</i> button</li>
<li>Switch to <i>Add Currency</i></li>
<li>Insert e.g. <code>EUR</code> for Euro</li>
<li>Select <i>Filter by Currencies</i></li>
<li>Find the entry <i>USDEUR</i></li>
<li>
Click the menu item <i>Gather Historical Data</i> in the dialog
</li>
</ol>
</mat-card-content>
</mat-card>

Loading…
Cancel
Save