using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; 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 EmailValidator from FluentValidation. So let's keep them sync - https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation/Validators/EmailValidator.cs private const string EMAIL_EXPRESSION = @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$"; private static readonly Regex _emailRegex; #endregion #region Ctor static CommonHelper() { _emailRegex = new Regex(EMAIL_EXPRESSION, RegexOptions.IgnoreCase); } #endregion #region Methods /// /// 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 _emailRegex.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) { if (instance == null) throw new ArgumentNullException(nameof(instance)); if (propertyName == null) throw new ArgumentNullException(nameof(propertyName)); var instanceType = instance.GetType(); var pi = instanceType.GetProperty(propertyName); if (pi == null) 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)); } /// /// Convert enum for front-end /// /// Input string /// Converted string public static string ConvertEnum(string str) { if (string.IsNullOrEmpty(str)) return string.Empty; var result = string.Empty; foreach (var c in str) if (c.ToString() != c.ToString().ToLowerInvariant()) result += " " + c.ToString(); else result += c.ToString(); //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 } }