Creating a configuration manager with a start of edit

This commit is contained in:
Zoe Roux 2021-05-18 17:55:48 +02:00
parent 0f00c22f7f
commit d115797dd7
9 changed files with 128 additions and 58 deletions

View File

@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
using Kyoo.Models;
using Kyoo.Models.Exceptions;
namespace Kyoo.Controllers
{
/// <summary>
/// A class to ease configuration management. This work WITH Microsoft's package, you can still use IOptions patterns
/// to access your options, this manager ease dynamic work and editing.
/// It works with <see cref="ConfigurationReference"/>.
/// </summary>
public interface IConfigurationManager
{
/// <summary>
/// Edit the value of a setting using it's path. Save it to the json file.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__'</param>
/// <param name="value">The new value of the resource</param>
/// <typeparam name="T">The type of the resource</typeparam>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
Task EditValue<T>(string path, T value);
/// <summary>
/// Edit the value of a setting using it's path. Save it to the json file.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__'</param>
/// <param name="value">The new value of the resource</param>
/// <param name="type">The type of the resource</param>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
Task EditValue(string path, object value, Type type);
}
}

View File

@ -1,9 +0,0 @@
namespace Kyoo.Models
{
public class Account
{
public string Username { get; set; }
public string Email { get; set; }
public string Picture { get; set; }
}
}

View File

@ -1,4 +0,0 @@
namespace Kyoo.Models
{
public enum ImageType { Poster, Background, Logo }
}

View File

