Add event-driven quick action dispatch

This commit is contained in:
Drechsler, Meik
2026-07-22 11:57:32 +02:00
parent fb45f1c42b
commit 9bd3896ba0
20 changed files with 591 additions and 139 deletions

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
using F4SD.ActionConnector.Payloads;
namespace F4SD.ActionConnector.Execution
{
/// <summary>
/// Resolves template variables such as {{Case.Id}} or {{Case.ClosedAt:yyyy-MM-ddTHH:mm:ssZ}}
/// against a payload object.
///
/// Variable format: {{ObjectName.PropertyName[:FormatSpecifier]}}
/// </summary>
internal static class PayloadVariableResolver
{
private static readonly Regex VariablePattern =
new Regex(@"\{\{(?<obj>[^.}]+)\.(?<prop>[^:}]+)(?::(?<fmt>[^}]+))?\}\}",
RegexOptions.Compiled);
/// <summary>
/// Returns a new dictionary with every value in <paramref name="rawParameters"/> having
/// its template variables replaced by the corresponding payload property values.
/// Pure single-variable templates (e.g. <c>{{Case.ClosedAt}}</c>) yield the raw typed
/// object; mixed or formatted templates yield a resolved string.
/// </summary>
internal static IDictionary<string, object> Resolve(
IDictionary<string, string> rawParameters,
PayloadBase payload)
{
var resolved = new Dictionary<string, object>(rawParameters.Count);
foreach (var pair in rawParameters)
resolved[pair.Key] = ResolveValue(pair.Value, payload);
return resolved;
}
private static object ResolveValue(string template, PayloadBase payload)
{
var match = VariablePattern.Match(template);
// Pure single variable with no format specifier → return raw object
if (match.Success && match.Value == template && !match.Groups["fmt"].Success)
return ResolveRawProperty(match, payload);
// Mixed template, literal, or explicit format specifier → return resolved string
return ResolveString(template, payload);
}
private static object ResolveRawProperty(Match match, PayloadBase payload)
{
string propertyName = match.Groups["prop"].Value;
PropertyInfo property = payload.GetType().GetProperty(
propertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (property == null)
return match.Value;
return property.GetValue(payload);
}
private static string ResolveString(string template, PayloadBase payload)
{
return VariablePattern.Replace(template, match => ResolveMatch(match, payload));
}
private static string ResolveMatch(Match match, PayloadBase payload)
{
string propertyName = match.Groups["prop"].Value;
string formatSpecifier = match.Groups["fmt"].Success ? match.Groups["fmt"].Value : null;
PropertyInfo property = payload.GetType().GetProperty(
propertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (property == null)
return match.Value;
object value = property.GetValue(payload);
if (value == null)
return string.Empty;
if (formatSpecifier != null && value is IFormattable formattable)
return formattable.ToString(formatSpecifier, CultureInfo.InvariantCulture);
return value.ToString();
}
}
}