Refactoring Validation methods.
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
@@ -329,7 +329,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
Global.ChaumianClient.DeactivateFrequentStatusProcessingIfNotMixing();
}
- public string ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
[ValidateMethod(nameof(ValidatePassword))]
public string Password

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -966,7 +966,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _allSelectedAmount, value);
}
- public string ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
[ValidateMethod(nameof(ValidatePassword))]
public string Password
@@ -1035,24 +1035,24 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
Suggestions.Clear();
}
- public string ValidateAddress()
+ public ErrorDescriptors ValidateAddress()
{
if (string.IsNullOrWhiteSpace(Address))
{
- return "";
+ return ErrorDescriptors.Empty;
}
if (AddressStringParser.TryParseBitcoinAddress(Address, Global.Network, out _))
{
- return "";
+ return ErrorDescriptors.Empty;
}
if (AddressStringParser.TryParseBitcoinUrl(Address, Global.Network, out _))
{
- return "";
+ return ErrorDescriptors.Empty;
}
- return "Invalid address.";
+ return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Warning, "Invalid address."));
}
[ValidateMethod(nameof(ValidateAddress))]

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/WalletInfoViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/WalletInfoViewModel.cs
@@ -90,7 +90,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _showSensitiveKeys, value);
}
- public string ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
[ValidateMethod(nameof(ValidatePassword))]
public string Password