@ -10,7 +10,6 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Models;
using Kyoo.Models.Attributes;
namespace Kyoo
@ -33,7 +32,7 @@ namespace Kyoo
}
/// <summary>
/// Get the name of a property. Usfull for selectors as members ex: Load(x => x.Shows)
/// Get the name of a property. Useful for selectors as members ex: Load(x => x.Shows)
/// </summary>
/// <param name="ex">The expression</param>
/// <returns>The name of the expression</returns>
@ -71,10 +70,10 @@ namespace Kyoo
}
/// <summary>
/// Slugify a string (Replace spaces by -, Uniformise accents é -> e)
/// Slugify a string (Replace spaces by -, Uniformize accents é -> e)
/// </summary>
/// <param name="str">The string to slugify</param>
/// <returns>The slugified string</returns>
/// <returns>The slug version of the given string</returns>
public static string ToSlug(string str)
{
if (str == null)
@ -98,37 +97,12 @@ namespace Kyoo
str = Regex.Replace(str, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return str;
}
/// <summary>
/// Set the image of a show using the <see cref="ImageType"/> type.
/// </summary>
/// <param name="show">The owner of the image</param>
/// <param name="imgUrl">The url of the image</param>
/// <param name="type">The type of the image</param>
public static void SetImage(Show show, string imgUrl, ImageType type)
{
switch(type)
{
case ImageType.Poster:
show.Poster = imgUrl;
break;
case ImageType.Logo:
show.Logo = imgUrl;
break;
case ImageType.Background:
show.Backdrop = imgUrl;
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
}
/// <summary>
/// Merge two lists, can keep duplicates or remove them.
/// </summary>
/// <param name="first">The first enumarble to merge</param>
/// <param name="second">The second enumerable to merge, if items from this list are equals to one from the first, they are not keeped</param>
/// <param name="first">The first enumerable to merge</param>
/// <param name="second">The second enumerable to merge, if items from this list are equals to one from the first, they are not kept</param>
/// <param name="isEqual">Equality function to compare items. If this is null, duplicated elements are kept</param>
/// <returns>The two list merged as an array</returns>
public static T[] MergeLists<T>(IEnumerable<T> first,
@ -150,7 +124,7 @@ namespace Kyoo
/// At the end, the OnMerge method of first will be called if first is a <see cref="IOnMerge"/>
/// </summary>
/// <param name="first">The object to assign</param>
/// <param name="second">The object containg new values</param>
/// <param name="second">The object containing new values</param>
/// <typeparam name="T">Fields of T will be used</typeparam>
/// <returns><see cref="first"/></returns>
public static T Assign<T>(T first, T second)
@ -339,7 +313,7 @@ namespace Kyoo
/// </summary>
/// <param name="type">The type to check</param>
/// <param name="genericType">The generic type to check against (Only generic types are supported like typeof(IEnumerable&lt;&gt;).</param>
/// <returns>The generic definition of genericType that type inherit or null if type does not implement the genric type.</returns>
/// <returns>The generic definition of genericType that type inherit or null if type does not implement the generic type.</returns>
/// <exception cref="ArgumentNullException"><see cref="type"/> and <see cref="genericType"/> can't be null</exception>
/// <exception cref="ArgumentException"><see cref="genericType"/> must be a generic type</exception>
public static Type GetGenericDefinition([NotNull] Type type, [NotNull] Type genericType)

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Kyoo.Api;
using Kyoo.Models;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
namespace Kyoo.Controllers
{
public class ConfigurationManager : IConfigurationManager
{
/// <summary>
/// The configuration to retrieve and edit.
/// </summary>
private readonly IConfiguration _configuration;
/// <summary>
/// The strongly typed list of options
/// </summary>
private readonly Dictionary<string, Type> _references;
/// <summary>
/// Create a new <see cref="ConfigurationApi"/> using the given configuration.
/// </summary>
/// <param name="configuration">The configuration to use.</param>
/// <param name="references">The strongly typed option list.</param>
public ConfigurationManager(IConfiguration configuration, IEnumerable<ConfigurationReference> references)
{
_configuration = configuration;
_references = references.ToDictionary(x => x.Path, x => x.Type, StringComparer.OrdinalIgnoreCase);
}
/// <inheritdoc />
public Task EditValue<T>(string path, T value)
{
return EditValue(path, value, typeof(T));
}
/// <inheritdoc />
public async Task EditValue(string path, object value, Type type)
{
JObject obj = JObject.FromObject(ToObject(_configuration));
// TODO allow path to change
await using StreamWriter writer = new("settings.json");
await writer.WriteAsync(obj.ToString());
}
/// <summary>
/// Transform a configuration to a strongly typed object (the root configuration is an <see cref="ExpandoObject"/>
/// but child elements are using strong types.
/// </summary>
/// <param name="config">The configuration to transform</param>
/// <returns>A strongly typed representation of the configuration.</returns>
private object ToObject(IConfiguration config)
{
ExpandoObject obj = new();
foreach (IConfigurationSection section in config.GetChildren())
{
if (!_references.TryGetValue(section.Path, out Type type))
continue;
obj.TryAdd(section.Key, section.Get(type));
}
return obj;
}
}
}

View File

@ -99,6 +99,7 @@ namespace Kyoo
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
});
services.AddSingleton<IConfigurationManager, ConfigurationManager>();
services.AddSingleton<IFileManager, FileManager>();
services.AddSingleton<ITranscoder, Transcoder>();
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models;
using Kyoo.Models.Permissions;
using Microsoft.AspNetCore.Mvc;
@ -16,6 +18,8 @@ namespace Kyoo.Api
[ApiController]
public class ConfigurationApi : Controller
{
private readonly ConfigurationManager _manager;
/// <summary>
/// The configuration to retrieve and edit.
/// </summary>
@ -31,8 +35,9 @@ namespace Kyoo.Api
/// </summary>
/// <param name="configuration">The configuration to use.</param>
/// <param name="references">The strongly typed option list.</param>
public ConfigurationApi(IConfiguration configuration, IEnumerable<ConfigurationReference> references)
public ConfigurationApi(ConfigurationManager manager, IConfiguration configuration, IEnumerable<ConfigurationReference> references)
{
_manager = manager;
_configuration = configuration;
_references = references.ToDictionary(x => x.Path, x => x.Type, StringComparer.OrdinalIgnoreCase);
}
@ -70,16 +75,13 @@ namespace Kyoo.Api
/// <response code="404">No configuration exists for the given slug</response>
[HttpPut("{slug}")]
[Permission(nameof(ConfigurationApi), Kind.Admin)]
public ActionResult<object> EditConfiguration(string slug, [FromBody] object newValue)
public async Task<ActionResult<object>> EditConfiguration(string slug, [FromBody] object newValue)
{
slug = slug.Replace("__", ":");
if (!_references.TryGetValue(slug, out Type type))
return NotFound();
// object ret = _configuration.(type, slug);
// if (ret != null)
// return ret;
// object option = Activator.CreateInstance(type);
// _configuration.Bind(slug, option);
await _manager.EditValue(slug, newValue, type);
// await _configuration.SetValue(slug, newValue, type);
return newValue;
}
}

View File

@ -14,13 +14,13 @@ namespace Kyoo.Api
[Route("api/library")]
[Route("api/libraries")]
[ApiController]
[PartialPermission(nameof(LibraryAPI))]
public class LibraryAPI : CrudApi<Library>
[PartialPermission(nameof(LibraryApi))]
public class LibraryApi : CrudApi<Library>
{
private readonly ILibraryManager _libraryManager;
private readonly ITaskManager _taskManager;
public LibraryAPI(ILibraryManager libraryManager, ITaskManager taskManager, IConfiguration configuration)
public LibraryApi(ILibraryManager libraryManager, ITaskManager taskManager, IConfiguration configuration)
: base(libraryManager.LibraryRepository, configuration)
{
_libraryManager = libraryManager;

View File

@ -15,11 +15,11 @@ namespace Kyoo.Api
[Route("api/studios")]
[ApiController]
[PartialPermission(nameof(ShowApi))]
public class StudioAPI : CrudApi<Studio>
public class StudioApi : CrudApi<Studio>
{
private readonly ILibraryManager _libraryManager;
public StudioAPI(ILibraryManager libraryManager, IConfiguration config)
public StudioApi(ILibraryManager libraryManager, IConfiguration config)
: base(libraryManager.StudioRepository, config)
{
_libraryManager = libraryManager;