From 6e3d5b769ab4044a2885985a278d160a1aa58ab3 Mon Sep 17 00:00:00 2001 From: Tobias Klika Date: Fri, 13 Oct 2023 13:43:40 +0200 Subject: [PATCH] validation updates --- zero/Validation/ValidatorExtensions.cs | 82 ++----------------- .../Validation/Validators/CultureValidator.cs | 29 +++++++ zero/Validation/Validators/EmailValidator.cs | 34 ++++++++ zero/Validation/Validators/EmailsValidator.cs | 35 ++++++++ zero/Validation/Validators/HexValidator.cs | 12 +++ zero/Validation/Validators/RegexValidator.cs | 34 ++++++++ zero/Validation/Validators/UrlValidator.cs | 15 ++++ 7 files changed, 165 insertions(+), 76 deletions(-) create mode 100644 zero/Validation/Validators/CultureValidator.cs create mode 100644 zero/Validation/Validators/EmailValidator.cs create mode 100644 zero/Validation/Validators/EmailsValidator.cs create mode 100644 zero/Validation/Validators/HexValidator.cs create mode 100644 zero/Validation/Validators/RegexValidator.cs create mode 100644 zero/Validation/Validators/UrlValidator.cs diff --git a/zero/Validation/ValidatorExtensions.cs b/zero/Validation/ValidatorExtensions.cs index 187b18f6..99b23e69 100644 --- a/zero/Validation/ValidatorExtensions.cs +++ b/zero/Validation/ValidatorExtensions.cs @@ -1,117 +1,47 @@ using FluentValidation; -using System.Globalization; -using System.Net.Mail; +using zero.Validation.Validators; namespace zero.Validation; public static class ValidatorExtensions { - private const char DOT = '.'; - - private const char KLAMMERAFFE = '@'; - - private static string HEX_REGEX = "(^$)|(#[0-9a-fA-F]{3,8})"; - /// /// Validate a color input as HEX (#aabbccdd or #aabbcc or #abc) /// public static IRuleBuilderOptions Hex(this IRuleBuilder ruleBuilder) { - return ruleBuilder.Matches(HEX_REGEX).WithMessage("@errors.forms.hex_format"); + return ruleBuilder.SetValidator(new HexValidator()); } - /// /// Validate an email /// public static IRuleBuilderOptions Url(this IRuleBuilder ruleBuilder) { - return ruleBuilder.Must((root, value, context) => - { - return value.IsNullOrWhiteSpace() || Uri.IsWellFormedUriString(value, UriKind.Absolute); - }).WithMessage("@errors.forms.url_format"); + return ruleBuilder.SetValidator(new UrlValidator()); } - /// /// Validate an email /// public static IRuleBuilderOptions Email(this IRuleBuilder ruleBuilder) { - return ruleBuilder.Must((root, value, context) => ValidateEmail(value)).WithMessage("@errors.forms.email_invalid"); + return ruleBuilder.SetValidator(new EmailValidator()); } - /// /// Validate one or multiple emails /// public static IRuleBuilderOptions Emails(this IRuleBuilder ruleBuilder) { - return ruleBuilder.Must((root, value, context) => - { - if (value.IsNullOrWhiteSpace()) - { - return true; - } - - string[] mails = value.Split(',', ';').Select(x => x.Trim()).Where(x => !x.IsNullOrWhiteSpace()).ToArray(); - - if (!mails.Any()) - { - return false; - } - - foreach (string mail in mails) - { - if (!ValidateEmail(mail)) - { - return false; - } - } - - return true; - }).WithMessage("@errors.forms.emails_invalid"); + return ruleBuilder.SetValidator(new EmailsValidator()); } - - private static bool ValidateEmail(string value) - { - if (value == null) - { - return false; - } - - int index = value.IndexOf(KLAMMERAFFE); - - return - index > 0 && - index != value.Length - 1 && - index == value.LastIndexOf(KLAMMERAFFE) && - MailAddress.TryCreate(value, out _); - } - - /// /// Validates a culture identifier /// public static IRuleBuilderOptions Culture(this IRuleBuilder ruleBuilder) { - return ruleBuilder.Must((root, value, context) => - { - if (value.IsNullOrWhiteSpace()) - { - return true; - } - - try - { - CultureInfo info = CultureInfo.GetCultureInfo(value); - return info != null && !info.EnglishName.Equals(value, StringComparison.InvariantCultureIgnoreCase); - } - catch - { - return false; - } - }).WithMessage("@errors.forms.culture"); + return ruleBuilder.SetValidator(new CultureValidator()); } } diff --git a/zero/Validation/Validators/CultureValidator.cs b/zero/Validation/Validators/CultureValidator.cs new file mode 100644 index 00000000..bf51e577 --- /dev/null +++ b/zero/Validation/Validators/CultureValidator.cs @@ -0,0 +1,29 @@ +using FluentValidation.Validators; +using System.Globalization; + +namespace zero.Validation.Validators; + +public class CultureValidator : PropertyValidator +{ + public override string Name => "CultureValidator"; + + protected override string GetDefaultMessageTemplate(string errorCode) => Localized(errorCode, Name); + + public override bool IsValid(FluentValidation.ValidationContext context, string value) + { + if (value.IsNullOrWhiteSpace()) + { + return true; + } + + try + { + CultureInfo info = CultureInfo.GetCultureInfo(value); + return info != null && !info.EnglishName.Equals(value, StringComparison.InvariantCultureIgnoreCase); + } + catch + { + return false; + } + } +} \ No newline at end of file diff --git a/zero/Validation/Validators/EmailValidator.cs b/zero/Validation/Validators/EmailValidator.cs new file mode 100644 index 00000000..17627cd7 --- /dev/null +++ b/zero/Validation/Validators/EmailValidator.cs @@ -0,0 +1,34 @@ +using FluentValidation.Validators; +using System.Net.Mail; + +namespace zero.Validation.Validators; + +public class EmailValidator : PropertyValidator, IEmailValidator +{ + public override string Name => "EmailValidator"; + + private const char KLAMMERAFFE = '@'; + + protected override string GetDefaultMessageTemplate(string errorCode) => Localized(errorCode, Name); + + public override bool IsValid(FluentValidation.ValidationContext context, string value) + { + return ValidateEmail(value); + } + + public static bool ValidateEmail(string value) + { + if (value == null) + { + return false; + } + + int index = value.IndexOf(KLAMMERAFFE); + + return + index > 0 && + index != value.Length - 1 && + index == value.LastIndexOf(KLAMMERAFFE) && + MailAddress.TryCreate(value, out _); + } +} \ No newline at end of file diff --git a/zero/Validation/Validators/EmailsValidator.cs b/zero/Validation/Validators/EmailsValidator.cs new file mode 100644 index 00000000..67f57d13 --- /dev/null +++ b/zero/Validation/Validators/EmailsValidator.cs @@ -0,0 +1,35 @@ +using FluentValidation.Validators; + +namespace zero.Validation.Validators; + +public class EmailsValidator : PropertyValidator, IEmailValidator +{ + public override string Name => "EmailValidator"; + + protected override string GetDefaultMessageTemplate(string errorCode) => Localized(errorCode, Name); + + public override bool IsValid(FluentValidation.ValidationContext context, string value) + { + if (value.IsNullOrWhiteSpace()) + { + return true; + } + + string[] mails = value.Split(',', ';').Select(x => x.Trim()).Where(x => !x.IsNullOrWhiteSpace()).ToArray(); + + if (!mails.Any()) + { + return false; + } + + foreach (string mail in mails) + { + if (!EmailValidator.ValidateEmail(mail)) + { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/zero/Validation/Validators/HexValidator.cs b/zero/Validation/Validators/HexValidator.cs new file mode 100644 index 00000000..f6b990af --- /dev/null +++ b/zero/Validation/Validators/HexValidator.cs @@ -0,0 +1,12 @@ +using System.Text.RegularExpressions; + +namespace zero.Validation.Validators; + +public class HexValidator : RegexValidator +{ + public override string Name => "HexValidator"; + + static Regex Regex = CreateRegex("(^$)|(#[0-9a-fA-F]{3,8})"); + + public HexValidator() : base(Regex) { } +} \ No newline at end of file diff --git a/zero/Validation/Validators/RegexValidator.cs b/zero/Validation/Validators/RegexValidator.cs new file mode 100644 index 00000000..ee7b3032 --- /dev/null +++ b/zero/Validation/Validators/RegexValidator.cs @@ -0,0 +1,34 @@ +using FluentValidation.Validators; +using System.Text.RegularExpressions; + +namespace zero.Validation.Validators; + +public abstract class RegexValidator : PropertyValidator +{ + private readonly Regex _regex = null; + + public RegexValidator(Regex regex) + { + _regex = regex; + } + + protected static Regex CreateRegex(string expression) + { + const RegexOptions options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture; + return new Regex(expression, options, TimeSpan.FromSeconds(2.0)); + } + + protected override string GetDefaultMessageTemplate(string errorCode) => Localized(errorCode, Name); + + public override bool IsValid(FluentValidation.ValidationContext context, string value) + { + if (value == null) return true; + + if (!_regex.IsMatch(value)) + { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/zero/Validation/Validators/UrlValidator.cs b/zero/Validation/Validators/UrlValidator.cs new file mode 100644 index 00000000..1a636ef7 --- /dev/null +++ b/zero/Validation/Validators/UrlValidator.cs @@ -0,0 +1,15 @@ +using FluentValidation.Validators; + +namespace zero.Validation.Validators; + +public class UrlValidator : PropertyValidator +{ + public override string Name => "UrlValidator"; + + protected override string GetDefaultMessageTemplate(string errorCode) => Localized(errorCode, Name); + + public override bool IsValid(FluentValidation.ValidationContext context, string value) + { + return value.IsNullOrWhiteSpace() || Uri.IsWellFormedUriString(value, UriKind.Absolute); + } +} \ No newline at end of file