MODIFY
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
WalletWasabi.Gui/Tabs/SettingsViewModel.cs
@@ -287,12 +287,12 @@ namespace WalletWasabi.Gui.Tabs
}
var isValid =
- string.IsNullOrEmpty(ValidatePrivacyLevel(SomePrivacyLevel, whiteSpaceOk: false))
- && string.IsNullOrEmpty(ValidatePrivacyLevel(FinePrivacyLevel, whiteSpaceOk: false))
- && string.IsNullOrEmpty(ValidatePrivacyLevel(StrongPrivacyLevel, whiteSpaceOk: false))
- && string.IsNullOrEmpty(ValidateDustThreshold(DustThreshold, whiteSpaceOk: false))
- && string.IsNullOrEmpty(ValidateEndPoint(TorSocks5EndPoint, Constants.DefaultTorSocksPort, whiteSpaceOk: false))
- && string.IsNullOrEmpty(ValidateEndPoint(BitcoinP2pEndPoint, network.DefaultPort, whiteSpaceOk: false));
+ ValidatePrivacyLevel(SomePrivacyLevel, whiteSpaceOk: false).HasErrors
+ && ValidatePrivacyLevel(FinePrivacyLevel, whiteSpaceOk: false).HasErrors
+ && ValidatePrivacyLevel(StrongPrivacyLevel, whiteSpaceOk: false).HasErrors
+ && ValidateDustThreshold(DustThreshold, whiteSpaceOk: false).HasErrors
+ && ValidateEndPoint(TorSocks5EndPoint, Constants.DefaultTorSocksPort, whiteSpaceOk: false).HasErrors
+ && ValidateEndPoint(BitcoinP2pEndPoint, network.DefaultPort, whiteSpaceOk: false).HasErrors;
if (!isValid)
{
@@ -340,67 +340,67 @@ namespace WalletWasabi.Gui.Tabs
#region Validation
- public string ValidateSomePrivacyLevel()
+ public ErrorDescriptors ValidateSomePrivacyLevel()
=> ValidatePrivacyLevel(SomePrivacyLevel, whiteSpaceOk: true);
- public string ValidateFinePrivacyLevel()
+ public ErrorDescriptors ValidateFinePrivacyLevel()
=> ValidatePrivacyLevel(FinePrivacyLevel, whiteSpaceOk: true);
- public string ValidateStrongPrivacyLevel()
+ public ErrorDescriptors ValidateStrongPrivacyLevel()
=> ValidatePrivacyLevel(StrongPrivacyLevel, whiteSpaceOk: true);
- public string ValidateDustThreshold()
+ public ErrorDescriptors ValidateDustThreshold()
=> ValidateDustThreshold(DustThreshold, whiteSpaceOk: true);
- public string ValidateTorSocks5EndPoint()
+ public ErrorDescriptors ValidateTorSocks5EndPoint()
=> ValidateEndPoint(TorSocks5EndPoint, Constants.DefaultTorSocksPort, whiteSpaceOk: true);
- public string ValidateBitcoinP2pEndPoint()
+ public ErrorDescriptors ValidateBitcoinP2pEndPoint()
=> ValidateEndPoint(BitcoinP2pEndPoint, Network.DefaultPort, whiteSpaceOk: true);
- public string ValidatePrivacyLevel(string value, bool whiteSpaceOk)
+ public ErrorDescriptors ValidatePrivacyLevel(string value, bool whiteSpaceOk)
{
if (whiteSpaceOk && string.IsNullOrWhiteSpace(value))
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
if (uint.TryParse(value, out _))
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
- return "Invalid privacy level.";
+ return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Warning, "Invalid privacy level."));
}
- public string ValidateDustThreshold(string dustThreshold, bool whiteSpaceOk)
+ public ErrorDescriptors ValidateDustThreshold(string dustThreshold, bool whiteSpaceOk)
{
if (whiteSpaceOk && string.IsNullOrWhiteSpace(dustThreshold))
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
if (decimal.TryParse(dustThreshold, out var dust) && dust >= 0)
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
- return "Invalid dust threshold.";
+ return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Warning, "Invalid dust threshold."));
}
- public string ValidateEndPoint(string endPoint, int defaultPort, bool whiteSpaceOk)
+ public ErrorDescriptors ValidateEndPoint(string endPoint, int defaultPort, bool whiteSpaceOk)
{
if (whiteSpaceOk && string.IsNullOrWhiteSpace(endPoint))
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
if (EndPointParser.TryParse(endPoint, defaultPort, out _))
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
- return "Invalid endpoint.";
+ return new ErrorDescriptors(new ErrorDescriptor(ErrorSeverity.Warning, "Invalid endpoint."));
}
#endregion Validation

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/GenerateWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/GenerateWalletViewModel.cs
@@ -31,7 +31,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
IObservable<bool> canGenerate = Observable.CombineLatest(
this.WhenAnyValue(x => x.TermsAccepted),
- this.WhenAnyValue(x => x.Password).Select(pw => string.IsNullOrEmpty(ValidatePassword())),
+ this.WhenAnyValue(x => x.Password).Select(pw => !ValidatePassword().HasErrors),
(terms, pw) => terms && pw);
GenerateCommand = ReactiveCommand.Create(DoGenerateCommand, canGenerate);
@@ -94,21 +94,25 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
return isValid && !isReserved;
}
- public string ValidatePassword()
+ public ErrorDescriptors ValidatePassword()
{
string password = Password;
+
List<string> messages = new List<string>();
+
+ var errors = new ErrorDescriptors();
+
if (PasswordHelper.IsTrimable(password, out _))
{
- messages.Add("Leading and trailing white spaces are not allowed!");
+ errors.Add(new ErrorDescriptor(ErrorSeverity.Warning, "Leading and trailing white spaces are not allowed!"));
}
if (PasswordHelper.IsTooLong(password, out _))
{
- messages.Add(PasswordHelper.PasswordTooLongMessage);
+ errors.Add(new ErrorDescriptor(ErrorSeverity.Warning, PasswordHelper.PasswordTooLongMessage));
}
- return string.Join(' ', messages);
+ return errors;
}
[ValidateMethod(nameof(ValidatePassword))]

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/LoadWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/LoadWalletViewModel.cs
@@ -169,7 +169,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
set => this.RaiseAndSetIfChanged(ref _wallets, value);
}
- public string ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
[ValidateMethod(nameof(ValidatePassword))]
public string Password

