using System.ComponentModel; using System.Globalization; using System.Net; using System.Text.RegularExpressions; using Nop.Core.Infrastructure; namespace Nop.Core; /// /// Represents a common helper /// public partial class CommonHelper { #region Fields //we use regular expression based on RFC 5322 Official Standard (see https://emailregex.com/) private const string EMAIL_EXPRESSION = @"^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$"; #endregion #region Methods /// /// Get email validation regex /// /// Regular expression [GeneratedRegex(EMAIL_EXPRESSION, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture, "en-US")] public static partial Regex GetEmailRegex(); /// /// Ensures the subscriber email or throw. /// /// The email. /// public static string EnsureSubscriberEmailOrThrow(string email) { var output = EnsureNotNull(email); output = output.Trim(); output = EnsureMaximumLength(output, 255); if (!IsValidEmail(output)) { throw new NopException("Email is not valid."); } return output; } /// /// Verifies that a string is in valid e-mail format /// /// Email to verify /// true if the string is a valid e-mail address and false if it's not public static bool IsValidEmail(string email) { if (string.IsNullOrEmpty(email)) return false; email = email.Trim(); return GetEmailRegex().IsMatch(email); } /// /// Verifies that string is an valid IP-Address /// /// IPAddress to verify /// true if the string is a valid IpAddress and false if it's not public static bool IsValidIpAddress(string ipAddress) { return IPAddress.TryParse(ipAddress, out var _); } /// /// Generate random digit code /// /// Length /// Result string public static string GenerateRandomDigitCode(int length) { using var random = new SecureRandomNumberGenerator(); var str = string.Empty; for (var i = 0; i < length; i++) str = string.Concat(str, random.Next(10).ToString()); return str; } /// /// Returns an random integer number within a specified rage /// /// Minimum number /// Maximum number /// Result public static int GenerateRandomInteger(int min = 0, int max = int.MaxValue) { using var random = new SecureRandomNumberGenerator(); return random.Next(min, max); } /// /// Ensure that a string doesn't exceed maximum allowed length /// /// Input string /// Maximum length /// A string to add to the end if the original string was shorten /// Input string if its length is OK; otherwise, truncated input string public static string EnsureMaximumLength(string str, int maxLength, string postfix = null) { if (string.IsNullOrEmpty(str)) return str; if (str.Length <= maxLength) return str; var pLen = postfix?.Length ?? 0; var result = str[0..(maxLength - pLen)]; if (!string.IsNullOrEmpty(postfix)) { result += postfix; } return result; } /// /// Ensures that a string only contains numeric values /// /// Input string /// Input string with only numeric values, empty string if input is null/empty public static string EnsureNumericOnly(string str) { return string.IsNullOrEmpty(str) ? string.Empty : new string(str.Where(char.IsDigit).ToArray()); } /// /// Ensure that a string is not null /// /// Input string /// Result public static string EnsureNotNull(string str) { return str ?? string.Empty; } /// /// Indicates whether the specified strings are null or empty strings /// /// Array of strings to validate /// Boolean public static bool AreNullOrEmpty(params string[] stringsToValidate) { return stringsToValidate.Any(string.IsNullOrEmpty); } /// /// Compare two arrays /// /// Type /// Array 1 /// Array 2 /// Result public static bool ArraysEqual(T[] a1, T[] a2) { //also see Enumerable.SequenceEqual(a1, a2); if (ReferenceEquals(a1, a2)) return true; if (a1 == null || a2 == null) return false; if (a1.Length != a2.Length) return false; var comparer = EqualityComparer.Default; return !a1.Where((t, i) => !comparer.Equals(t, a2[i])).Any(); } /// /// Sets a property on an object to a value. /// /// The object whose property to set. /// The name of the property to set. /// The value to set the property to. public static void SetProperty(object instance, string propertyName, object value) { ArgumentNullException.ThrowIfNull(instance); ArgumentNullException.ThrowIfNull(propertyName); var instanceType = instance.GetType(); var pi = instanceType.GetProperty(propertyName) ?? throw new NopException("No property '{0}' found on the instance of type '{1}'.", propertyName, instanceType); if (!pi.CanWrite) throw new NopException("The property '{0}' on the instance of type '{1}' does not have a setter.", propertyName, instanceType); if (value != null && !value.GetType().IsAssignableFrom(pi.PropertyType)) value = To(value, pi.PropertyType); pi.SetValue(instance, value, Array.Empty()); } /// /// Converts a value to a destination type. /// /// The value to convert. /// The type to convert the value to. /// The converted value. public static object To(object value, Type destinationType) { return To(value, destinationType, CultureInfo.InvariantCulture); } /// /// Converts a value to a destination type. /// /// The value to convert. /// The type to convert the value to. /// Culture /// The converted value. public static object To(object value, Type destinationType, CultureInfo culture) { if (value == null) return null; var sourceType = value.GetType(); var destinationConverter = TypeDescriptor.GetConverter(destinationType); if (destinationConverter.CanConvertFrom(value.GetType())) return destinationConverter.ConvertFrom(null, culture, value); var sourceConverter = TypeDescriptor.GetConverter(sourceType); if (sourceConverter.CanConvertTo(destinationType)) return sourceConverter.ConvertTo(null, culture, value, destinationType); if (destinationType.IsEnum && value is int) return Enum.ToObject(destinationType, (int)value); if (!destinationType.IsInstanceOfType(value)) return Convert.ChangeType(value, destinationType, culture); return value; } /// /// Converts a value to a destination type. /// /// The value to convert. /// The type to convert the value to. /// The converted value. public static T To(object value) { //return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture); return (T)To(value, typeof(T)); } /// /// Splits the camel-case word into separate one /// /// Input string /// Splitted string public static string SplitCamelCaseWord(string str) { if (string.IsNullOrEmpty(str)) return string.Empty; var result = str.ToCharArray() .Select(p => p.ToString()) .Aggregate(string.Empty, (current, c) => current + (c == c.ToUpperInvariant() ? $" {c}" : c)); //ensure no spaces (e.g. when the first letter is upper case) result = result.TrimStart(); return result; } /// /// Get difference in years /// /// /// /// public static int GetDifferenceInYears(DateTime startDate, DateTime endDate) { //source: http://stackoverflow.com/questions/9/how-do-i-calculate-someones-age-in-c //this assumes you are looking for the western idea of age and not using East Asian reckoning. var age = endDate.Year - startDate.Year; if (startDate > endDate.AddYears(-age)) age--; return age; } /// /// Get DateTime to the specified year, month, and day using the conventions of the current thread culture /// /// The year /// The month /// The day /// An instance of the Nullable public static DateTime? ParseDate(int? year, int? month, int? day) { if (!year.HasValue || !month.HasValue || !day.HasValue) return null; DateTime? date = null; try { date = new DateTime(year.Value, month.Value, day.Value, CultureInfo.CurrentCulture.Calendar); } catch { } return date; } #endregion #region Properties /// /// Gets or sets the default file provider /// public static INopFileProvider DefaultFileProvider { get; set; } #endregion }