Made implementation api cleaner
This commit is contained in:
parent
d55490dd51
commit
e8706cad1c
20 changed files with 139 additions and 131 deletions
|
@ -1,5 +1,6 @@
|
|||
using Moonlight.App.Database.Entities.Store;
|
||||
using Moonlight.App.Models.Abstractions;
|
||||
using Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
namespace Moonlight.App.Actions.Dummy;
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System.ComponentModel;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Extensions.Attributes;
|
||||
|
||||
namespace Moonlight.App.Actions.Dummy;
|
||||
|
||||
|
|
25
Moonlight/App/Actions/Dummy/DummyServiceDefinition.cs
Normal file
25
Moonlight/App/Actions/Dummy/DummyServiceDefinition.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using Moonlight.App.Actions.Dummy.Layouts;
|
||||
using Moonlight.App.Actions.Dummy.Pages;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
namespace Moonlight.App.Actions.Dummy;
|
||||
|
||||
public class DummyServiceDefinition : ServiceDefinition
|
||||
{
|
||||
public override ServiceActions Actions => new DummyActions();
|
||||
public override Type ConfigType => typeof(DummyConfig);
|
||||
public override async Task BuildUserView(ServiceViewContext context)
|
||||
{
|
||||
context.Layout = ComponentHelper.FromType<DummyUser>();
|
||||
|
||||
await context.AddPage<DummyPage>("Demo", "/demo");
|
||||
}
|
||||
|
||||
public override Task BuildAdminView(ServiceViewContext context)
|
||||
{
|
||||
context.Layout = ComponentHelper.FromType<DummyAdmin>();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Moonlight.App.Actions.Dummy.Layouts;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.Store;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Models.Abstractions;
|
||||
|
||||
namespace Moonlight.App.Actions.Dummy;
|
||||
|
||||
public class DummyServiceImplementation : ServiceImplementation
|
||||
{
|
||||
public override ServiceActions Actions { get; } = new DummyActions();
|
||||
public override Type ConfigType { get; } = typeof(DummyConfig);
|
||||
|
||||
public override RenderFragment GetAdminLayout()
|
||||
{
|
||||
return ComponentHelper.FromType(typeof(DummyAdmin));
|
||||
}
|
||||
|
||||
public override RenderFragment GetUserLayout()
|
||||
{
|
||||
return ComponentHelper.FromType(typeof(DummyUser));
|
||||
}
|
||||
|
||||
public override ServiceUiPage[] GetUserPages(Service service, User user)
|
||||
{
|
||||
return Array.Empty<ServiceUiPage>();
|
||||
}
|
||||
|
||||
public override ServiceUiPage[] GetAdminPages(Service service, User user)
|
||||
{
|
||||
return Array.Empty<ServiceUiPage>();
|
||||
}
|
||||
}
|
|
@ -17,4 +17,7 @@ public static class ComponentHelper
|
|||
|
||||
builder.CloseComponent();
|
||||
};
|
||||
|
||||
public static RenderFragment FromType<T>(Action<Dictionary<string, object>>? buildAttributes = null) where T : ComponentBase =>
|
||||
FromType(typeof(T), buildAttributes);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using Moonlight.App.Database.Entities.Store;
|
||||
|
||||
namespace Moonlight.App.Models.Abstractions;
|
||||
|
||||
public abstract class ServiceActions
|
||||
{
|
||||
public abstract Task Create(IServiceProvider provider, Service service);
|
||||
public abstract Task Update(IServiceProvider provider, Service service);
|
||||
public abstract Task Delete(IServiceProvider provider, Service service);
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.Store;
|
||||
|
||||
namespace Moonlight.App.Models.Abstractions;
|
||||
|
||||
public abstract class ServiceImplementation
|
||||
{
|
||||
public abstract ServiceActions Actions { get; }
|
||||
public abstract Type ConfigType { get; }
|
||||
|
||||
public abstract RenderFragment GetAdminLayout();
|
||||
public abstract RenderFragment GetUserLayout();
|
||||
|
||||
// The service and user parameter can be used to only show certain pages to admins or other
|
||||
public abstract ServiceUiPage[] GetUserPages(Service service, User user);
|
||||
public abstract ServiceUiPage[] GetAdminPages(Service service, User user);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
public abstract class ServiceActions
|
||||
{
|
||||
public abstract Task Create(IServiceProvider provider, Database.Entities.Store.Service service);
|
||||
public abstract Task Update(IServiceProvider provider, Database.Entities.Store.Service service);
|
||||
public abstract Task Delete(IServiceProvider provider, Database.Entities.Store.Service service);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Moonlight.App.Database.Entities;
|
||||
|
||||
namespace Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
public abstract class ServiceDefinition
|
||||
{
|
||||
// Config
|
||||
public abstract ServiceActions Actions { get; }
|
||||
public abstract Type ConfigType { get; }
|
||||
|
||||
// Methods
|
||||
public abstract Task BuildUserView(ServiceViewContext context);
|
||||
public abstract Task BuildAdminView(ServiceViewContext context);
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Moonlight.App.Models.Abstractions;
|
||||
namespace Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
public class ServiceUiPage
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Route { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public ComponentBase Component { get; set; }
|
||||
public RenderFragment Component { get; set; }
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.Store;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
namespace Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
public class ServiceViewContext
|
||||
{
|
||||
// Meta
|
||||
public Service Service { get; set; }
|
||||
public User User { get; set; }
|
||||
public Product Product { get; set; }
|
||||
|
||||
// Content
|
||||
public List<ServiceUiPage> Pages { get; set; } = new();
|
||||
public RenderFragment Layout { get; set; }
|
||||
|
||||
public Task AddPage<T>(string name, string route, string icon = "") where T : ComponentBase
|
||||
{
|
||||
Pages.Add(new()
|
||||
{
|
||||
Name = name,
|
||||
Route = route,
|
||||
Icon = icon,
|
||||
Component = ComponentHelper.FromType<T>()
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.Store;
|
||||
using Moonlight.App.Models.Abstractions;
|
||||
using Moonlight.App.Models.Abstractions.Services;
|
||||
|
||||
namespace Moonlight.App.Plugins.Contexts;
|
||||
|
||||
|
@ -13,5 +11,6 @@ public class PluginContext
|
|||
public WebApplication WebApplication { get; set; }
|
||||
public List<Action> PreInitTasks = new();
|
||||
public List<Action> PostInitTasks = new();
|
||||
public Action<List<ServiceUiPage>, ServiceManageContext>? BuildServiceUiPages = null;
|
||||
public Action<ServiceViewContext>? BuildUserServiceView { get; set; } = null;
|
||||
public Action<ServiceViewContext>? BuildAdminServiceView { get; set; } = null;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using Moonlight.App.Database.Entities;
|
||||
using Moonlight.App.Database.Entities.Store;
|
||||
|
||||
namespace Moonlight.App.Plugins.Contexts;
|
||||
|
||||
public class ServiceManageContext
|
||||
{
|
||||
public Service Service { get; set; }
|
||||
public User User { get; set; }
|
||||
public Product Product { get; set; }
|
||||
}
|
|
@ -3,6 +3,7 @@ using Moonlight.App.Database.Entities;
|
|||
using Moonlight.App.Database.Entities.Store;
|
||||
using Moonlight.App.Helpers;
|
||||
using Moonlight.App.Models.Abstractions;
|
||||
using Moonlight.App.Models.Abstractions.Services;
|
||||
using Moonlight.App.Plugins;
|
||||
using Moonlight.App.Plugins.Contexts;
|
||||
|
||||
|
@ -108,18 +109,24 @@ public class PluginService
|
|||
}
|
||||
}
|
||||
|
||||
public Task<ServiceUiPage[]> BuildServiceUiPages(ServiceUiPage[] pages, ServiceManageContext context)
|
||||
public Task BuildUserServiceView(ServiceViewContext context)
|
||||
{
|
||||
var list = pages.ToList();
|
||||
|
||||
foreach (var plugin in Plugins)
|
||||
{
|
||||
// Only build if the plugin adds a page
|
||||
if(plugin.Context.BuildServiceUiPages != null)
|
||||
plugin.Context.BuildServiceUiPages.Invoke(list, context);
|
||||
plugin.Context.BuildUserServiceView?.Invoke(context);
|
||||
}
|
||||
|
||||
return Task.FromResult(list.ToArray());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task BuildAdminServiceView(ServiceViewContext context)
|
||||
{
|
||||
foreach (var plugin in Plugins)
|
||||
{
|
||||
plugin.Context.BuildAdminServiceView?.Invoke(context);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private string[] FindFiles(string dir)
|
||||
|
|
|
@ -9,17 +9,17 @@ namespace Moonlight.App.Services.ServiceManage;
|
|||
public class ServiceAdminService
|
||||
{
|
||||
private readonly IServiceScopeFactory ServiceScopeFactory;
|
||||
private readonly ServiceTypeService ServiceTypeService;
|
||||
private readonly ServiceDefinitionService ServiceDefinitionService;
|
||||
|
||||
public ServiceAdminService(IServiceScopeFactory serviceScopeFactory, ServiceTypeService serviceTypeService)
|
||||
public ServiceAdminService(IServiceScopeFactory serviceScopeFactory, ServiceDefinitionService serviceDefinitionService)
|
||||
{
|
||||
ServiceScopeFactory = serviceScopeFactory;
|
||||
ServiceTypeService = serviceTypeService;
|
||||
ServiceDefinitionService = serviceDefinitionService;
|
||||
}
|
||||
|
||||
public async Task<Service> Create(User u, Product p, Action<Service>? modifyService = null)
|
||||
{
|
||||
var impl = ServiceTypeService.Get(p);
|
||||
var impl = ServiceDefinitionService.Get(p);
|
||||
|
||||
// Load models in new scope
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
|
@ -66,7 +66,7 @@ public class ServiceAdminService
|
|||
if (service == null)
|
||||
throw new DisplayException("Service does not exist anymore");
|
||||
|
||||
var impl = ServiceTypeService.Get(service);
|
||||
var impl = ServiceDefinitionService.Get(service);
|
||||
|
||||
await impl.Actions.Delete(scope.ServiceProvider, service);
|
||||
|
||||
|
|
|
@ -2,24 +2,25 @@
|
|||
using Moonlight.App.Database.Entities.Store;
|
||||
using Moonlight.App.Database.Enums;
|
||||
using Moonlight.App.Models.Abstractions;
|
||||
using Moonlight.App.Models.Abstractions.Services;
|
||||
using Moonlight.App.Repositories;
|
||||
|
||||
namespace Moonlight.App.Services.ServiceManage;
|
||||
|
||||
public class ServiceTypeService
|
||||
public class ServiceDefinitionService
|
||||
{
|
||||
private readonly Dictionary<ServiceType, ServiceImplementation> ServiceImplementations = new();
|
||||
private readonly Dictionary<ServiceType, ServiceDefinition> ServiceImplementations = new();
|
||||
|
||||
private readonly IServiceScopeFactory ServiceScopeFactory;
|
||||
|
||||
public ServiceTypeService(IServiceScopeFactory serviceScopeFactory)
|
||||
public ServiceDefinitionService(IServiceScopeFactory serviceScopeFactory)
|
||||
{
|
||||
ServiceScopeFactory = serviceScopeFactory;
|
||||
}
|
||||
|
||||
public void Register<T>(ServiceType type) where T : ServiceImplementation
|
||||
public void Register<T>(ServiceType type) where T : ServiceDefinition
|
||||
{
|
||||
var impl = Activator.CreateInstance<T>() as ServiceImplementation;
|
||||
var impl = Activator.CreateInstance<T>() as ServiceDefinition;
|
||||
|
||||
if (impl == null)
|
||||
throw new ArgumentException("The provided type is not an service implementation");
|
||||
|
@ -30,7 +31,7 @@ public class ServiceTypeService
|
|||
ServiceImplementations.Add(type, impl);
|
||||
}
|
||||
|
||||
public ServiceImplementation Get(Service s)
|
||||
public ServiceDefinition Get(Service s)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var serviceRepo = scope.ServiceProvider.GetRequiredService<Repository<Service>>();
|
||||
|
@ -43,9 +44,9 @@ public class ServiceTypeService
|
|||
return Get(service.Product);
|
||||
}
|
||||
|
||||
public ServiceImplementation Get(Product p) => Get(p.Type);
|
||||
public ServiceDefinition Get(Product p) => Get(p.Type);
|
||||
|
||||
public ServiceImplementation Get(ServiceType type)
|
||||
public ServiceDefinition Get(ServiceType type)
|
||||
{
|
||||
if (!ServiceImplementations.ContainsKey(type))
|
||||
throw new ArgumentException($"No service implementation found for {type}");
|
|
@ -13,7 +13,7 @@ public class ServiceService // This service is used for managing services and cr
|
|||
private readonly Repository<User> UserRepository;
|
||||
|
||||
public ServiceAdminService Admin => ServiceProvider.GetRequiredService<ServiceAdminService>();
|
||||
public ServiceTypeService Type => ServiceProvider.GetRequiredService<ServiceTypeService>();
|
||||
public ServiceDefinitionService Definition => ServiceProvider.GetRequiredService<ServiceDefinitionService>();
|
||||
public ServiceManageService Manage => ServiceProvider.GetRequiredService<ServiceManageService>();
|
||||
|
||||
public ServiceService(IServiceProvider serviceProvider, Repository<Service> serviceRepository, Repository<User> userRepository)
|
||||
|
|
|
@ -108,7 +108,7 @@ public class StoreAdminService
|
|||
{
|
||||
try
|
||||
{
|
||||
var impl = ServiceService.Type.Get(type);
|
||||
var impl = ServiceService.Definition.Get(type);
|
||||
return impl.ConfigType;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
|
@ -123,7 +123,7 @@ public class StoreAdminService
|
|||
}
|
||||
public object GetProductConfig(Product product)
|
||||
{
|
||||
var impl = ServiceService.Type.Get(product.Type);
|
||||
var impl = ServiceService.Definition.Get(product.Type);
|
||||
|
||||
return JsonConvert.DeserializeObject(product.ConfigJson, impl.ConfigType) ??
|
||||
CreateNewProductConfig(product.Type);
|
||||
|
|
|
@ -80,7 +80,7 @@ builder.Services.AddSingleton<AutoMailSendService>();
|
|||
// Services / ServiceManage
|
||||
builder.Services.AddScoped<ServiceService>();
|
||||
builder.Services.AddSingleton<ServiceAdminService>();
|
||||
builder.Services.AddSingleton<ServiceTypeService>();
|
||||
builder.Services.AddSingleton<ServiceDefinitionService>();
|
||||
builder.Services.AddSingleton<ServiceManageService>();
|
||||
|
||||
// Services / Ticketing
|
||||
|
@ -123,9 +123,9 @@ app.MapControllers();
|
|||
// Auto start background services
|
||||
app.Services.GetRequiredService<AutoMailSendService>();
|
||||
|
||||
var serviceService = app.Services.GetRequiredService<ServiceTypeService>();
|
||||
var serviceService = app.Services.GetRequiredService<ServiceDefinitionService>();
|
||||
|
||||
serviceService.Register<DummyServiceImplementation>(ServiceType.Server);
|
||||
serviceService.Register<DummyServiceDefinition>(ServiceType.Server);
|
||||
|
||||
await pluginService.RunPrePost(app);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
@using Moonlight.App.Services.ServiceManage
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Moonlight.App.Models.Abstractions
|
||||
@using Moonlight.App.Models.Abstractions.Services
|
||||
@using Moonlight.App.Services
|
||||
|
||||
@inject Repository<Service> ServiceRepository
|
||||
|
@ -20,10 +21,10 @@
|
|||
else
|
||||
{
|
||||
<CascadingValue Name="Service" Value="Service">
|
||||
<CascadingValue Name="Implementation" Value="Implementation">
|
||||
<CascadingValue Name="Implementation" Value="Definition">
|
||||
<CascadingValue Name="Route" Value="Route">
|
||||
<CascadingValue Name="Pages" Value="ServiceUiPages">
|
||||
@Implementation.GetUserLayout()
|
||||
<CascadingValue Name="ViewContext" Value="ViewContext">
|
||||
@ViewContext.Layout
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
</CascadingValue>
|
||||
|
@ -40,8 +41,8 @@
|
|||
public string? Route { get; set; }
|
||||
|
||||
private Service? Service;
|
||||
private ServiceImplementation Implementation;
|
||||
private ServiceUiPage[] ServiceUiPages;
|
||||
private ServiceDefinition Definition;
|
||||
private ServiceViewContext ViewContext;
|
||||
|
||||
private async Task Load(LazyLoader lazyLoader)
|
||||
{
|
||||
|
@ -64,29 +65,21 @@
|
|||
if (Service == null)
|
||||
return;
|
||||
|
||||
|
||||
// Load implementation
|
||||
await lazyLoader.SetText("Loading implementation");
|
||||
Definition = ServiceService.Definition.Get(Service.Product.Type);
|
||||
|
||||
Implementation = ServiceService.Type.Get(Service.Product.Type);
|
||||
// Build dynamic user interface
|
||||
await lazyLoader.SetText("Building dynamic user interface");
|
||||
|
||||
await lazyLoader.SetText("Building ui");
|
||||
|
||||
// Build ui pages
|
||||
List<ServiceUiPage> pagesWithoutPlugins = new();
|
||||
|
||||
// -- Add default here --
|
||||
|
||||
// Add implementation pages
|
||||
pagesWithoutPlugins.AddRange(Implementation.GetUserPages(Service, IdentityService.CurrentUser));
|
||||
|
||||
// Modify pages through plugins
|
||||
ServiceUiPages = await PluginService.BuildServiceUiPages(pagesWithoutPlugins.ToArray(), new()
|
||||
ViewContext = new ServiceViewContext()
|
||||
{
|
||||
Product = Service.Product,
|
||||
Service = Service,
|
||||
Product = Service.Product,
|
||||
User = IdentityService.CurrentUser
|
||||
});
|
||||
};
|
||||
|
||||
// Done :D
|
||||
await Definition.BuildUserView(ViewContext);
|
||||
await PluginService.BuildUserServiceView(ViewContext);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue