implement settings api
This commit is contained in:
@@ -1,25 +1,171 @@
|
||||
using EmbedIO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using EmbedIO;
|
||||
using EmbedIO.Routing;
|
||||
using EmbedIO.WebApi;
|
||||
using Swan;
|
||||
using Humanizer;
|
||||
using Torch.Views;
|
||||
using TorchRemote.Models.Responses;
|
||||
using TorchRemote.Models.Shared.Settings;
|
||||
using TorchRemote.Plugin.Abstractions.Controllers;
|
||||
using TorchRemote.Plugin.Utils;
|
||||
using StringExtensions = Swan.StringExtensions;
|
||||
|
||||
namespace TorchRemote.Plugin.Controllers;
|
||||
|
||||
public class SettingsController : WebApiController, ISettingsController
|
||||
{
|
||||
private const string RootPath = "/settings";
|
||||
|
||||
[Route(HttpVerbs.Get, $"{RootPath}/{{id}}")]
|
||||
public SettingInfoResponse Get(Guid id)
|
||||
[Route(HttpVerbs.Get, $"{RootPath}/{{fullName}}")]
|
||||
public SettingInfoResponse Get(string fullName)
|
||||
{
|
||||
if (!Statics.SettingManager.Settings.TryGetValue(id, out var setting))
|
||||
throw HttpException.NotFound($"Setting with id {id} not found", id);
|
||||
if (!Statics.SettingManager.Settings.TryGetValue(fullName, out var setting))
|
||||
throw HttpException.NotFound($"Setting with fullName {fullName} not found", fullName);
|
||||
|
||||
return new(setting.Name.Humanize(), setting.Properties.Select(b =>
|
||||
new SettingPropertyInfo(b.DisplayInfo?.Name ?? b.Name.Humanize(),
|
||||
b.DisplayInfo?.Description, b.DisplayInfo?.Order, b.TypeId))
|
||||
.ToArray());
|
||||
return new(StringExtensions.Humanize(setting.Name), setting.Schema, setting
|
||||
.Type.GetProperties(
|
||||
BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(b => setting.IncludeDisplayOnly &&
|
||||
b.HasAttribute<DisplayAttribute>())
|
||||
.Select(b =>
|
||||
{
|
||||
var attr = b.GetCustomAttribute<DisplayAttribute>();
|
||||
return new SettingPropertyInfo(
|
||||
attr?.Name ?? StringExtensions.Humanize(b.Name),
|
||||
Statics.SerializerOptions
|
||||
.PropertyNamingPolicy!.ConvertName(b.Name),
|
||||
attr?.Description,
|
||||
attr?.Order is 0 or null ? null : attr.Order);
|
||||
}).ToArray());
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Get, $"{RootPath}/{{fullName}}/values")]
|
||||
public IEnumerable<PropertyBase> GetValues(string fullName, [JsonData] IEnumerable<string> propertyNames)
|
||||
{
|
||||
if (!Statics.SettingManager.Settings.TryGetValue(fullName, out var setting))
|
||||
throw HttpException.NotFound($"Setting with fullName {fullName} not found", fullName);
|
||||
|
||||
return propertyNames.Select(name =>
|
||||
{
|
||||
var propInfo =
|
||||
setting.Type.GetProperty(name.Pascalize(), BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
if (propInfo is null)
|
||||
throw HttpException.NotFound("Property not found", name);
|
||||
|
||||
var type = propInfo!.PropertyType;
|
||||
var value = propInfo.GetValue(setting.Value);
|
||||
|
||||
return type switch
|
||||
{
|
||||
_ when type == typeof(int) || type == typeof(int?) => (PropertyBase)new IntegerProperty(name, (int?)value),
|
||||
_ when type == typeof(string) => new StringProperty(name, (string?)value),
|
||||
_ when type.IsPrimitive => new NumberProperty(name, value is null ? null : (double?)Convert.ChangeType(value, typeof(double))),
|
||||
_ when type == typeof(DateTime) || type == typeof(DateTime?) => new DateTimeProperty(
|
||||
name, (DateTime?)value),
|
||||
_ when type == typeof(TimeSpan) || type == typeof(TimeSpan?) => new DurationProperty(
|
||||
name, (TimeSpan?)value),
|
||||
_ when type.IsEnum || Nullable.GetUnderlyingType(type)?.IsEnum == true => new EnumProperty(
|
||||
name, Enum.GetName(Nullable.GetUnderlyingType(type) ?? type, value)!),
|
||||
_ when type == typeof(Guid) || type == typeof(Guid?) => new UuidProperty(
|
||||
name, (Guid?)value),
|
||||
_ when type == typeof(Uri) => new UriProperty(name, (Uri?)value),
|
||||
_ when type.IsClass => new ObjectProperty(
|
||||
name, JsonSerializer.SerializeToElement(value, type, Statics.SerializerOptions)),
|
||||
_ => throw HttpException.NotFound("Property type not found", name),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Route(HttpVerbs.Patch, $"{RootPath}/{{fullName}}/values")]
|
||||
public int Patch(string fullName, [JsonData] IEnumerable<PropertyBase> properties)
|
||||
{
|
||||
if (!Statics.SettingManager.Settings.TryGetValue(fullName, out var setting))
|
||||
throw HttpException.NotFound($"Setting with fullName {fullName} not found", fullName);
|
||||
|
||||
return properties.Select(property =>
|
||||
{
|
||||
void Throw() => throw HttpException.BadRequest("Invalid value", property);
|
||||
|
||||
var propInfo =
|
||||
setting.Type.GetProperty(property.Name.Pascalize(), BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
if (propInfo is null) Throw();
|
||||
|
||||
var type = propInfo!.PropertyType;
|
||||
var instance = setting.Value;
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case BooleanProperty booleanProperty when type == typeof(bool):
|
||||
if (booleanProperty.Value is null) Throw();
|
||||
propInfo.SetValue(instance, booleanProperty.Value!.Value);
|
||||
break;
|
||||
case BooleanProperty booleanProperty when type == typeof(bool?):
|
||||
propInfo.SetValue(instance, booleanProperty.Value);
|
||||
break;
|
||||
case DateTimeProperty dateTimeProperty when type == typeof(DateTime):
|
||||
if (dateTimeProperty.Value is null) Throw();
|
||||
propInfo.SetValue(instance, dateTimeProperty.Value!.Value);
|
||||
break;
|
||||
case DateTimeProperty dateTimeProperty when type == typeof(DateTime?):
|
||||
propInfo.SetValue(instance, dateTimeProperty.Value);
|
||||
break;
|
||||
case DurationProperty durationProperty when type == typeof(TimeSpan):
|
||||
if (durationProperty.Value is null) Throw();
|
||||
propInfo.SetValue(instance, durationProperty.Value!.Value);
|
||||
break;
|
||||
case DurationProperty durationProperty when type == typeof(TimeSpan?):
|
||||
propInfo.SetValue(instance, durationProperty.Value);
|
||||
break;
|
||||
case EnumProperty enumProperty when type.IsEnum:
|
||||
propInfo.SetValue(instance, Enum.Parse(type, enumProperty.Value, true));
|
||||
break;
|
||||
case IntegerProperty integerProperty when type == typeof(int):
|
||||
if (integerProperty.Value is null) Throw();
|
||||
propInfo.SetValue(instance, integerProperty.Value!.Value);
|
||||
break;
|
||||
case IntegerProperty integerProperty when type == typeof(int?):
|
||||
propInfo.SetValue(instance, integerProperty.Value);
|
||||
break;
|
||||
case NumberProperty numberProperty when type.IsPrimitive:
|
||||
if (numberProperty.Value is null) Throw();
|
||||
propInfo.SetValue(
|
||||
instance,
|
||||
type != typeof(double)
|
||||
? Convert.ChangeType(numberProperty.Value!.Value, type)
|
||||
: numberProperty.Value!.Value);
|
||||
break;
|
||||
case NumberProperty numberProperty when Nullable.GetUnderlyingType(type)?.IsPrimitive == true:
|
||||
propInfo.SetValue(
|
||||
instance,
|
||||
type != typeof(double?)
|
||||
? Convert.ChangeType(numberProperty.Value, type)
|
||||
: numberProperty.Value);
|
||||
break;
|
||||
case ObjectProperty objectProperty when type.IsClass:
|
||||
propInfo.SetValue(instance, objectProperty.Value.Deserialize(type, Statics.SerializerOptions));
|
||||
break;
|
||||
case StringProperty stringProperty when type == typeof(string):
|
||||
propInfo.SetValue(instance, stringProperty.Value);
|
||||
break;
|
||||
case UriProperty uriProperty when type == typeof(Uri):
|
||||
propInfo.SetValue(instance, uriProperty.Value);
|
||||
break;
|
||||
case UuidProperty uuidProperty when type == typeof(Guid):
|
||||
if (uuidProperty.Value is null) Throw();
|
||||
propInfo.SetValue(instance, uuidProperty.Value!.Value);
|
||||
break;
|
||||
case UuidProperty uuidProperty when type == typeof(Guid?):
|
||||
propInfo.SetValue(instance, uuidProperty.Value);
|
||||
break;
|
||||
default:
|
||||
Throw();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}).Count();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user