MODIFY
WalletWasabi.Gui/Tabs/WalletManager/RecoverWalletViewModel.cs
WalletWasabi.Gui/Tabs/WalletManager/RecoverWalletViewModel.cs
@@ -92,7 +92,7 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
_suggestions = new ObservableCollection<SuggestionViewModel>();
}
- public string ValidatePassword() => PasswordHelper.ValidatePassword(Password);
+ public ErrorDescriptors ValidatePassword() => PasswordHelper.ValidatePassword(Password);
[ValidateMethod(nameof(ValidatePassword))]
public string Password
@@ -101,6 +101,11 @@ namespace WalletWasabi.Gui.Tabs.WalletManager
set => this.RaiseAndSetIfChanged(ref _password, value);
}
+ private void ValidatePasswordN(ErrorDescriptor obj)
+ {
+ throw new NotImplementedException();
+ }
+
public string MnemonicWords
{
get => _mnemonicWords;

MODIFY
WalletWasabi.Gui/ViewModels/Validation/Validator.cs
WalletWasabi.Gui/ViewModels/Validation/Validator.cs
using System.Collections.Generic;
using System.Reflection;
using System.Text;
+using WalletWasabi.Helpers;
namespace WalletWasabi.Gui.ViewModels.Validation
{
public static class Validator
{
- public static List<string> ValidateAllProperties(object instance)
+ public static ErrorDescriptors ValidateAllProperties(object instance)
{
- var result = new List<string>();
+ var result = new ErrorDescriptors();
+
foreach (PropertyInfo property in ReflectionHelper.GetPropertyInfos(instance))
{
- var errorString = ValidateMethod(instance, property);
- if (!string.IsNullOrEmpty(errorString))
+ var error = ValidateMethod(instance, property);
+
+ if (error.Equals(ErrorDescriptor.Default))
{
- result.Add(errorString);
+ result.AddRange(error);
}
}
return result;
}
- public static string ValidateProperty(object instance, string propertyName)
+ public static ErrorDescriptors ValidateProperty(object instance, string propertyName)
{
var property = ReflectionHelper.GetPropertyInfo(instance, propertyName);
@@ -30,20 +33,20 @@ namespace WalletWasabi.Gui.ViewModels.Validation
return ValidateMethod(instance, property);
}
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
- private static string ValidateMethod(object instance, PropertyInfo property)
+ private static ErrorDescriptors ValidateMethod(object instance, PropertyInfo property)
{
var vma = ReflectionHelper.GetAttribute<ValidateMethodAttribute>(property);
if (vma != null)
{
- return ReflectionHelper.InvokeMethod<string>(instance, vma.MethodName);
+ return ReflectionHelper.InvokeMethod<ErrorDescriptors>(instance, vma.MethodName);
}
else
{
- return string.Empty;
+ return ErrorDescriptors.Empty;
}
}
}

MODIFY
WalletWasabi.Gui/ViewModels/ViewModelBase.cs
WalletWasabi.Gui/ViewModels/ViewModelBase.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using WalletWasabi.Gui.ViewModels.Validation;
+using WalletWasabi.Helpers;
namespace WalletWasabi.Gui.ViewModels
{
@@ -12,17 +13,18 @@ namespace WalletWasabi.Gui.ViewModels
{
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
- public bool HasErrors => Validator.ValidateAllProperties(this).Any();
+ public bool HasErrors => Validator.ValidateAllProperties(this).HasErrors;
public IEnumerable GetErrors(string propertyName)
{
- var errorString = Validator.ValidateProperty(this, propertyName);
- if (!string.IsNullOrEmpty(errorString))
+ var error = Validator.ValidateProperty(this, propertyName);
+
+ if (error.HasErrors)
{
- return new List<string> { errorString };
+ return error;
}
- return null;
+ return ErrorDescriptors.Empty;
}
protected void NotifyErrorsChanged(string propertyName)

MODIFY
WalletWasabi/Helpers/ErrorDescriptor.cs
WalletWasabi/Helpers/ErrorDescriptor.cs
@@ -5,7 +5,19 @@ namespace WalletWasabi.Helpers
{
public class ErrorDescriptors : List<ErrorDescriptor>
{
- public bool HasErrors => this.Count == 0;
+ public bool HasErrors => this.Count > 0;
+
+ public static ErrorDescriptors Empty = new ErrorDescriptors();
+
+ public ErrorDescriptors() : base()
+ {
+
+ }
+
+ public ErrorDescriptors(params ErrorDescriptor[] errors)
+ {
+ this.AddRange(errors);
+ }
}
public enum ErrorSeverity

MODIFY
WalletWasabi/Helpers/PasswordHelper.cs
WalletWasabi/Helpers/PasswordHelper.cs
@@ -143,20 +143,21 @@ namespace WalletWasabi.Helpers
throw resultException; // Throw the last exception - Invalid password.
}
- public static string ValidatePassword(string password)
+ public static ErrorDescriptors ValidatePassword(string password)
{
- List<string> messages = new List<string>();
+ var errors = new ErrorDescriptors();
+
if (IsTrimable(password, out _))
{
- messages.Add(TrimWarnMessage);
+ errors.Add(new ErrorDescriptor(ErrorSeverity.Warning, TrimWarnMessage));
}
if (IsTooLong(password, out _))
{
- messages.Add(PasswordTooLongMessage);
+ errors.Add(new ErrorDescriptor(ErrorSeverity.Warning, PasswordTooLongMessage));
}
- return string.Join(' ', messages);
+ return errors;
}
}
}

Refactoring Validation methods.