public async Task <ActionResult> GetAsync([FromRoute] string path) { var allParams = PartitionByKey(HttpContext.Request.Query.ToDictionary(x => x.Key, x => x.Value), x => x.StartsWith("$")); var modifiers = allParams.Item1; var isFlatten = modifiers.TryGetValue("$flatten").Select(x => bool.Parse(x.First())).IfNone(false); var includeErrors = modifiers.TryGetValue("$includeErrors").Select(x => bool.Parse(x.First())).IfNone(false); var ignoreKeyTypes = modifiers.TryGetValue("$ignoreKeyTypes").Select(x => bool.Parse(x.First())).IfNone(false); var includePaths = modifiers.TryGetValue("$include").Select(x => x.ToArray()).IfNone(new string[] {}); var translateValue = ignoreKeyTypes ? (TranslateValue)TranslateValueToString : (x => x.Value); IReadOnlyDictionary <string, JsonValue> contextParams = allParams.Item2.ToDictionary(x => x.Key, x => x.Value.Count == 1 ? JsonValue.NewString(x.Value.ToString()) : JsonValue.NewArray(x.Value.Map(t => JsonValue.NewString(t)).ToArray()), StringComparer.OrdinalIgnoreCase); var identities = new IdentityHashSet(contextParams.Where(x => !x.Key.Contains(".")).Select(x => new Identity(x.Key, x.Value.AsString()))); if (!_checkAccess(User, path, identities)) { return(Forbid()); } GetLoadedContextByIdentityType contextProps = identityType => key => contextParams.TryGetValue($"{identityType}.{key}"); var root = ConfigurationPath.New(path); var query = GetQuery(root, includePaths); var values = await _tweek.GetContextAndCalculate(query, identities, _contextDriver, contextProps); var errors = values.Where(x => x.Value.Exception != null).ToDictionary(x => x.Key, x => x.Value.Exception.Message); Response.Headers.Add("X-Error-Count", errors.Count.ToString()); object result = null; if (root.IsScan) { var relativeData = values.Where(x => x.Value.Exception == null).ToDictionary(x => x.Key.ToRelative(root), x => x.Value); result = !isFlatten ? TreeResult.From(relativeData, translateValue) : relativeData.ToDictionary(x => x.Key.ToString(), x => translateValue(x.Value)); } else if (values.TryGetValue(root, out var value) && value.Exception == null) { result = ignoreKeyTypes ? TranslateValueToString(value) : value.Value; } if (!includeErrors) { return(Json(result)); } return(Json(new Dictionary <string, object> { { "data", result }, { "errors", errors } })); }
internal static GetLoadedContextByIdentityType Memoize(GetLoadedContextByIdentityType c) { var list = new Dictionary <string, GetContextValue>(); return((t) => { if (!list.ContainsKey(t)) { list[t] = Core.Context.ContextHelpers.Memoize(c(t)); } return list[t]; }); }
public static GetRuleValue GetRulesEvaluator(IdentityHashSet identities, GetLoadedContextByIdentityType contextByIdentity, GetRule getRule) { var identityTypes = identities.Select(x => x.Type).ToArray(); var flattenContext = ContextHelpers.FlattenLoadedContext(contextByIdentity); GetRuleValue getRuleValue = null; GetContextValue recursiveContext = key => { if (key.StartsWith("@@key:")) { key = key.Replace("@@key:", "keys."); } if (!key.StartsWith("keys.")) { return(Option <JsonValue> .None); } var path = new ConfigurationPath(key.Split('.')[1]); return(getRuleValue(path).Map(x => x.Value)); }; var context = ContextHelpers.Merge(flattenContext, recursiveContext); getRuleValue = Memoize(path => { try { foreach (var identity in identityTypes) { var fixedResult = ContextHelpers.GetFixedConfigurationContext(context, identity)(path); if (fixedResult.IsSome) { return(fixedResult); } } return(getRule(path).Bind(x => x.GetValue(context))); } catch (Exception e) { return(ConfigurationValue.Error(e)); } }); return(getRuleValue); }
public async Task <ActionResult> GetAsync([FromRoute] string path) { var allParams = PartitionByKey(HttpContext.Request.Query.ToDictionary(x => x.Key, x => x.Value), x => x.StartsWith("$")); var modifiers = allParams.Item1; var isFlatten = modifiers.TryGetValue("$flatten").Select(x => bool.Parse(x.First())).IfNone(false); var ignoreKeyTypes = modifiers.TryGetValue("$ignoreKeyTypes").Select(x => bool.Parse(x.First())).IfNone(false); var includePaths = modifiers.TryGetValue("$include").Select(x => x.ToArray()).IfNone(new string[] {}); var translateValue = ignoreKeyTypes ? (TranslateValue)TranslateValueToString : (x => x.Value); IReadOnlyDictionary <string, JsonValue> contextParams = allParams.Item2.ToDictionary(x => x.Key, x => JsonValue.NewString(x.Value.ToString()), StringComparer.OrdinalIgnoreCase); var identities = new IdentityHashSet(contextParams.Where(x => !x.Key.Contains(".")).Select(x => new Identity(x.Key, x.Value.AsString()))); if (!_checkAccess(User, path, identities)) { return(Forbid()); } GetLoadedContextByIdentityType contextProps = identityType => key => contextParams.TryGetValue($"{identityType}.{key}"); var root = ConfigurationPath.New(path); var query = GetQuery(root, includePaths); var data = await _tweek.GetContextAndCalculate(query, identities, _contextDriver, contextProps); if (root.IsScan) { var relativeData = data.ToDictionary(x => x.Key.ToRelative(root), x => x.Value); return(Json(!isFlatten ? (TreeResult.From(relativeData, translateValue)) : relativeData.ToDictionary(x => x.Key.ToString(), x => translateValue(x.Value)))); } return(data.Select(x => ignoreKeyTypes ? (object)x.Value.Value.AsString() : x.Value.Value) .FirstOrNone() .Match(x => Json(x), () => Json(null))); }
public static GetLoadedContextByIdentityType AddSystemContext(GetLoadedContextByIdentityType context) { var timeUtc = Option <JsonValue> .Some(JsonValue.NewString(DateTime.UtcNow.ToString("u"))); return(Fallback(context, type => { if (type.Equals("system", StringComparison.CurrentCultureIgnoreCase)) { return (key => { switch (key) { case "time_utc": return timeUtc; default: return Option <JsonValue> .None; } }); } return (key => Option <JsonValue> .None); })); }
public static Dictionary <ConfigurationPath, ConfigurationValue> Calculate(this ITweek tweek, ConfigurationPath pathQuery, HashSet <Identity> identities, GetLoadedContextByIdentityType context, ConfigurationPath[] includeFixedPaths = null) { return(tweek.Calculate(new[] { pathQuery }, identities, context, includeFixedPaths)); }
public static async Task <Dictionary <ConfigurationPath, ConfigurationValue> > GetContextAndCalculate(this ITweek tweek, ICollection <ConfigurationPath> pathQuery, HashSet <Identity> identities, IContextReader contextDriver, GetLoadedContextByIdentityType externalContext = null) { var allContextData = (await Task.WhenAll(identities .Select(async identity => new { Identity = identity, Context = new Dictionary <string, JsonValue>(await contextDriver.GetContext(identity), StringComparer.OrdinalIgnoreCase) }))) .ToDictionary(x => x.Identity, x => x.Context); externalContext = externalContext ?? ContextHelpers.EmptyContextByIdentityType; var loadedContexts = ContextHelpers.GetContextRetrieverByType(ContextHelpers.LoadContexts(allContextData), identities); var context = ContextHelpers.AddSystemContext(ContextHelpers.Fallback(externalContext, loadedContexts)); var contextPaths = pathQuery.Any(x => x.IsScan) ? allContextData.Values.SelectMany(x => x.Keys) .Where(x => x.Contains("@fixed:")) .Select(x => x.Split(':')[1]) .Select(ConfigurationPath.New).ToArray() : null; return(tweek.Calculate(pathQuery, identities, context, contextPaths)); }
public static Task <Dictionary <ConfigurationPath, ConfigurationValue> > GetContextAndCalculate(this ITweek tweek, ConfigurationPath pathQuery, HashSet <Identity> identities, IContextReader contextDriver, GetLoadedContextByIdentityType externalContext = null) { return(tweek.GetContextAndCalculate(new[] { pathQuery }, identities, contextDriver, externalContext)); }
internal static GetContextValue FlattenLoadedContext(GetLoadedContextByIdentityType getLoadedContext) { return(fullKey => SplitFullKey(fullKey).Bind(fk => getLoadedContext(fk.IdentityType)(fk.Key))); }