diff --git a/framework/src/Volo.Abp.Features/Volo.Abp.Features.csproj b/framework/src/Volo.Abp.Features/Volo.Abp.Features.csproj
index e626a34a9f..fc59bfaa9f 100644
--- a/framework/src/Volo.Abp.Features/Volo.Abp.Features.csproj
+++ b/framework/src/Volo.Abp.Features/Volo.Abp.Features.csproj
@@ -16,6 +16,7 @@
+
diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs
index 9065651b3b..8730c04591 100644
--- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs
+++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs
@@ -4,12 +4,14 @@ using System.Collections.Generic;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
+using Volo.Abp.Validation;
namespace Volo.Abp.Features
{
[DependsOn(
typeof(AbpLocalizationAbstractionsModule),
- typeof(AbpMultiTenancyAbstractionsModule)
+ typeof(AbpMultiTenancyAbstractionsModule),
+ typeof(AbpValidationModule)
)]
public class AbpFeaturesModule : AbpModule
{
diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs
index 6a1c030b21..bd79480326 100644
--- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs
+++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinition.cs
@@ -3,6 +3,7 @@ using System.Collections.Immutable;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Localization;
+using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.Features
{
@@ -29,6 +30,7 @@ namespace Volo.Abp.Features
/// Parent of this feature, if one exists.
/// If set, this feature can be enabled only if the parent is enabled.
///
+ [CanBeNull]
public FeatureDefinition Parent { get; private set; }
///
@@ -53,6 +55,7 @@ namespace Volo.Abp.Features
/// A list of allowed providers to get/set value of this feature.
/// An empty list indicates that all providers are allowed.
///
+ [NotNull]
public List AllowedProviders { get; }
///
@@ -63,6 +66,7 @@ namespace Volo.Abp.Features
/// Returns the value in the dictionary by given .
/// Returns null if given is not present in the dictionary.
///
+ [CanBeNull]
public object this[string name]
{
get => Properties.GetOrDefault(name);
@@ -75,20 +79,28 @@ namespace Volo.Abp.Features
[NotNull]
public Dictionary Properties { get; }
- //TODO: Implement input type like old ABP!
+ ///
+ /// Input type.
+ /// This can be used to prepare an input for changing this feature's value.
+ /// Default: .
+ ///
+ [CanBeNull]
+ public IStringValueType ValueType { get; set; }
public FeatureDefinition(
string name,
string defaultValue = null,
ILocalizableString displayName = null,
ILocalizableString description = null,
+ IStringValueType valueType = null,
bool isVisibleToClients = true)
{
Name = name;
DefaultValue = defaultValue;
- IsVisibleToClients = isVisibleToClients;
DisplayName = displayName ?? new FixedLocalizableString(name);
Description = description;
+ ValueType = valueType;
+ IsVisibleToClients = isVisibleToClients;
Properties = new Dictionary();
AllowedProviders = new List();
@@ -128,13 +140,15 @@ namespace Volo.Abp.Features
string defaultValue = null,
ILocalizableString displayName = null,
ILocalizableString description = null,
+ IStringValueType valueType = null,
bool isVisibleToClients = true)
{
var feature = new FeatureDefinition(
name,
defaultValue,
displayName,
- description,
+ description,
+ valueType,
isVisibleToClients)
{
Parent = this
diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs
index 4d0ccbba62..cba38070a7 100644
--- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs
+++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureGroupDefinition.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using Volo.Abp.Localization;
+using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.Features
{
@@ -53,6 +54,7 @@ namespace Volo.Abp.Features
string defaultValue = null,
ILocalizableString displayName = null,
ILocalizableString description = null,
+ IStringValueType valueType = null,
bool isVisibleToClients = true)
{
var feature = new FeatureDefinition(
@@ -60,6 +62,7 @@ namespace Volo.Abp.Features
defaultValue,
displayName,
description,
+ valueType,
isVisibleToClients
);
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/AlwaysValidValueValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/AlwaysValidValueValidator.cs
new file mode 100644
index 0000000000..ec444bd62b
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/AlwaysValidValueValidator.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [ValueValidator("NULL")]
+ public class AlwaysValidValueValidator : ValueValidatorBase
+ {
+ public override bool IsValid(object value)
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/BooleanValueValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/BooleanValueValidator.cs
new file mode 100644
index 0000000000..41c52894cd
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/BooleanValueValidator.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [ValueValidator("BOOLEAN")]
+ public class BooleanValueValidator : ValueValidatorBase
+ {
+ public override bool IsValid(object value)
+ {
+ if (value == null)
+ {
+ return false;
+ }
+
+ if (value is bool)
+ {
+ return true;
+ }
+
+ return bool.TryParse(value.ToString(), out _);
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/FreeTextStringValueType.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/FreeTextStringValueType.cs
new file mode 100644
index 0000000000..c02f617b48
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/FreeTextStringValueType.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [StringValueType("FREE_TEXT")]
+ public class FreeTextStringValueType : StringValueTypeBase
+ {
+ public FreeTextStringValueType()
+ {
+
+ }
+
+ public FreeTextStringValueType(IValueValidator validator)
+ : base(validator)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ISelectionStringValueItem.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ISelectionStringValueItem.cs
new file mode 100644
index 0000000000..1dd69158c7
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ISelectionStringValueItem.cs
@@ -0,0 +1,9 @@
+namespace Volo.Abp.Validation.StringValues
+{
+ public interface ISelectionStringValueItem
+ {
+ string Value { get; set; }
+
+ LocalizableStringInfo DisplayText { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ISelectionStringValueItemSource.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ISelectionStringValueItemSource.cs
new file mode 100644
index 0000000000..563503a05d
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ISelectionStringValueItemSource.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ public interface ISelectionStringValueItemSource
+ {
+ ICollection Items { get; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/IStringValueType.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/IStringValueType.cs
new file mode 100644
index 0000000000..674b6e55f9
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/IStringValueType.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using JetBrains.Annotations;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ public interface IStringValueType
+ {
+ string Name { get; }
+
+ [CanBeNull]
+ object this[string key] { get; set; }
+
+ [NotNull]
+ Dictionary Properties { get; }
+
+ IValueValidator Validator { get; set; }
+ }
+}
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/IValueValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/IValueValidator.cs
new file mode 100644
index 0000000000..afcacb3e34
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/IValueValidator.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using JetBrains.Annotations;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ public interface IValueValidator
+ {
+ string Name { get; }
+
+ [CanBeNull]
+ object this[string key] { get; set; }
+
+ [NotNull]
+ IDictionary Properties { get; }
+
+ bool IsValid(object value);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/LocalizableSelectionStringValueItem.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/LocalizableSelectionStringValueItem.cs
new file mode 100644
index 0000000000..716c9e0e1c
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/LocalizableSelectionStringValueItem.cs
@@ -0,0 +1,9 @@
+namespace Volo.Abp.Validation.StringValues
+{
+ public class LocalizableSelectionStringValueItem : ISelectionStringValueItem
+ {
+ public string Value { get; set; }
+
+ public LocalizableStringInfo DisplayText { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/LocalizableStringInfo.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/LocalizableStringInfo.cs
new file mode 100644
index 0000000000..f4359c967f
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/LocalizableStringInfo.cs
@@ -0,0 +1,15 @@
+namespace Volo.Abp.Validation.StringValues
+{
+ public class LocalizableStringInfo
+ {
+ public string ResourceName { get; }
+
+ public string Name { get; }
+
+ public LocalizableStringInfo(string resourceName, string name)
+ {
+ ResourceName = resourceName;
+ Name = name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/NumericValueValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/NumericValueValidator.cs
new file mode 100644
index 0000000000..e1b1972258
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/NumericValueValidator.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [ValueValidator("NUMERIC")]
+ public class NumericValueValidator : ValueValidatorBase
+ {
+ public int MinValue
+ {
+ get => (this["MinValue"] ?? "0").To();
+ set => this["MinValue"] = value;
+ }
+
+ public int MaxValue
+ {
+ get => (this["MaxValue"] ?? "0").To();
+ set => this["MaxValue"] = value;
+ }
+
+ public NumericValueValidator()
+ {
+
+ }
+
+ public NumericValueValidator(int minValue = int.MinValue, int maxValue = int.MaxValue)
+ {
+ MinValue = minValue;
+ MaxValue = maxValue;
+ }
+
+ public override bool IsValid(object value)
+ {
+ if (value == null)
+ {
+ return false;
+ }
+
+ if (value is int)
+ {
+ return IsValidInternal((int)value);
+ }
+
+ if (value is string)
+ {
+ int intValue;
+ if (int.TryParse(value as string, out intValue))
+ {
+ return IsValidInternal(intValue);
+ }
+ }
+
+ return false;
+ }
+
+ protected virtual bool IsValidInternal(int value)
+ {
+ return value.IsBetween(MinValue, MaxValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/SelectionStringValueType.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/SelectionStringValueType.cs
new file mode 100644
index 0000000000..e2d4ecbc99
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/SelectionStringValueType.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [StringValueType("SELECTION")]
+ public class SelectionStringValueType : StringValueTypeBase
+ {
+ public ISelectionStringValueItemSource ItemSource { get; set; }
+
+ public SelectionStringValueType()
+ {
+
+ }
+
+ public SelectionStringValueType(IValueValidator validator)
+ : base(validator)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StaticSelectionStringValueItemSource.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StaticSelectionStringValueItemSource.cs
new file mode 100644
index 0000000000..de0fed9879
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StaticSelectionStringValueItemSource.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ public class StaticSelectionStringValueItemSource : ISelectionStringValueItemSource
+ {
+ public ICollection Items { get; }
+
+ public StaticSelectionStringValueItemSource(params ISelectionStringValueItem[] items)
+ {
+ Items = Check.NotNullOrEmpty(items, nameof(items));
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueTypeAttribute.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueTypeAttribute.cs
new file mode 100644
index 0000000000..5fa8bef1ae
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueTypeAttribute.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class StringValueTypeAttribute : Attribute
+ {
+ public string Name { get; set; }
+
+ public StringValueTypeAttribute(string name)
+ {
+ Name = name;
+ }
+
+ public static string GetName(Type type)
+ {
+ if (type.IsDefined(typeof(StringValueTypeAttribute)))
+ {
+ return type.GetCustomAttributes(typeof(StringValueTypeAttribute)).Cast().First().Name;
+ }
+
+ return type.Name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueTypeBase.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueTypeBase.cs
new file mode 100644
index 0000000000..c6fd80fc13
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueTypeBase.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ public abstract class StringValueTypeBase : IStringValueType
+ {
+ public virtual string Name => ValueValidatorAttribute.GetName(GetType());
+
+ public object this[string key]
+ {
+ get => Properties.GetOrDefault(key);
+ set => Properties[key] = value;
+ }
+
+ public Dictionary Properties { get; }
+
+ public IValueValidator Validator { get; set; }
+
+ protected StringValueTypeBase()
+ : this(new AlwaysValidValueValidator())
+ {
+
+ }
+
+ protected StringValueTypeBase(IValueValidator validator)
+ {
+ Validator = validator;
+ Properties = new Dictionary();
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueValidator.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueValidator.cs
new file mode 100644
index 0000000000..3edc176b0c
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/StringValueValidator.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [ValueValidator("STRING")]
+ public class StringValueValidator : ValueValidatorBase
+ {
+ public bool AllowNull
+ {
+ get => (this["AllowNull"] ?? "false").To();
+ set => this["AllowNull"] = value.ToString().ToLowerInvariant();
+ }
+
+ public int MinLength
+ {
+ get => (this["MinLength"] ?? "0").To();
+ set => this["MinLength"] = value;
+ }
+
+ public int MaxLength
+ {
+ get => (this["MaxLength"] ?? "0").To();
+ set => this["MaxLength"] = value;
+ }
+
+ public string RegularExpression
+ {
+ get => this["RegularExpression"] as string;
+ set => this["RegularExpression"] = value;
+ }
+
+ public StringValueValidator()
+ {
+
+ }
+
+ public StringValueValidator(int minLength = 0, int maxLength = 0, string regularExpression = null, bool allowNull = false)
+ {
+ MinLength = minLength;
+ MaxLength = maxLength;
+ RegularExpression = regularExpression;
+ AllowNull = allowNull;
+ }
+
+ public override bool IsValid(object value)
+ {
+ if (value == null)
+ {
+ return AllowNull;
+ }
+
+ if (!(value is string))
+ {
+ return false;
+ }
+
+ var strValue = value as string;
+
+ if (MinLength > 0 && strValue.Length < MinLength)
+ {
+ return false;
+ }
+
+ if (MaxLength > 0 && strValue.Length > MaxLength)
+ {
+ return false;
+ }
+
+ if (!RegularExpression.IsNullOrEmpty())
+ {
+ return Regex.IsMatch(strValue, RegularExpression);
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ToggleStringValueType.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ToggleStringValueType.cs
new file mode 100644
index 0000000000..a262630766
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ToggleStringValueType.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ [StringValueType("TOGGLE")]
+ public class ToggleStringValueType : StringValueTypeBase
+ {
+ public ToggleStringValueType()
+ : this(new BooleanValueValidator())
+ {
+
+ }
+
+ public ToggleStringValueType(IValueValidator validator)
+ : base(validator)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ValueValidatorAttribute.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ValueValidatorAttribute.cs
new file mode 100644
index 0000000000..6f40ad0651
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ValueValidatorAttribute.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ValueValidatorAttribute : Attribute
+ {
+ public string Name { get; set; }
+
+ public ValueValidatorAttribute(string name)
+ {
+ Name = name;
+ }
+
+ public static string GetName(Type type)
+ {
+ if (type.IsDefined(typeof(ValueValidatorAttribute)))
+ {
+ return type.GetCustomAttributes(typeof(ValueValidatorAttribute)).Cast().First().Name;
+ }
+
+ return type.Name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ValueValidatorBase.cs b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ValueValidatorBase.cs
new file mode 100644
index 0000000000..ee91089fd4
--- /dev/null
+++ b/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/StringValues/ValueValidatorBase.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+
+namespace Volo.Abp.Validation.StringValues
+{
+ [Serializable]
+ public abstract class ValueValidatorBase : IValueValidator
+ {
+ public virtual string Name => ValueValidatorAttribute.GetName(GetType());
+
+ public object this[string key]
+ {
+ get => Properties.GetOrDefault(key);
+ set => Properties[key] = value;
+ }
+
+ public IDictionary Properties { get; }
+
+ protected ValueValidatorBase()
+ {
+ Properties = new Dictionary();
+ }
+
+ public abstract bool IsValid(object value);
+ }
+}
\ No newline at end of file