mirror of
https://github.com/alexhopeoconnor/dnsmasq-webui.git
synced 2026-10-03 22:12:00 +10:00
EffectiveConfig: add semantics wiring, validation, and tests
- Add DelegateMultiValueOptionValidator for multi-value option validation - Extend EffectiveConfigOptionKindMap, SpecialOptionSemantics, RenderFragmentRegistry - Add EffectiveConfigSemanticsWiringTests
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||||
|
using DnsmasqWebUI.Infrastructure.Services.EffectiveConfig;
|
||||||
|
|
||||||
|
namespace DnsmasqWebUI.Tests;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wiring tests that ensure special-option semantics actually feed parser and registry behavior.
|
||||||
|
/// </summary>
|
||||||
|
public class EffectiveConfigSemanticsWiringTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ParserBehaviorMap_UsesSpecialSemantics_ForSpecialOptions()
|
||||||
|
{
|
||||||
|
var specialOptions = new[]
|
||||||
|
{
|
||||||
|
DnsmasqConfKeys.UseStaleCache,
|
||||||
|
DnsmasqConfKeys.AddMac,
|
||||||
|
DnsmasqConfKeys.AddSubnet,
|
||||||
|
DnsmasqConfKeys.Umbrella,
|
||||||
|
DnsmasqConfKeys.Do0x20Encode,
|
||||||
|
DnsmasqConfKeys.ConnmarkAllowlistEnable,
|
||||||
|
DnsmasqConfKeys.DnssecCheckUnsigned,
|
||||||
|
DnsmasqConfKeys.Leasequery,
|
||||||
|
DnsmasqConfKeys.DhcpGenerateNames,
|
||||||
|
DnsmasqConfKeys.DhcpBroadcast,
|
||||||
|
DnsmasqConfKeys.BootpDynamic,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var option in specialOptions)
|
||||||
|
{
|
||||||
|
var semantics = EffectiveConfigSpecialOptionSemantics.TryGetSemantics(option);
|
||||||
|
Assert.NotNull(semantics);
|
||||||
|
Assert.Equal(semantics!.ParserBehavior, EffectiveConfigParserBehaviorMap.GetBehavior(option));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Registry_WiresLeasequeryMultiValidator_FromSpecialSemantics()
|
||||||
|
{
|
||||||
|
var registry = new EffectiveConfigRenderFragmentRegistry();
|
||||||
|
var factory = registry.GetMultiDescriptorFactory(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.Leasequery);
|
||||||
|
Assert.NotNull(factory);
|
||||||
|
|
||||||
|
var descriptor = factory!(
|
||||||
|
EffectiveConfigFieldBuilder.SectionDhcp,
|
||||||
|
DnsmasqConfKeys.Leasequery,
|
||||||
|
status: null,
|
||||||
|
getItems: _ => null);
|
||||||
|
|
||||||
|
Assert.NotNull(descriptor.Validator);
|
||||||
|
Assert.NotNull(descriptor.Validator!.ValidateItem("not-an-ip", Array.Empty<string>()));
|
||||||
|
Assert.Null(descriptor.Validator.ValidateItem("10.0.0.0/24", Array.Empty<string>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -216,6 +216,8 @@ public static class EffectiveConfigOptionKindMap
|
|||||||
/// Maps dnsmasq option names to parser behavior (LastWins / Flag / Multi). Used by ConfigSetCache so it
|
/// Maps dnsmasq option names to parser behavior (LastWins / Flag / Multi). Used by ConfigSetCache so it
|
||||||
/// dispatches to GetLastValue, GetFlag, or GetMultiValue from one place. Special cases (NoHosts value,
|
/// dispatches to GetLastValue, GetFlag, or GetMultiValue from one place. Special cases (NoHosts value,
|
||||||
/// AddnHosts, DhcpLeaseFilePath) remain explicit in the cache.
|
/// AddnHosts, DhcpLeaseFilePath) remain explicit in the cache.
|
||||||
|
/// For special options, behavior is sourced from <see cref="EffectiveConfigSpecialOptionSemantics"/>
|
||||||
|
/// to keep parse/write/validation semantics centralized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class EffectiveConfigParserBehaviorMap
|
public static class EffectiveConfigParserBehaviorMap
|
||||||
{
|
{
|
||||||
@@ -400,6 +402,7 @@ public static class EffectiveConfigParserBehaviorMap
|
|||||||
|
|
||||||
/// <summary>Returns LastWins, Flag, or Multi for the given option name; defaults to LastWins if unknown.</summary>
|
/// <summary>Returns LastWins, Flag, or Multi for the given option name; defaults to LastWins if unknown.</summary>
|
||||||
public static EffectiveConfigParserBehavior GetBehavior(string optionName) =>
|
public static EffectiveConfigParserBehavior GetBehavior(string optionName) =>
|
||||||
BehaviorByOptionName.TryGetValue(optionName, out var b) ? b : EffectiveConfigParserBehavior.LastWins;
|
EffectiveConfigSpecialOptionSemantics.TryGetSemantics(optionName)?.ParserBehavior
|
||||||
|
?? (BehaviorByOptionName.TryGetValue(optionName, out var b) ? b : EffectiveConfigParserBehavior.LastWins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-13
@@ -13,9 +13,15 @@ public sealed record OptionSemantics(
|
|||||||
string OptionName,
|
string OptionName,
|
||||||
EffectiveConfigParserBehavior ParserBehavior,
|
EffectiveConfigParserBehavior ParserBehavior,
|
||||||
EffectiveConfigWriteBehavior WriteBehavior,
|
EffectiveConfigWriteBehavior WriteBehavior,
|
||||||
EffectiveConfigSingleValueValidator? Validator
|
EffectiveConfigSingleValueValidator? SingleValueValidator,
|
||||||
|
EffectiveConfigMultiItemValidator? MultiItemValidator
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for validating one item in a multi-value option editor.
|
||||||
|
/// </summary>
|
||||||
|
public delegate string? EffectiveConfigMultiItemValidator(string? value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lookup for special-option semantics. Used by EffectiveConfigWriteSemantics and registry for validators.
|
/// Lookup for special-option semantics. Used by EffectiveConfigWriteSemantics and registry for validators.
|
||||||
/// Inverse-pair options (e.g. Do0x20Encode) have their (enabled key, disabled key) in a separate table.
|
/// Inverse-pair options (e.g. Do0x20Encode) have their (enabled key, disabled key) in a separate table.
|
||||||
@@ -29,57 +35,68 @@ public static class EffectiveConfigSpecialOptionSemantics
|
|||||||
DnsmasqConfKeys.UseStaleCache,
|
DnsmasqConfKeys.UseStaleCache,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
SpecialOptionValidators.ValidateUseStaleCache),
|
SpecialOptionValidators.ValidateUseStaleCache,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.AddMac] = new OptionSemantics(
|
[DnsmasqConfKeys.AddMac] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.AddMac,
|
DnsmasqConfKeys.AddMac,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
SpecialOptionValidators.ValidateAddMac),
|
SpecialOptionValidators.ValidateAddMac,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.AddSubnet] = new OptionSemantics(
|
[DnsmasqConfKeys.AddSubnet] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.AddSubnet,
|
DnsmasqConfKeys.AddSubnet,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
SpecialOptionValidators.ValidateAddSubnet),
|
SpecialOptionValidators.ValidateAddSubnet,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.Umbrella] = new OptionSemantics(
|
[DnsmasqConfKeys.Umbrella] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.Umbrella,
|
DnsmasqConfKeys.Umbrella,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
SpecialOptionValidators.ValidateUmbrella),
|
SpecialOptionValidators.ValidateUmbrella,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.Do0x20Encode] = new OptionSemantics(
|
[DnsmasqConfKeys.Do0x20Encode] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.Do0x20Encode,
|
DnsmasqConfKeys.Do0x20Encode,
|
||||||
EffectiveConfigParserBehavior.Flag,
|
EffectiveConfigParserBehavior.Flag,
|
||||||
EffectiveConfigWriteBehavior.InversePair,
|
EffectiveConfigWriteBehavior.InversePair,
|
||||||
Validator: null),
|
SingleValueValidator: null,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.ConnmarkAllowlistEnable] = new OptionSemantics(
|
[DnsmasqConfKeys.ConnmarkAllowlistEnable] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.ConnmarkAllowlistEnable,
|
DnsmasqConfKeys.ConnmarkAllowlistEnable,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
SpecialOptionValidators.ValidateConnmarkAllowlistEnable),
|
SpecialOptionValidators.ValidateConnmarkAllowlistEnable,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.DnssecCheckUnsigned] = new OptionSemantics(
|
[DnsmasqConfKeys.DnssecCheckUnsigned] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.DnssecCheckUnsigned,
|
DnsmasqConfKeys.DnssecCheckUnsigned,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
SpecialOptionValidators.ValidateDnssecCheckUnsigned),
|
SpecialOptionValidators.ValidateDnssecCheckUnsigned,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.Leasequery] = new OptionSemantics(
|
[DnsmasqConfKeys.Leasequery] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.Leasequery,
|
DnsmasqConfKeys.Leasequery,
|
||||||
EffectiveConfigParserBehavior.Multi,
|
EffectiveConfigParserBehavior.Multi,
|
||||||
EffectiveConfigWriteBehavior.MultiKeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.MultiKeyOnlyOrValue,
|
||||||
null),
|
SingleValueValidator: null,
|
||||||
|
SpecialOptionValidators.ValidateLeasequeryValue),
|
||||||
[DnsmasqConfKeys.DhcpGenerateNames] = new OptionSemantics(
|
[DnsmasqConfKeys.DhcpGenerateNames] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.DhcpGenerateNames,
|
DnsmasqConfKeys.DhcpGenerateNames,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
null),
|
SingleValueValidator: null,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.DhcpBroadcast] = new OptionSemantics(
|
[DnsmasqConfKeys.DhcpBroadcast] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.DhcpBroadcast,
|
DnsmasqConfKeys.DhcpBroadcast,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
null),
|
SingleValueValidator: null,
|
||||||
|
MultiItemValidator: null),
|
||||||
[DnsmasqConfKeys.BootpDynamic] = new OptionSemantics(
|
[DnsmasqConfKeys.BootpDynamic] = new OptionSemantics(
|
||||||
DnsmasqConfKeys.BootpDynamic,
|
DnsmasqConfKeys.BootpDynamic,
|
||||||
EffectiveConfigParserBehavior.LastWins,
|
EffectiveConfigParserBehavior.LastWins,
|
||||||
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
EffectiveConfigWriteBehavior.KeyOnlyOrValue,
|
||||||
null),
|
SingleValueValidator: null,
|
||||||
|
MultiItemValidator: null),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>Keys (enabled, disabled) for InversePair options only. Used by write path and readonly hints.</summary>
|
/// <summary>Keys (enabled, disabled) for InversePair options only. Used by write path and readonly hints.</summary>
|
||||||
@@ -103,5 +120,9 @@ public static class EffectiveConfigSpecialOptionSemantics
|
|||||||
|
|
||||||
/// <summary>Returns validator from semantics for special options; otherwise null.</summary>
|
/// <summary>Returns validator from semantics for special options; otherwise null.</summary>
|
||||||
public static EffectiveConfigSingleValueValidator? GetValidator(string optionName) =>
|
public static EffectiveConfigSingleValueValidator? GetValidator(string optionName) =>
|
||||||
TryGetSemantics(optionName)?.Validator;
|
TryGetSemantics(optionName)?.SingleValueValidator;
|
||||||
|
|
||||||
|
/// <summary>Returns per-item multi validator from semantics for special options; otherwise null.</summary>
|
||||||
|
public static EffectiveConfigMultiItemValidator? GetMultiItemValidator(string optionName) =>
|
||||||
|
TryGetSemantics(optionName)?.MultiItemValidator;
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-8
@@ -4,8 +4,8 @@ using DnsmasqWebUI.Models.Dnsmasq;
|
|||||||
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
|
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
|
||||||
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
|
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
|
||||||
using DnsmasqWebUI.Infrastructure.Services.EffectiveConfig.Abstractions;
|
using DnsmasqWebUI.Infrastructure.Services.EffectiveConfig.Abstractions;
|
||||||
using DnsmasqWebUI.Infrastructure.Services.EffectiveConfig.Validation;
|
|
||||||
using DnsmasqWebUI.Components.EffectiveConfig.CustomDisplays;
|
using DnsmasqWebUI.Components.EffectiveConfig.CustomDisplays;
|
||||||
|
using DnsmasqWebUI.Infrastructure.Services.EffectiveConfig.Validation;
|
||||||
|
|
||||||
namespace DnsmasqWebUI.Infrastructure.Services.EffectiveConfig;
|
namespace DnsmasqWebUI.Infrastructure.Services.EffectiveConfig;
|
||||||
|
|
||||||
@@ -103,19 +103,19 @@ public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragm
|
|||||||
|
|
||||||
// Key-only or key=value options: checkbox (On) + optional value input; with semantic validators.
|
// Key-only or key=value options: checkbox (On) + optional value input; with semantic validators.
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.UseStaleCache, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.UseStaleCache, typeof(KeyOnlyOrValueDisplay));
|
||||||
RegisterValidatedSingle(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.UseStaleCache, SpecialOptionValidators.ValidateUseStaleCache);
|
RegisterSemanticSingleValidator(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.UseStaleCache);
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddMac, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddMac, typeof(KeyOnlyOrValueDisplay));
|
||||||
RegisterValidatedSingle(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddMac, SpecialOptionValidators.ValidateAddMac);
|
RegisterSemanticSingleValidator(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddMac);
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddSubnet, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddSubnet, typeof(KeyOnlyOrValueDisplay));
|
||||||
RegisterValidatedSingle(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddSubnet, SpecialOptionValidators.ValidateAddSubnet);
|
RegisterSemanticSingleValidator(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.AddSubnet);
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.Umbrella, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.Umbrella, typeof(KeyOnlyOrValueDisplay));
|
||||||
RegisterValidatedSingle(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.Umbrella, SpecialOptionValidators.ValidateUmbrella);
|
RegisterSemanticSingleValidator(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.Umbrella);
|
||||||
|
|
||||||
// connmark-allowlist-enable, dnssec-check-unsigned: key-only or key=value with validation.
|
// connmark-allowlist-enable, dnssec-check-unsigned: key-only or key=value with validation.
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.ConnmarkAllowlistEnable, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.ConnmarkAllowlistEnable, typeof(KeyOnlyOrValueDisplay));
|
||||||
RegisterValidatedSingle(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.ConnmarkAllowlistEnable, SpecialOptionValidators.ValidateConnmarkAllowlistEnable);
|
RegisterSemanticSingleValidator(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.ConnmarkAllowlistEnable);
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.DnssecCheckUnsigned, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.DnssecCheckUnsigned, typeof(KeyOnlyOrValueDisplay));
|
||||||
RegisterValidatedSingle(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.DnssecCheckUnsigned, SpecialOptionValidators.ValidateDnssecCheckUnsigned);
|
RegisterSemanticSingleValidator(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.DnssecCheckUnsigned);
|
||||||
|
|
||||||
// DHCP key-only-or-value options (optional value; no custom validator).
|
// DHCP key-only-or-value options (optional value; no custom validator).
|
||||||
RegisterComponent(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpGenerateNames, typeof(KeyOnlyOrValueDisplay));
|
RegisterComponent(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpGenerateNames, typeof(KeyOnlyOrValueDisplay));
|
||||||
@@ -182,7 +182,7 @@ public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragm
|
|||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpOptsfile);
|
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpOptsfile);
|
||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpHostsdir);
|
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpHostsdir);
|
||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpOptsdir);
|
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpOptsdir);
|
||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.Leasequery);
|
RegisterSemanticMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.Leasequery);
|
||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpRelay);
|
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpRelay);
|
||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpCircuitid);
|
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpCircuitid);
|
||||||
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpRemoteid);
|
RegisterMultiDescriptor(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpRemoteid);
|
||||||
@@ -273,6 +273,21 @@ public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragm
|
|||||||
validator);
|
validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterSemanticSingleValidator(string sectionId, string optionName)
|
||||||
|
{
|
||||||
|
var validator = EffectiveConfigSpecialOptionSemantics.GetValidator(optionName);
|
||||||
|
if (validator is not null)
|
||||||
|
RegisterValidatedSingle(sectionId, optionName, validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterSemanticMultiDescriptor(string sectionId, string optionName, IMultiValueEditBehavior? behavior = null)
|
||||||
|
{
|
||||||
|
var validator = EffectiveConfigSpecialOptionSemantics.GetMultiItemValidator(optionName) is { } validate
|
||||||
|
? new DelegateMultiValueOptionValidator(validate)
|
||||||
|
: null;
|
||||||
|
RegisterMultiDescriptor(sectionId, optionName, behavior, validator);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public EffectiveConfigDescriptorFactory? GetDescriptorFactory(string sectionId, string optionName)
|
public EffectiveConfigDescriptorFactory? GetDescriptorFactory(string sectionId, string optionName)
|
||||||
{
|
{
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||||
|
|
||||||
|
namespace DnsmasqWebUI.Infrastructure.Services.EffectiveConfig.Validation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adapts a semantics multi-item validator delegate to <see cref="IMultiValueOptionValidator"/>.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DelegateMultiValueOptionValidator(EffectiveConfigMultiItemValidator validate)
|
||||||
|
: IMultiValueOptionValidator
|
||||||
|
{
|
||||||
|
public string? ValidateItem(string normalized, IReadOnlyList<string> current, int? editIndex = null) =>
|
||||||
|
validate(normalized);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user