/* * Copyright (c) 2022 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Extensions.Validation * File: ValidatorExtensions.cs * * ValidatorExtensions.cs is part of VNLib.Plugins.Extensions.Validation which is part of the larger * VNLib collection of libraries and utilities. * * VNLib.Plugins.Extensions.Validation is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 2 of the License, * or (at your option) any later version. * * VNLib.Plugins.Extensions.Validation is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VNLib.Plugins.Extensions.Validation. If not, see http://www.gnu.org/licenses/. */ using System; using System.Collections; using System.Text.RegularExpressions; using FluentValidation; using FluentValidation.Results; namespace VNLib.Plugins.Extensions.Validation { /// /// Defines extenstion methods for /// public static class ValidatorExtensions { public static readonly Regex PhoneRegex = new(@"^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$", RegexOptions.Compiled); public static readonly Regex AlphaRegx = new(@"[a-zA-Z]*", RegexOptions.Compiled); public static readonly Regex NumericRegx = new(@"[0-9]*", RegexOptions.Compiled); public static readonly Regex AlphaNumRegx = new(@"[a-zA-Z0-9]*", RegexOptions.Compiled); public static readonly Regex OnlyAlphaRegx = new(@"^[a-zA-Z\s]*$", RegexOptions.Compiled); public static readonly Regex OnlyNumericRegx = new(@"^[0-9]*$", RegexOptions.Compiled); public static readonly Regex OnlyAlphaNumRegx = new(@"^[a-zA-Z0-9\s]*$", RegexOptions.Compiled); public static readonly Regex PasswordRegx = new(@"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-])", RegexOptions.Compiled); public static readonly Regex IllegalRegx = new(@"[\r\n\t\a\b\e\f|^~`<>{}]", RegexOptions.Compiled); public static readonly Regex SpecialCharactersRegx = new(@"[\r\n\t\a\b\e\f#?!@$%^&*\+\-\~`|<>\{}]", RegexOptions.Compiled); /// /// Gets a collection of Json-serializable validation errors /// /// /// A collection of json errors to return to a user public static ICollection GetErrorsAsCollection(this ValidationResult result) { return result.Errors.ConvertAll(static err => new ValidationErrorMessage { ErrorMessage = err.ErrorMessage, PropertyName = err.PropertyName }); } /// /// Tests the the property against /// to determine if the string matches the proper phone number form /// /// /// /// public static IRuleBuilderOptions PhoneNumber(this IRuleBuilder builder) { return builder.Must(static phone => phone?.Length > 0 && PhoneRegex.IsMatch(phone)) .WithMessage("{PropertyValue} is not a valid phone number."); } /// /// Tests the the property against /// to determine if the string matches the proper phone number form, or allows emtpy strings /// /// /// /// public static IRuleBuilderOptions EmptyPhoneNumber(this IRuleBuilder builder) { return builder.Must(static phone => !(phone?.Length).HasValue || PhoneRegex.IsMatch(phone)) .WithMessage("{PropertyValue} is not a valid phone number."); } /// /// Checks a string against . /// If the string is null or empty, it is allowed. /// /// /// /// public static IRuleBuilderOptions SpecialCharacters(this IRuleBuilder builder) { return builder.Must(static str => str == null || !SpecialCharactersRegx.IsMatch(str)) .WithMessage("{PropertyName} contains illegal characters"); } /// /// Checks a string against . /// If the string is null or empty, it is allowed. /// /// /// /// public static IRuleBuilderOptions IllegalCharacters(this IRuleBuilder builder) { return builder.Must(static str => str == null || !IllegalRegx.IsMatch(str)) .WithMessage("{PropertyName} contains illegal characters"); } /// /// Makes sure a field contains at least 1 character a-Z /// /// /// /// public static IRuleBuilderOptions Alpha(this IRuleBuilder builder) { return builder.Must(static str => str == null || AlphaRegx.IsMatch(str)) .WithMessage("{PropertyName} requires at least one a-Z character."); } /// /// Determines if all characters are only a-Z (allows whitespace) /// /// /// /// public static IRuleBuilderOptions AlphaOnly(this IRuleBuilder builder) { return builder.Must(static str => str == null || OnlyAlphaRegx.IsMatch(str)) .WithMessage("{PropertyName} can only be a alpha character from a-Z."); } /// /// Makes sure a field contains at least 1 numeral /// /// /// /// public static IRuleBuilderOptions Numeric(this IRuleBuilder builder) { return builder.Must(static str => str == null || NumericRegx.IsMatch(str)) .WithMessage("{PropertyName} requires at least one number."); } /// /// Determines if all characters are only 0-9 (not whitespace is allowed) /// /// /// /// public static IRuleBuilderOptions NumericOnly(this IRuleBuilder builder) { return builder.Must(static str => str == null || OnlyNumericRegx.IsMatch(str)) .WithMessage("{PropertyName} can only be a number 0-9."); } /// /// Makes sure the field contains at least 1 alpha numeric character (whitespace included) /// /// /// /// public static IRuleBuilderOptions AlphaNumeric(this IRuleBuilder builder) { return builder.Must(static str => str == null || AlphaNumRegx.IsMatch(str)) .WithMessage("{PropertyName} must contain at least one alpha-numeric character."); } /// /// Determines if all characters are only alpha-numeric (whitespace allowed) /// /// /// /// public static IRuleBuilderOptions AlphaNumericOnly(this IRuleBuilder builder) { return builder.Must(static str => str == null || OnlyAlphaNumRegx.IsMatch(str)) .WithMessage("{PropertyName} can only contain alpha numeric characters."); } /// /// Tests the string against the password regular expression to determine if the /// value meets the basic password requirements /// /// /// /// public static IRuleBuilderOptions Password(this IRuleBuilder builder) { return builder.Must(static str => str == null || PasswordRegx.IsMatch(str)) .WithMessage("{PropertyName} does not meet password requirements."); } /// /// Defines a length validator on the current rule builder, but only for string properties. /// Validation will fail if the length of the string is outside of the specified range. /// The range is inclusive /// /// /// /// The length range of the specified string /// public static IRuleBuilderOptions Length(this IRuleBuilder builder, Range lengthRange) { return builder.Length(lengthRange.Start.Value, lengthRange.End.Value); } } }