From 52e7093c268d20c73fba5ce75ceb78916617bb42 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 20 May 2021 01:14:48 +0200 Subject: [PATCH] Allowing untyped sections in the config --- .../Controllers/PremissionValidator.cs | 2 +- Kyoo.Common/Models/ConfigurationReference.cs | 6 ++ Kyoo.Common/Module.cs | 14 +++++ Kyoo/Controllers/ConfigurationManager.cs | 62 ++++++++++++++++--- Kyoo/CoreModule.cs | 2 + Kyoo/Program.cs | 2 +- Kyoo/Views/ConfigurationApi.cs | 4 +- 7 files changed, 80 insertions(+), 12 deletions(-) diff --git a/Kyoo.Authentication/Controllers/PremissionValidator.cs b/Kyoo.Authentication/Controllers/PremissionValidator.cs index 62a4843b..ca3102ed 100644 --- a/Kyoo.Authentication/Controllers/PremissionValidator.cs +++ b/Kyoo.Authentication/Controllers/PremissionValidator.cs @@ -132,7 +132,7 @@ namespace Kyoo.Authentication } string permStr = $"{permission.ToLower()}.{kind.ToString()!.ToLower()}"; - string overallStr = $"{_group.ToString()}.{kind.ToString()!.ToLower()}"; + string overallStr = $"{_group.ToString().ToLower()}.{kind.ToString()!.ToLower()}"; AuthenticateResult res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); if (res.Succeeded) { diff --git a/Kyoo.Common/Models/ConfigurationReference.cs b/Kyoo.Common/Models/ConfigurationReference.cs index fab6f9d3..00d20b4c 100644 --- a/Kyoo.Common/Models/ConfigurationReference.cs +++ b/Kyoo.Common/Models/ConfigurationReference.cs @@ -87,5 +87,11 @@ namespace Kyoo.Models { return CreateReference(path, typeof(T)); } + + + public static ConfigurationReference CreateUntyped(string path) + { + return new(path, null); + } } } \ No newline at end of file diff --git a/Kyoo.Common/Module.cs b/Kyoo.Common/Module.cs index 0b5e0d04..a8a81b88 100644 --- a/Kyoo.Common/Module.cs +++ b/Kyoo.Common/Module.cs @@ -82,6 +82,20 @@ namespace Kyoo services.AddSingleton(confRef); return services; } + + /// + /// Add an editable configuration to the editable configuration list. + /// WARNING: this method allow you to add an unmanaged type. This type won't be editable. This can be used + /// for external libraries or variable arguments. + /// + /// The service collection to edit + /// The root path of the editable configuration. It should not be a nested type. + /// The given service collection is returned. + public static IServiceCollection AddUntypedConfiguration(this IServiceCollection services, string path) + { + services.AddSingleton(ConfigurationReference.CreateUntyped(path)); + return services; + } /// /// Get the public URL of kyoo using the given configuration instance. diff --git a/Kyoo/Controllers/ConfigurationManager.cs b/Kyoo/Controllers/ConfigurationManager.cs index c0a1340b..c0a63895 100644 --- a/Kyoo/Controllers/ConfigurationManager.cs +++ b/Kyoo/Controllers/ConfigurationManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.IO; using System.Linq; @@ -35,13 +36,30 @@ namespace Kyoo.Controllers _references = references.ToDictionary(x => x.Path, x => x.Type, StringComparer.OrdinalIgnoreCase); } + private Type GetType(string path) + { + path = path.Replace("__", ":"); + + // TODO handle lists and dictionaries. + if (_references.TryGetValue(path, out Type type)) + { + if (type != null) + return type; + throw new ArgumentException($"The configuration at {path} is not editable or readable."); + } + + string parent = path.Contains(':') ? path[..path.IndexOf(':')] : null; + if (parent != null && _references.TryGetValue(parent, out type) && type == null) + throw new ArgumentException($"The configuration at {path} is not editable or readable."); + throw new ItemNotFoundException($"No configuration exists for the name: {path}"); + } + /// public object GetValue(string path) { path = path.Replace("__", ":"); // TODO handle lists and dictionaries. - if (!_references.TryGetValue(path, out Type type)) - throw new ItemNotFoundException($"No configuration exists for the name: {path}"); + Type type = GetType(path); object ret = _configuration.GetValue(type, path); if (ret != null) return ret; @@ -55,8 +73,7 @@ namespace Kyoo.Controllers { path = path.Replace("__", ":"); // TODO handle lists and dictionaries. - if (!_references.TryGetValue(path, out Type type)) - throw new ItemNotFoundException($"No configuration exists for the name: {path}"); + Type type = GetType(path); if (typeof(T).IsAssignableFrom(type)) throw new InvalidCastException($"The type {typeof(T).Name} is not valid for " + $"a resource of type {type.Name}."); @@ -67,8 +84,7 @@ namespace Kyoo.Controllers public async Task EditValue(string path, object value) { path = path.Replace("__", ":"); - if (!_references.TryGetValue(path, out Type type)) - throw new ItemNotFoundException($"No configuration exists for the name: {path}"); + Type type = GetType(path); value = JObject.FromObject(value).ToObject(type); if (value == null) throw new ArgumentException("Invalid value format."); @@ -87,18 +103,48 @@ namespace Kyoo.Controllers /// /// The configuration to transform /// A strongly typed representation of the configuration. + [SuppressMessage("ReSharper", "RedundantJumpStatement")] private ExpandoObject ToObject(IConfiguration config) { ExpandoObject obj = new(); foreach (IConfigurationSection section in config.GetChildren()) { - if (!_references.TryGetValue(section.Path, out Type type)) + try + { + Type type = GetType(section.Path); + obj.TryAdd(section.Key, section.Get(type)); + } + catch (ArgumentException) + { + obj.TryAdd(section.Key, ToUntyped(section)); + } + catch + { continue; - obj.TryAdd(section.Key, section.Get(type)); + } } return obj; } + + /// + /// Transform the configuration section in nested expando objects. + /// + /// The section to convert + /// The converted section + private static object ToUntyped(IConfigurationSection config) + { + ExpandoObject obj = new(); + + foreach (IConfigurationSection section in config.GetChildren()) + { + obj.TryAdd(section.Key, ToUntyped(section)); + } + + if (!obj.Any()) + return config.Value; + return obj; + } } } \ No newline at end of file diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs index 726ed36a..34e24e75 100644 --- a/Kyoo/CoreModule.cs +++ b/Kyoo/CoreModule.cs @@ -99,6 +99,8 @@ namespace Kyoo services.AddConfiguration(TaskOptions.Path); services.Configure(_configuration.GetSection(MediaOptions.Path)); services.AddConfiguration(MediaOptions.Path); + services.AddUntypedConfiguration("database"); + services.AddUntypedConfiguration("logging"); services.AddControllers() .AddNewtonsoftJson(x => diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index db83cfd9..12227266 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -109,7 +109,7 @@ namespace Kyoo .UseKestrel(options => { options.AddServerHeader = false; }) .UseIIS() .UseIISIntegration() - .UseUrls(configuration.GetValue("basics:urls")) + .UseUrls(configuration.GetValue("basics:url")) .UseStartup(); } } diff --git a/Kyoo/Views/ConfigurationApi.cs b/Kyoo/Views/ConfigurationApi.cs index 13d7f5ca..7830d786 100644 --- a/Kyoo/Views/ConfigurationApi.cs +++ b/Kyoo/Views/ConfigurationApi.cs @@ -71,9 +71,9 @@ namespace Kyoo.Api { return NotFound(); } - catch (ArgumentException) + catch (ArgumentException ex) { - return BadRequest(); + return BadRequest(ex.Message); } } }