diff --git a/src/Utils/Data/Masa.Utils.Data.Prometheus/Extensions/ObjectExtensions.cs b/src/Utils/Data/Masa.Utils.Data.Prometheus/Extensions/ObjectExtensions.cs index 040a87648..e9253e860 100644 --- a/src/Utils/Data/Masa.Utils.Data.Prometheus/Extensions/ObjectExtensions.cs +++ b/src/Utils/Data/Masa.Utils.Data.Prometheus/Extensions/ObjectExtensions.cs @@ -47,7 +47,7 @@ public static class ObjectExtensions } //struct - return GetObjValue(type, obj, preStr, isEnumString, isCamelCase, isUrlEncode); + return GetObjValue(type, obj, preStr, isEnumString, isCamelCase, isUrlEncode); } if (type.IsArray || type.GetInterfaces().Any(t => t.Name.IndexOf("IEnumerable") == 0)) @@ -68,7 +68,7 @@ private static string GetObjValue(Type type, object obj, string preStr, bool isE foreach (var item in properties) { - var str = GetMemerInfoValue(item, item.GetValue(obj), preStr, isEnumString, isCamelCase, isUrlEncode); + var str = GetMemberInfoValue(item, item.GetValue(obj), preStr, isEnumString, isCamelCase, isUrlEncode); if (string.IsNullOrEmpty(str)) continue; list.Add(str); @@ -76,7 +76,7 @@ private static string GetObjValue(Type type, object obj, string preStr, bool isE foreach (var item in fields) { - var str = GetMemerInfoValue(item, item.GetValue(obj), preStr, isEnumString, isCamelCase, isUrlEncode); + var str = GetMemberInfoValue(item, item.GetValue(obj), preStr, isEnumString, isCamelCase, isUrlEncode); if (string.IsNullOrEmpty(str)) continue; list.Add(str); @@ -89,7 +89,7 @@ private static string GetObjValue(Type type, object obj, string preStr, bool isE return string.Join('&', list); } - private static string? GetMemerInfoValue(MemberInfo info, object? value, string preStr, bool isEnumString = false, bool isCamelCase = true, bool isUrlEncode = true) + private static string? GetMemberInfoValue(MemberInfo info, object? value, string preStr, bool isEnumString = false, bool isCamelCase = true, bool isUrlEncode = true) { if (value == null) return null; diff --git a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/CollectionExtensions.cs b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/CollectionExtensions.cs new file mode 100644 index 000000000..c13832a63 --- /dev/null +++ b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/CollectionExtensions.cs @@ -0,0 +1,54 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace System.Collections; + +public static class CollectionExtensions +{ + public static bool IsNullOrEmpty(this ICollection source) + { + return source == null || !source.Any(); + } + + public static bool AddIfNotContains(this ICollection source, T item) + { + if (source.Contains(item)) + { + return false; + } + + source.Add(item); + return true; + } + + public static void AddIfNotContains(this ICollection source, IEnumerable items) + { + foreach (var item in items) + { + if (source.Contains(item)) + { + continue; + } + source.Add(item); + } + } + + public static int RemoveAll(this ICollection source, Func predicate) + { + var items = source.Where(predicate).ToList(); + foreach (var item in items) + { + source.Remove(item); + } + + return items.Count; + } + + public static void RemoveAll(this ICollection source, IEnumerable items) + { + foreach (var item in items) + { + source.Remove(item); + } + } +} diff --git a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/FillType.cs b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/FillType.cs index 6b00b92d6..9f1903175 100644 --- a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/FillType.cs +++ b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/FillType.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace @@ -7,7 +7,7 @@ namespace System; public enum FillType { - NoFile = 1, + NoFill = 1, /// /// left fill diff --git a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/StringExtensions.cs b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/StringExtensions.cs index 731a9143e..102ed6aef 100644 --- a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/StringExtensions.cs +++ b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/StringExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace @@ -49,10 +49,10 @@ public static string GetSpecifiedLengthString( this string value, int length, Action action, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ') { - if (fillType == FillType.NoFile && value.Length < length) + if (fillType == FillType.NoFill && value.Length < length) action.Invoke(); var keyLength = value.Length; @@ -66,4 +66,239 @@ public static string GetSpecifiedLengthString( throw new NotSupportedException($"... Unsupported {nameof(fillType)}"); } + + /// + /// If the given string does not end with char, char is added to the end of the given string. + /// + public static string EnsureEndsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) + { + if (str.EndsWith(c.ToString(), comparisonType)) + { + return str; + } + + return str + c; + } + + /// + /// If the given string does not start with char, char is added to the beginning of the given string. + /// + public static string EnsureStartsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) + { + if (str.StartsWith(c.ToString(), comparisonType)) + { + return str; + } + + return c + str; + } + + /// + /// Converts new line const in the string to . + /// + public static string NormalizeLineBreak(this string str) + { + return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine); + } + + /// + /// Gets a substring of a string from beginning of the string. + /// + /// Thrown if is null + /// Thrown if is bigger that string's length + public static string Left(this string str, int len) + { + if (str.Length < len) + { + throw new ArgumentException("len argument can`t be greater than string's length!"); + } + + return str.Substring(0, len); + } + + /// + /// Gets a substring of a string from end of the string. + /// + /// Thrown if is null + /// Thrown if is bigger that string's length + public static string Right(this string str, int len) + { + if (str.Length < len) + { + throw new ArgumentException("len argument can`t be greater than string's length!"); + } + + return str.Substring(str.Length - len, len); + } + + /// + /// split string by . + /// + public static string[] SplitToLines(this string str) + { + return str.Split(Environment.NewLine); + } + + /// + /// split string by . + /// + public static string[] SplitToLines(this string str, StringSplitOptions options) + { + return str.Split(Environment.NewLine, options); + } + + public static string ToFirstCharUpper(this string str) + { + if (str.IsNullOrWhiteSpace()) + { + return str; + } + return char.ToUpperInvariant(str[0]) + str.Substring(1); + } + + public static string ToFirstCharLower(this string str) + { + if (str.IsNullOrWhiteSpace()) + { + return str; + } + return char.ToLowerInvariant(str[0]) + str.Substring(1); + } + + /// + /// Conversion string to PascalCase. + /// Example: User_Name -> UserName, user_name -> UserName, user_Name -> UserName, User_name -> UserName + /// + /// + /// + public static string ToPascalCase(this string str) + { + if (str.IsNullOrWhiteSpace()) + { + return str; + } + return string.Join("", str.Split(new[] { '-', '_', ' ' }) + .Where(s => !s.IsNullOrWhiteSpace()) + .Select(c => ToFirstCharUpper(c))); + } + + /// + /// Conversion string to CamelCase. + /// Example: User_Name -> userName, user_name -> userName, user_Name -> userName, User_name -> userName + /// + /// + /// + public static string ToCamelCase(this string str) + { + if (str.IsNullOrWhiteSpace()) + { + return str; + } + return string.Join("", str.Split(new[] { '-', '_', ' ' }) + .Where(s => !s.IsNullOrWhiteSpace()) + .Select((c, i) => i == 0 ? ToFirstCharLower(c) : ToFirstCharUpper(c))); + } + + /// + /// Conversion PascalCase/camelCase string to sentence (splitting words by space). + /// Example: "ThisIsSampleSentence" is converted to "This is sample sentence". + /// + /// + public static string ToSentenceCase(this string str) + { + if (str.IsNullOrWhiteSpace()) + { + return str; + } + + return ToFirstCharUpper(ConvertCase(str, ' ')); + } + + /// + /// Conversion PascalCase/camelCase string to kebab-case. + /// Example: "UserName" is converted to "user-name". + /// + /// + /// + public static string ToKebabCase(this string str) + { + if (str.IsNullOrEmpty()) + { + return str; + } + return ConvertCase(str, '-'); + } + + /// + /// conversion PascalCase/camelCase string to snake case. + /// Example: "UserName" is converted to "user_name". + /// + /// + /// + public static string ToSnakeCase(this string str) + { + if (str.IsNullOrWhiteSpace()) + { + return str; + } + + return ConvertCase(str, '_'); + } + +#pragma warning disable S3776 + private static string ConvertCase(string str, char wordDelimiter) + { + var builder = new StringBuilder(str.Length + Math.Min(2, str.Length / 5)); + var previousCategory = default(UnicodeCategory?); + for (var currentIndex = 0; currentIndex < str.Length; currentIndex++) + { + var currentChar = str[currentIndex]; + if (currentChar == wordDelimiter) + { + builder.Append(wordDelimiter); + previousCategory = null; + continue; + } + + var currentCategory = char.GetUnicodeCategory(currentChar); + switch (currentCategory) + { + case UnicodeCategory.UppercaseLetter: + case UnicodeCategory.TitlecaseLetter: + if (previousCategory == UnicodeCategory.SpaceSeparator || + previousCategory == UnicodeCategory.LowercaseLetter || + previousCategory != UnicodeCategory.DecimalDigitNumber && + previousCategory != null && + currentIndex > 0 && + currentIndex + 1 < str.Length && + char.IsLower(str[currentIndex + 1])) + { + builder.Append(wordDelimiter); + } + + currentChar = char.ToLower(currentChar); + break; + + case UnicodeCategory.LowercaseLetter: + case UnicodeCategory.DecimalDigitNumber: + if (previousCategory == UnicodeCategory.SpaceSeparator) + { + builder.Append(wordDelimiter); + } + break; + + default: + if (previousCategory != null) + { + previousCategory = UnicodeCategory.SpaceSeparator; + } + continue; + } + + builder.Append(currentChar); + previousCategory = currentCategory; + } + return builder.ToString(); + } +#pragma warning restore S3776 } diff --git a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/_Imports.cs b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/_Imports.cs index e206af5ad..4dc4d04cc 100644 --- a/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/_Imports.cs +++ b/src/Utils/Extensions/Masa.Utils.Extensions.DotNet/_Imports.cs @@ -8,7 +8,7 @@ global using System.Dynamic; global using System.Globalization; global using System.Reflection; -global using System.Runtime.CompilerServices; +global using System.Security.Cryptography; global using System.Text; global using System.Text.Json.Serialization; global using System.Text.RegularExpressions; diff --git a/src/Utils/Extensions/Tests/Masa.Utils.Extensions.DotNet.Tests/StringTest.cs b/src/Utils/Extensions/Tests/Masa.Utils.Extensions.DotNet.Tests/StringTest.cs index 9a9220ef3..db6bbb552 100644 --- a/src/Utils/Extensions/Tests/Masa.Utils.Extensions.DotNet.Tests/StringTest.cs +++ b/src/Utils/Extensions/Tests/Masa.Utils.Extensions.DotNet.Tests/StringTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. namespace Masa.Utils.Extensions.DotNet.Tests; @@ -21,4 +21,60 @@ public void TestTrimEnd(string value, string trimParameter, string result) { Assert.AreEqual(result, value.TrimEnd(trimParameter, StringComparison.OrdinalIgnoreCase)); } + + [DataTestMethod] + [DataRow("User-Name", "userName")] + [DataRow("User_Name", "userName")] + [DataRow("user Name", "userName")] + [DataRow("_name", "name")] + [DataRow("name_", "name")] + [DataRow("user_id", "userId")] + public void TestToCamelCase(string value, string expected) + { + var actual = value.ToCamelCase(); + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow("User-Name", "UserName")] + [DataRow("User_Name", "UserName")] + [DataRow("user Name", "UserName")] + [DataRow("_name", "Name")] + [DataRow("name_", "Name")] + [DataRow("user_id", "UserId")] + public void TestToPascalCase(string value, string expected) + { + var actual = value.ToPascalCase(); + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow("ThisIsSampleSentence", "This is sample sentence")] + [DataRow("MASAStack", "Masa stack")] + public void TestToSentenceCase(string value, string expected) + { + var actual = value.ToSentenceCase(); + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow("ThisIsSampleSentence", "this-is-sample-sentence")] + [DataRow("UserID", "user-id")] + [DataRow("userID", "user-id")] + [DataRow("MASAAuth", "masa-auth")] + public void TestToKebabCase(string value, string expected) + { + var actual = value.ToKebabCase(); + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow("ThisIsSampleSentence", "this_is_sample_sentence")] + [DataRow("UserID", "user_id")] + [DataRow("MASAAuth", "masa_auth")] + public void TestToSnakeCase(string value, string expected) + { + var actual = value.ToSnakeCase(); + Assert.AreEqual(expected, actual); + } } diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/FluentValidationExtensions.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/FluentValidationExtensions.cs index 084e7ed89..d924b154e 100644 --- a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/FluentValidationExtensions.cs +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/FluentValidationExtensions.cs @@ -50,6 +50,9 @@ public static IRuleBuilderOptions Phone(this IRuleBuilder IdCard(this IRuleBuilder ruleBuilder, string? culture = null) => ruleBuilder.SetValidator(new IdCardValidator(culture)); + public static IRuleBuilderOptions Email(this IRuleBuilder ruleBuilder) + => ruleBuilder.SetValidator(new EmailRegularValidator()); + public static IRuleBuilderOptions Url(this IRuleBuilder ruleBuilder) => ruleBuilder.SetValidator(new UrlValidator()); @@ -58,4 +61,10 @@ public static IRuleBuilderOptions Port(this IRuleBuilder Required(this IRuleBuilder ruleBuilder) => ruleBuilder.SetValidator(new RequiredValidator()); + + public static IRuleBuilderOptions Identity(this IRuleBuilder ruleBuilder) + => ruleBuilder.SetValidator(new IdentityValidator()); + + public static IRuleBuilderOptions Password(this IRuleBuilder ruleBuilder, string expression = RegularHelper.PASSWORD_REGULAR) + => ruleBuilder.SetValidator(new PasswordValidator(expression)); } diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Internal/RegularHelper.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Internal/RegularHelper.cs index 75306d701..a3cbabe10 100644 --- a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Internal/RegularHelper.cs +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Internal/RegularHelper.cs @@ -10,6 +10,7 @@ internal static class RegularHelper internal const string CHINESE = "^\\s{0}$|^[\u4e00-\u9fa5]+$"; internal const string NUMBER = "^\\s{0}$|^[0-9]+$"; internal const string LETTER = "^\\s{0}$|^[a-zA-Z]+$"; + internal const string IDENTIFY = "^\\s{0}$|^[a-zA-Z0-9\\.-]+$"; internal const string LOWER_LETTER = "^\\s{0}$|^[a-z]+$"; internal const string UPPER_LETTER = "^\\s{0}$|^[A-Z]+$"; internal const string LETTER_NUMBER = "^\\s{0}$|^[a-zA-Z0-9]+$"; @@ -19,6 +20,10 @@ internal static class RegularHelper internal const string CHINESE_LETTER_UNDERLINE = "^\\s{0}$|^[\u4e00-\u9fa5_a-zA-Z]+$"; internal const string IDCARD = "^\\s{0}$|(^\\d{15}$)|(^\\d{17}([0-9]|X|x)$)"; internal const string URL = "^\\s{0}$|[a-zA-z]+://[^s]*"; + internal const string EMAIL = @"^\s{0}$|^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$"; +#pragma warning disable S2068 + internal const string PASSWORD_REGULAR = @"^\s{0}$|^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Za-z])\S*$"; +#pragma warning restore S2068 internal const string PORT = "^\\s{0}$|^([1-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$"; diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/ChineseSimplifiedLanguage.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/ChineseSimplifiedLanguage.cs index 76480c86f..accc8df4a 100644 --- a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/ChineseSimplifiedLanguage.cs +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/ChineseSimplifiedLanguage.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace @@ -25,6 +25,9 @@ internal class ChineseSimplifiedLanguage : ILanguageProvider "RequiredValidator" => "'{PropertyName}' 是必需的", "UpperLetterValidator" => "'{PropertyName}' 必须是大写字母.", "UrlValidator" => "'{PropertyName}' 必须是一个合法的Url地址", + "EmailRegularValidator" => "'{PropertyName}' 必须是一个合法的Email", + "PasswordValidator" => "'{PropertyName}' 密码验证规则不通过", + "IdentityValidator" => "'{PropertyName}' 必须是数字、字母或中划线和点", _ => string.Empty, }; } diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/EnglishLanguage.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/EnglishLanguage.cs index ca4ecc908..35807fd7d 100644 --- a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/EnglishLanguage.cs +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/EnglishLanguage.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace @@ -25,6 +25,9 @@ internal class EnglishLanguage : ILanguageProvider "RequiredValidator" => "'{PropertyName}' is required.", "UpperLetterValidator" => "'{PropertyName}' must be uppercase.", "UrlValidator" => "'{PropertyName}' must be a legal Url address.", + "EmailRegularValidator" => "'{PropertyName}' must be a legal Email.", + "PasswordValidator" => "'{PropertyName}' password validation rule failed.", + "IdentityValidator" => "'{PropertyName}' must be numbers, letters or . and - .", _ => string.Empty, }; } diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/MasaLanguageManager.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/MasaLanguageManager.cs index dd01a476b..f63511975 100644 --- a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/MasaLanguageManager.cs +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Resources/MasaLanguageManager.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace @@ -39,6 +39,9 @@ public MasaLanguageManager() AddTranslation(language, nameof(RequiredValidator), languageProvider.GetTranslation(nameof(RequiredValidator))); AddTranslation(language, nameof(UpperLetterValidator), languageProvider.GetTranslation(nameof(UpperLetterValidator))); AddTranslation(language, nameof(UrlValidator), languageProvider.GetTranslation(nameof(UrlValidator))); + AddTranslation(language, nameof(EmailRegularValidator), languageProvider.GetTranslation(nameof(EmailRegularValidator))); + AddTranslation(language, nameof(PasswordValidator), languageProvider.GetTranslation(nameof(PasswordValidator))); + AddTranslation(language, nameof(IdentityValidator), languageProvider.GetTranslation(nameof(IdentityValidator))); } } diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/EmailRegularValidator.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/EmailRegularValidator.cs new file mode 100644 index 000000000..42862dca9 --- /dev/null +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/EmailRegularValidator.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace FluentValidation.Validators; + +public class EmailRegularValidator : MasaRegularExpressionValidator +{ + public override string Name => nameof(EmailRegularValidator); + + public EmailRegularValidator() : base(RegularHelper.EMAIL) + { + } +} diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/IdentityValidator.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/IdentityValidator.cs new file mode 100644 index 000000000..26a9e3485 --- /dev/null +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/IdentityValidator.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace FluentValidation.Validators; + +public class IdentityValidator : MasaRegularExpressionValidator +{ + public override string Name => nameof(IdentityValidator); + + public IdentityValidator() : base(RegularHelper.IDENTIFY) + { + } +} diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PasswordValidator.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PasswordValidator.cs new file mode 100644 index 000000000..ef6f18065 --- /dev/null +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PasswordValidator.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace FluentValidation.Validators; + +public class PasswordValidator : RegularExpressionValidator +{ + public override string Name => nameof(PasswordValidator); + + public PasswordValidator(string expression) : base(expression) + { + } +} diff --git a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PhoneValidator.cs b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PhoneValidator.cs index 3ad5aa4f6..f6eddc16e 100644 --- a/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PhoneValidator.cs +++ b/src/Utils/Extensions/Validations/Masa.Utils.Extensions.Validations.FluentValidation/Validators/PhoneValidator.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace diff --git a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/EmailValidatorTest.cs b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/EmailValidatorTest.cs new file mode 100644 index 000000000..349287d5d --- /dev/null +++ b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/EmailValidatorTest.cs @@ -0,0 +1,36 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Utils.Extensions.Validations.FluentValidation.Tests; + +[TestClass] +public class EmailValidatorTest : ValidatorBaseTest +{ + public override string Message => "'Email' must be a legal Email."; + + [DataRow("masastack123@", false)] + [DataRow("123", false)] + [DataRow("123@qq.com", true)] + [DataTestMethod] + public void TestEmail(string email, bool expectedResult) + { + var validator = new RegisterUserEventValidator(); + var result = validator.Validate(new RegisterUserEvent() + { + Email = email + }); + Assert.AreEqual(expectedResult, result.IsValid); + if (!expectedResult) + { + Assert.AreEqual(Message, result.Errors[0].ErrorMessage); + } + } + + public class RegisterUserEventValidator : AbstractValidator + { + public RegisterUserEventValidator() + { + RuleFor(r => r.Email).Email(); + } + } +} diff --git a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/Events/RegisterUserEvent.cs b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/Events/RegisterUserEvent.cs index 2cad73766..9e6e60494 100644 --- a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/Events/RegisterUserEvent.cs +++ b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/Events/RegisterUserEvent.cs @@ -1,4 +1,4 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ReSharper disable once CheckNamespace @@ -18,4 +18,8 @@ public class RegisterUserEvent public string Referer { get; set; } public string? Remark { get; set; } + + public string Email { get; set; } + + public string Password { get; set; } } diff --git a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/IdentityValidatorTest.cs b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/IdentityValidatorTest.cs new file mode 100644 index 000000000..5ab5e5994 --- /dev/null +++ b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/IdentityValidatorTest.cs @@ -0,0 +1,36 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Utils.Extensions.Validations.FluentValidation.Tests; + +[TestClass] +public class IdentityValidatorTest : ValidatorBaseTest +{ + public override string Message => "'' must be numbers, letters or . and - ."; + + [DataRow("Masa团队", false)] + [DataRow("masastack", true)] + [DataRow("masastack@123", false)] + [DataRow("Masa", true)] + [DataRow("123#", false)] + [DataRow("123.", true)] + [DataTestMethod] + public void TestIdentity(string identity, bool expectedResult) + { + var validator = new IdentityValidator(); + var result = validator.Validate(identity); + Assert.AreEqual(expectedResult, result.IsValid); + if (!expectedResult) + { + Assert.AreEqual(Message, result.Errors[0].ErrorMessage); + } + } + + public class IdentityValidator : AbstractValidator + { + public IdentityValidator() + { + RuleFor(r => r).Identity(); + } + } +} diff --git a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/NumberValidatorTest.cs b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/NumberValidatorTest.cs index 0d1b5c26b..773fc35ea 100644 --- a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/NumberValidatorTest.cs +++ b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/NumberValidatorTest.cs @@ -1,10 +1,10 @@ -// Copyright (c) MASA Stack All rights reserved. +// Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. namespace Masa.Utils.Extensions.Validations.FluentValidation.Tests; [TestClass] -public class NumberValidatorTest: ValidatorBaseTest +public class NumberValidatorTest : ValidatorBaseTest { public override string Message => "'Id Card' must be Number."; diff --git a/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/PasswordValidatorTest.cs b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/PasswordValidatorTest.cs new file mode 100644 index 000000000..3ef92a8be --- /dev/null +++ b/src/Utils/Extensions/Validations/Tests/Masa.Utils.Extensions.Validations.FluentValidation.Tests/PasswordValidatorTest.cs @@ -0,0 +1,40 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Utils.Extensions.Validations.FluentValidation.Tests; + +[TestClass] +public class PasswordValidatorTest : ValidatorBaseTest +{ + public override string Message => "'Password' password validation rule failed."; + + [DataRow("Masa团队", false)] + [DataRow("masastack", false)] + [DataRow("masastack@123", true)] + [DataRow("Masa", false)] + [DataRow("Masa@123", true)] + [DataRow("123", false)] + [DataRow("123.", false)] + [DataTestMethod] + public void TestPassword(string pwd, bool expectedResult) + { + var validator = new RegisterUserEventValidator(); + var result = validator.Validate(new RegisterUserEvent() + { + Password = pwd + }); + Assert.AreEqual(expectedResult, result.IsValid); + if (!expectedResult) + { + Assert.AreEqual(Message, result.Errors[0].ErrorMessage); + } + } + + public class RegisterUserEventValidator : AbstractValidator + { + public RegisterUserEventValidator() + { + RuleFor(r => r.Password).Password(); + } + } +} diff --git a/src/Utils/Security/Masa.Utils.Security.Cryptography/AesUtils.cs b/src/Utils/Security/Masa.Utils.Security.Cryptography/AesUtils.cs index b7c81dc51..78ddcaa8c 100644 --- a/src/Utils/Security/Masa.Utils.Security.Cryptography/AesUtils.cs +++ b/src/Utils/Security/Masa.Utils.Security.Cryptography/AesUtils.cs @@ -48,7 +48,7 @@ public static string Encrypt( public static string Encrypt( string content, string key, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -69,7 +69,7 @@ public static string Encrypt( string content, string key, string iv, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -98,7 +98,7 @@ public static string Encrypt( string content, string key, byte[] ivBuffer, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -137,7 +137,7 @@ public static byte[] EncryptToBytes( public static byte[] EncryptToBytes( Stream stream, string key, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -158,7 +158,7 @@ public static byte[] EncryptToBytes( Stream stream, string key, string iv, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -185,7 +185,7 @@ public static byte[] EncryptToBytes( Stream stream, string key, byte[] ivBuffer, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -243,7 +243,7 @@ public static void EncryptFile( Stream stream, string key, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -265,7 +265,7 @@ public static void EncryptFile( string key, byte[] ivBuffer, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -295,7 +295,7 @@ public static void EncryptFile( string key, string iv, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -339,7 +339,7 @@ public static string Decrypt( public static string Decrypt( string content, string key, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -360,7 +360,7 @@ public static string Decrypt( string content, string key, string iv, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -388,7 +388,7 @@ public static string Decrypt( string content, string key, byte[] ivBuffer, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -432,7 +432,7 @@ public static byte[] DecryptToBytes( public static byte[] DecryptToBytes( Stream stream, string key, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -453,7 +453,7 @@ public static byte[] DecryptToBytes( Stream stream, string key, string iv, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -480,7 +480,7 @@ public static byte[] DecryptToBytes( Stream stream, string key, byte[] ivBuffer, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -515,7 +515,7 @@ public static byte[] DecryptToBytes( public static void DecryptFile( Stream stream, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => DecryptFile(stream, DefaultEncryptKey, outputPath, fillType, fillCharacter, encoding); @@ -534,7 +534,7 @@ public static void DecryptFile( Stream stream, string key, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -556,7 +556,7 @@ public static void DecryptFile( string key, byte[] ivBuffer, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) @@ -581,7 +581,7 @@ public static void DecryptFile( string key, string iv, string outputPath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null, int? aesLength = null) diff --git a/src/Utils/Security/Masa.Utils.Security.Cryptography/DESUtils.cs b/src/Utils/Security/Masa.Utils.Security.Cryptography/DESUtils.cs index 077d8fc90..87c7745a8 100644 --- a/src/Utils/Security/Masa.Utils.Security.Cryptography/DESUtils.cs +++ b/src/Utils/Security/Masa.Utils.Security.Cryptography/DESUtils.cs @@ -70,7 +70,7 @@ public static string Encrypt( string key, DESEncryptType desEncryptType = DESEncryptType.Improved, bool isToLower = true, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => Encrypt(content, key, DefaultEncryptIv, desEncryptType, isToLower, fillType, fillCharacter, encoding); @@ -93,7 +93,7 @@ public static string Encrypt( string iv, DESEncryptType desEncryptType = DESEncryptType.Improved, bool isToLower = true, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) { @@ -146,7 +146,7 @@ public static string Decrypt( string content, string key, DESEncryptType desEncryptType = DESEncryptType.Improved, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => Decrypt(content, key, DefaultEncryptIv, desEncryptType, fillType, fillCharacter, encoding); @@ -167,7 +167,7 @@ public static string Decrypt( string key, string iv, DESEncryptType desEncryptType = DESEncryptType.Improved, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) { @@ -208,7 +208,7 @@ public static void EncryptFile( FileStream fileStream, string key, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => EncryptOrDecryptFile(fileStream, key, outFilePath, true, fillType, fillCharacter, encoding); @@ -228,7 +228,7 @@ public static void EncryptFile( string key, string iv, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => EncryptOrDecryptFile(fileStream, key, iv, true, outFilePath, fillType, fillCharacter, encoding); @@ -248,7 +248,7 @@ public static void EncryptFile( string key, byte[] ivBuffer, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) { @@ -274,7 +274,7 @@ public static void DecryptFile( FileStream fileStream, string key, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => EncryptOrDecryptFile(fileStream, key, outFilePath, false, fillType, fillCharacter, encoding); @@ -294,7 +294,7 @@ public static void DecryptFile( string key, string iv, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => EncryptOrDecryptFile(fileStream, key, iv, false, outFilePath, fillType, fillCharacter, encoding); @@ -314,7 +314,7 @@ public static void DecryptFile( string key, byte[] ivBuffer, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) { @@ -332,7 +332,7 @@ private static void EncryptOrDecryptFile( string key, string outFilePath, bool isEncrypt, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) => EncryptOrDecryptFile(fileStream, key, DefaultEncryptKey, isEncrypt, outFilePath, fillType, fillCharacter, encoding); @@ -343,7 +343,7 @@ private static void EncryptOrDecryptFile( string iv, bool isEncrypt, string outFilePath, - FillType fillType = FillType.NoFile, + FillType fillType = FillType.NoFill, char fillCharacter = ' ', Encoding? encoding = null) { diff --git a/src/Utils/Security/Tests/Masa.Utils.Security.Cryptography.Tests/AesTest.cs b/src/Utils/Security/Tests/Masa.Utils.Security.Cryptography.Tests/AesTest.cs index d448c83ce..c6a2db249 100644 --- a/src/Utils/Security/Tests/Masa.Utils.Security.Cryptography.Tests/AesTest.cs +++ b/src/Utils/Security/Tests/Masa.Utils.Security.Cryptography.Tests/AesTest.cs @@ -20,10 +20,10 @@ public void TestEncryptAndDecrypt() var source3 = AesUtils.Decrypt(AesUtils.Encrypt(str, key, "123", FillType.Right), key, "123", FillType.Right); Assert.IsTrue(str == source3); - Assert.ThrowsException(() => AesUtils.Encrypt(str, key, "123", FillType.NoFile)); + Assert.ThrowsException(() => AesUtils.Encrypt(str, key, "123", FillType.NoFill)); string encryptResult = AesUtils.Encrypt(str, key, "123", FillType.Right); - Assert.ThrowsException(() => AesUtils.Decrypt(encryptResult, key, "123", FillType.NoFile)); + Assert.ThrowsException(() => AesUtils.Decrypt(encryptResult, key, "123", FillType.NoFill)); } [DataRow(16)] @@ -53,10 +53,10 @@ public void TestEncryptAndDecrypt2(int length) var source3 = AesUtils.Decrypt(AesUtils.Encrypt(str, key, "123", FillType.Right), key, "123", FillType.Right); Assert.IsTrue(str == source3); - Assert.ThrowsException(() => AesUtils.Encrypt(str, key, "123", FillType.NoFile)); + Assert.ThrowsException(() => AesUtils.Encrypt(str, key, "123", FillType.NoFill)); string encryptResult = AesUtils.Encrypt(str, key, "123", FillType.Right); - Assert.ThrowsException(() => AesUtils.Decrypt(encryptResult, key, "123", FillType.NoFile)); + Assert.ThrowsException(() => AesUtils.Decrypt(encryptResult, key, "123", FillType.NoFill)); } [TestMethod]