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