Added api documentation/definition system system
This commit is contained in:
66
Moonlight/Assets/Core/css/scalar.css
Normal file
66
Moonlight/Assets/Core/css/scalar.css
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
.light-mode {
|
||||||
|
--scalar-background-1: #fff;
|
||||||
|
--scalar-background-2: #f8fafc;
|
||||||
|
--scalar-background-3: #e7e7e7;
|
||||||
|
--scalar-background-accent: #8ab4f81f;
|
||||||
|
--scalar-color-1: #000;
|
||||||
|
--scalar-color-2: #6b7280;
|
||||||
|
--scalar-color-3: #9ca3af;
|
||||||
|
--scalar-color-accent: #00c16a;
|
||||||
|
--scalar-border-color: #e5e7eb;
|
||||||
|
--scalar-color-green: #069061;
|
||||||
|
--scalar-color-red: #ef4444;
|
||||||
|
--scalar-color-yellow: #f59e0b;
|
||||||
|
--scalar-color-blue: #1d4ed8;
|
||||||
|
--scalar-color-orange: #fb892c;
|
||||||
|
--scalar-color-purple: #6d28d9;
|
||||||
|
--scalar-button-1: #000;
|
||||||
|
--scalar-button-1-hover: rgba(0, 0, 0, 0.9);
|
||||||
|
--scalar-button-1-color: #fff;
|
||||||
|
}
|
||||||
|
.dark-mode {
|
||||||
|
--scalar-background-1: #020420;
|
||||||
|
--scalar-background-2: #121a31;
|
||||||
|
--scalar-background-3: #1e293b;
|
||||||
|
--scalar-background-accent: #8ab4f81f;
|
||||||
|
--scalar-color-1: #fff;
|
||||||
|
--scalar-color-2: #cbd5e1;
|
||||||
|
--scalar-color-3: #94a3b8;
|
||||||
|
--scalar-color-accent: #00dc82;
|
||||||
|
--scalar-border-color: #1e293b;
|
||||||
|
--scalar-color-green: #069061;
|
||||||
|
--scalar-color-red: #f87171;
|
||||||
|
--scalar-color-yellow: #fde68a;
|
||||||
|
--scalar-color-blue: #60a5fa;
|
||||||
|
--scalar-color-orange: #fb892c;
|
||||||
|
--scalar-color-purple: #ddd6fe;
|
||||||
|
--scalar-button-1: hsla(0, 0%, 100%, 0.9);
|
||||||
|
--scalar-button-1-hover: hsla(0, 0%, 100%, 0.8);
|
||||||
|
--scalar-button-1-color: #000;
|
||||||
|
}
|
||||||
|
.dark-mode .t-doc__sidebar,
|
||||||
|
.light-mode .t-doc__sidebar {
|
||||||
|
--scalar-sidebar-background-1: var(--scalar-background-1);
|
||||||
|
--scalar-sidebar-color-1: var(--scalar-color-1);
|
||||||
|
--scalar-sidebar-color-2: var(--scalar-color-3);
|
||||||
|
--scalar-sidebar-border-color: var(--scalar-border-color);
|
||||||
|
--scalar-sidebar-item-hover-background: transparent;
|
||||||
|
--scalar-sidebar-item-hover-color: var(--scalar-color-1);
|
||||||
|
--scalar-sidebar-item-active-background: transparent;
|
||||||
|
--scalar-sidebar-color-active: var(--scalar-color-accent);
|
||||||
|
--scalar-sidebar-search-background: transparent;
|
||||||
|
--scalar-sidebar-search-color: var(--scalar-color-3);
|
||||||
|
--scalar-sidebar-search-border-color: var(--scalar-border-color);
|
||||||
|
--scalar-sidebar-indent-border: var(--scalar-border-color);
|
||||||
|
--scalar-sidebar-indent-border-hover: var(--scalar-color-1);
|
||||||
|
--scalar-sidebar-indent-border-active: var(--scalar-color-accent);
|
||||||
|
}
|
||||||
|
.scalar-card .request-card-footer {
|
||||||
|
--scalar-background-3: var(--scalar-background-2);
|
||||||
|
--scalar-button-1: #0f172a;
|
||||||
|
--scalar-button-1-hover: rgba(30, 41, 59, 0.5);
|
||||||
|
--scalar-button-1-color: #fff;
|
||||||
|
}
|
||||||
|
.scalar-card .show-api-client-button {
|
||||||
|
border: 1px solid #334155 !important;
|
||||||
|
}
|
||||||
11
Moonlight/Core/Attributes/ApiDocumentAttribute.cs
Normal file
11
Moonlight/Core/Attributes/ApiDocumentAttribute.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Moonlight.Core.Attributes;
|
||||||
|
|
||||||
|
public class ApiDocumentAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public ApiDocumentAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,14 @@ public class CoreConfiguration
|
|||||||
[JsonProperty("Customisation")] public CustomisationData Customisation { get; set; } = new();
|
[JsonProperty("Customisation")] public CustomisationData Customisation { get; set; } = new();
|
||||||
|
|
||||||
[JsonProperty("Security")] public SecurityData Security { get; set; } = new();
|
[JsonProperty("Security")] public SecurityData Security { get; set; } = new();
|
||||||
|
[JsonProperty("Development")] public DevelopmentData Development { get; set; } = new();
|
||||||
|
|
||||||
|
public class DevelopmentData
|
||||||
|
{
|
||||||
|
[JsonProperty("EnableApiReference")]
|
||||||
|
[Description("This enables the api reference at your-moonlight.domain/admin/api/reference. Changing this requires a restart")]
|
||||||
|
public bool EnableApiReference { get; set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
public class HttpData
|
public class HttpData
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ using Moonlight.Core.Models.Abstractions.Feature;
|
|||||||
using Moonlight.Core.Models.Enums;
|
using Moonlight.Core.Models.Enums;
|
||||||
using Moonlight.Core.Repositories;
|
using Moonlight.Core.Repositories;
|
||||||
using Moonlight.Core.Services;
|
using Moonlight.Core.Services;
|
||||||
using Moonlight.Core.UI.Components.Cards;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Moonlight.Core.Attributes;
|
||||||
|
using Moonlight.Core.Implementations.ApiDefinition;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
namespace Moonlight.Core;
|
namespace Moonlight.Core;
|
||||||
|
|
||||||
@@ -32,7 +35,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
Author = "MasuOwO and contributors";
|
Author = "MasuOwO and contributors";
|
||||||
IssueTracker = "https://github.com/Moonlight-Panel/Moonlight/issues";
|
IssueTracker = "https://github.com/Moonlight-Panel/Moonlight/issues";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task OnPreInitialized(PreInitContext context)
|
public override Task OnPreInitialized(PreInitContext context)
|
||||||
{
|
{
|
||||||
// Load configuration
|
// Load configuration
|
||||||
@@ -41,17 +44,17 @@ public class CoreFeature : MoonlightFeature
|
|||||||
);
|
);
|
||||||
|
|
||||||
var config = configService.Get();
|
var config = configService.Get();
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
context.EnableDependencyInjection<CoreFeature>();
|
context.EnableDependencyInjection<CoreFeature>();
|
||||||
|
|
||||||
var builder = context.Builder;
|
var builder = context.Builder;
|
||||||
|
|
||||||
builder.Services.AddDbContext<DataContext>();
|
builder.Services.AddDbContext<DataContext>();
|
||||||
|
|
||||||
//
|
//
|
||||||
builder.Services.AddSingleton(new JwtService<CoreJwtType>(config.Security.Token));
|
builder.Services.AddSingleton(new JwtService<CoreJwtType>(config.Security.Token));
|
||||||
|
|
||||||
// Mooncore services
|
// Mooncore services
|
||||||
builder.Services.AddScoped(typeof(Repository<>), typeof(GenericRepository<>));
|
builder.Services.AddScoped(typeof(Repository<>), typeof(GenericRepository<>));
|
||||||
builder.Services.AddScoped<CookieService>();
|
builder.Services.AddScoped<CookieService>();
|
||||||
@@ -60,7 +63,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
builder.Services.AddScoped<ToastService>();
|
builder.Services.AddScoped<ToastService>();
|
||||||
builder.Services.AddScoped<ClipboardService>();
|
builder.Services.AddScoped<ClipboardService>();
|
||||||
builder.Services.AddScoped<ModalService>();
|
builder.Services.AddScoped<ModalService>();
|
||||||
|
|
||||||
builder.Services.AddMoonCoreUi(configuration =>
|
builder.Services.AddMoonCoreUi(configuration =>
|
||||||
{
|
{
|
||||||
configuration.ToastJavascriptPrefix = "moonlight.toasts";
|
configuration.ToastJavascriptPrefix = "moonlight.toasts";
|
||||||
@@ -69,13 +72,13 @@ public class CoreFeature : MoonlightFeature
|
|||||||
configuration.ClipboardJavascriptPrefix = "moonlight.clipboard";
|
configuration.ClipboardJavascriptPrefix = "moonlight.clipboard";
|
||||||
configuration.FileDownloadJavascriptPrefix = "moonlight.utils";
|
configuration.FileDownloadJavascriptPrefix = "moonlight.utils";
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add external services and blazor/asp.net stuff
|
// Add external services and blazor/asp.net stuff
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddBlazorTable();
|
builder.Services.AddBlazorTable();
|
||||||
|
|
||||||
// Configure blazor pipeline in detail
|
// Configure blazor pipeline in detail
|
||||||
builder.Services.AddServerSideBlazor().AddHubOptions(options =>
|
builder.Services.AddServerSideBlazor().AddHubOptions(options =>
|
||||||
{
|
{
|
||||||
@@ -85,15 +88,15 @@ public class CoreFeature : MoonlightFeature
|
|||||||
// Setup authentication if required
|
// Setup authentication if required
|
||||||
if (config.Authentication.UseDefaultAuthentication)
|
if (config.Authentication.UseDefaultAuthentication)
|
||||||
builder.Services.AddScoped<IAuthenticationProvider, DefaultAuthenticationProvider>();
|
builder.Services.AddScoped<IAuthenticationProvider, DefaultAuthenticationProvider>();
|
||||||
|
|
||||||
// Setup http upload limit
|
// Setup http upload limit
|
||||||
context.Builder.WebHost.ConfigureKestrel(options =>
|
context.Builder.WebHost.ConfigureKestrel(options =>
|
||||||
{
|
{
|
||||||
options.Limits.MaxRequestBodySize = ByteSizeValue.FromMegaBytes(config.Http.UploadLimit).Bytes;
|
options.Limits.MaxRequestBodySize = ByteSizeValue.FromMegaBytes(config.Http.UploadLimit).Bytes;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assets
|
// Assets
|
||||||
|
|
||||||
// - Javascript
|
// - Javascript
|
||||||
context.AddAsset("Core", "js/bootstrap.js");
|
context.AddAsset("Core", "js/bootstrap.js");
|
||||||
context.AddAsset("Core", "js/moonlight.js");
|
context.AddAsset("Core", "js/moonlight.js");
|
||||||
@@ -101,24 +104,58 @@ public class CoreFeature : MoonlightFeature
|
|||||||
context.AddAsset("Core", "js/toaster.js");
|
context.AddAsset("Core", "js/toaster.js");
|
||||||
context.AddAsset("Core", "js/sidebar.js");
|
context.AddAsset("Core", "js/sidebar.js");
|
||||||
context.AddAsset("Core", "js/alerter.js");
|
context.AddAsset("Core", "js/alerter.js");
|
||||||
|
|
||||||
// - Css
|
// - Css
|
||||||
context.AddAsset("Core", "css/blazor.css");
|
context.AddAsset("Core", "css/blazor.css");
|
||||||
context.AddAsset("Core", "css/boxicons.css");
|
context.AddAsset("Core", "css/boxicons.css");
|
||||||
context.AddAsset("Core", "css/sweetalert2dark.css");
|
context.AddAsset("Core", "css/sweetalert2dark.css");
|
||||||
context.AddAsset("Core", "css/utils.css");
|
context.AddAsset("Core", "css/utils.css");
|
||||||
|
|
||||||
|
// Api
|
||||||
|
if (config.Development.EnableApiReference)
|
||||||
|
{
|
||||||
|
builder.Services.AddSwaggerGen(async options =>
|
||||||
|
{
|
||||||
|
foreach (var definition in await context.Plugins.GetImplementations<IApiDefinition>())
|
||||||
|
{
|
||||||
|
options.SwaggerDoc(
|
||||||
|
definition.GetId(),
|
||||||
|
new OpenApiInfo()
|
||||||
|
{
|
||||||
|
Title = definition.GetName(),
|
||||||
|
Version = definition.GetVersion()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
options.SwaggerGeneratorOptions.DocInclusionPredicate = (document, description) =>
|
||||||
|
{
|
||||||
|
foreach (var attribute in description.CustomAttributes())
|
||||||
|
{
|
||||||
|
if (attribute is ApiDocumentAttribute documentAttribute)
|
||||||
|
return document == documentAttribute.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnInitialized(InitContext context)
|
public override async Task OnInitialized(InitContext context)
|
||||||
{
|
{
|
||||||
var app = context.Application;
|
var app = context.Application;
|
||||||
|
|
||||||
|
// Config
|
||||||
|
var configService = app.Services.GetRequiredService<ConfigService<CoreConfiguration>>();
|
||||||
|
var config = configService.Get();
|
||||||
|
|
||||||
// Allow MoonlightService to access the app
|
// Allow MoonlightService to access the app
|
||||||
var moonlightService = app.Services.GetRequiredService<MoonlightService>();
|
var moonlightService = app.Services.GetRequiredService<MoonlightService>();
|
||||||
moonlightService.Application = app;
|
moonlightService.Application = app;
|
||||||
|
|
||||||
// Define permissions
|
// Define permissions
|
||||||
var permissionService = app.Services.GetRequiredService<PermissionService>();
|
var permissionService = app.Services.GetRequiredService<PermissionService>();
|
||||||
|
|
||||||
@@ -127,25 +164,31 @@ public class CoreFeature : MoonlightFeature
|
|||||||
Name = "See Admin Page",
|
Name = "See Admin Page",
|
||||||
Description = "Allows access to the admin page and the connected stats (server and user count)"
|
Description = "Allows access to the admin page and the connected stats (server and user count)"
|
||||||
});
|
});
|
||||||
|
|
||||||
await permissionService.Register(1000, new()
|
await permissionService.Register(1000, new()
|
||||||
{
|
{
|
||||||
Name = "Manage users",
|
Name = "Manage users",
|
||||||
Description = "Allows access to users and their sessions"
|
Description = "Allows access to users and their sessions"
|
||||||
});
|
});
|
||||||
|
|
||||||
await permissionService.Register(9000, new()
|
await permissionService.Register(9000, new()
|
||||||
{
|
{
|
||||||
Name = "View exceptions",
|
Name = "View exceptions",
|
||||||
Description = "Allows to see the raw message of exceptions when thrown in a view"
|
Description = "Allows to see the raw message of exceptions when thrown in a view"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await permissionService.Register(9998, new()
|
||||||
|
{
|
||||||
|
Name = "Manage admin api access",
|
||||||
|
Description = "Allows access to manage api keys and their permissions"
|
||||||
|
});
|
||||||
|
|
||||||
await permissionService.Register(9999, new()
|
await permissionService.Register(9999, new()
|
||||||
{
|
{
|
||||||
Name = "Manage system",
|
Name = "Manage system",
|
||||||
Description = "Allows access to the core system if moonlight and all configuration files"
|
Description = "Allows access to the core system if moonlight and all configuration files"
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
@@ -153,7 +196,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
app.MapFallbackToPage("/_Host");
|
app.MapFallbackToPage("/_Host");
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
app.UseWebSockets();
|
app.UseWebSockets();
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
var pluginService = app.Services.GetRequiredService<PluginService>();
|
var pluginService = app.Services.GetRequiredService<PluginService>();
|
||||||
|
|
||||||
@@ -162,26 +205,26 @@ public class CoreFeature : MoonlightFeature
|
|||||||
await pluginService.RegisterImplementation<IDiagnoseAction>(new PluginsDiagnoseAction());
|
await pluginService.RegisterImplementation<IDiagnoseAction>(new PluginsDiagnoseAction());
|
||||||
await pluginService.RegisterImplementation<IDiagnoseAction>(new FeatureDiagnoseAction());
|
await pluginService.RegisterImplementation<IDiagnoseAction>(new FeatureDiagnoseAction());
|
||||||
await pluginService.RegisterImplementation<IDiagnoseAction>(new LogDiagnoseAction());
|
await pluginService.RegisterImplementation<IDiagnoseAction>(new LogDiagnoseAction());
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
await pluginService.RegisterImplementation<IAdminDashboardColumn>(new UserCount());
|
await pluginService.RegisterImplementation<IAdminDashboardColumn>(new UserCount());
|
||||||
await pluginService.RegisterImplementation<IUserDashboardComponent>(new GreetingMessages());
|
await pluginService.RegisterImplementation<IUserDashboardComponent>(new GreetingMessages());
|
||||||
|
|
||||||
// Startup job services
|
// Startup job services
|
||||||
var startupJobService = app.Services.GetRequiredService<StartupJobService>();
|
var startupJobService = app.Services.GetRequiredService<StartupJobService>();
|
||||||
|
|
||||||
await startupJobService.AddJob("Default user creation", TimeSpan.FromSeconds(3), async provider =>
|
await startupJobService.AddJob("Default user creation", TimeSpan.FromSeconds(3), async provider =>
|
||||||
{
|
{
|
||||||
using var scope = provider.CreateScope();
|
using var scope = provider.CreateScope();
|
||||||
|
|
||||||
var configService = scope.ServiceProvider.GetRequiredService<ConfigService<CoreConfiguration>>();
|
var configService = scope.ServiceProvider.GetRequiredService<ConfigService<CoreConfiguration>>();
|
||||||
var userRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
|
var userRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
|
||||||
var authenticationProvider = scope.ServiceProvider.GetRequiredService<IAuthenticationProvider>();
|
var authenticationProvider = scope.ServiceProvider.GetRequiredService<IAuthenticationProvider>();
|
||||||
|
|
||||||
if(!configService.Get().Authentication.UseDefaultAuthentication)
|
if (!configService.Get().Authentication.UseDefaultAuthentication)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(userRepo.Get().Any())
|
if (userRepo.Get().Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Define credentials
|
// Define credentials
|
||||||
@@ -202,43 +245,52 @@ public class CoreFeature : MoonlightFeature
|
|||||||
var user = userRepo.Get().First(x => x.Username == username);
|
var user = userRepo.Get().First(x => x.Username == username);
|
||||||
user.Permissions = 9999;
|
user.Permissions = 9999;
|
||||||
userRepo.Update(user);
|
userRepo.Update(user);
|
||||||
|
|
||||||
Logger.Info($"Default login: Email: '{email}' Password: '{password}'");
|
Logger.Info($"Default login: Email: '{email}' Password: '{password}'");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Api
|
||||||
|
if (config.Development.EnableApiReference)
|
||||||
|
{
|
||||||
|
app.MapSwagger("/api/core/reference/openapi/{documentName}");
|
||||||
|
|
||||||
|
await pluginService.RegisterImplementation<IApiDefinition>(new InternalApiDefinition());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task OnUiInitialized(UiInitContext context)
|
public override Task OnUiInitialized(UiInitContext context)
|
||||||
{
|
{
|
||||||
context.EnablePages<CoreFeature>();
|
context.EnablePages<CoreFeature>();
|
||||||
|
|
||||||
// User pages
|
// User pages
|
||||||
context.AddSidebarItem("Dashboard", "bxs-dashboard", "/", needsExactMatch: true, index: int.MinValue);
|
context.AddSidebarItem("Dashboard", "bxs-dashboard", "/", needsExactMatch: true, index: int.MinValue);
|
||||||
|
|
||||||
// Admin pages
|
// Admin pages
|
||||||
context.AddSidebarItem("Dashboard", "bxs-dashboard", "/admin", needsExactMatch: true, isAdmin: true, index: int.MinValue);
|
context.AddSidebarItem("Dashboard", "bxs-dashboard", "/admin", needsExactMatch: true, isAdmin: true,
|
||||||
|
index: int.MinValue);
|
||||||
context.AddSidebarItem("Users", "bxs-group", "/admin/users", needsExactMatch: false, isAdmin: true);
|
context.AddSidebarItem("Users", "bxs-group", "/admin/users", needsExactMatch: false, isAdmin: true);
|
||||||
context.AddSidebarItem("System", "bxs-component", "/admin/sys", needsExactMatch: false, isAdmin: true);
|
context.AddSidebarItem("System", "bxs-component", "/admin/sys", needsExactMatch: false, isAdmin: true);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnSessionInitialized(SessionInitContext context)
|
public override async Task OnSessionInitialized(SessionInitContext context)
|
||||||
{
|
{
|
||||||
var lazyLoader = context.LazyLoader;
|
var lazyLoader = context.LazyLoader;
|
||||||
|
|
||||||
// - Authentication
|
// - Authentication
|
||||||
var cookieService = context.ServiceProvider.GetRequiredService<CookieService>();
|
var cookieService = context.ServiceProvider.GetRequiredService<CookieService>();
|
||||||
var identityService = context.ServiceProvider.GetRequiredService<IdentityService>();
|
var identityService = context.ServiceProvider.GetRequiredService<IdentityService>();
|
||||||
|
|
||||||
await lazyLoader.SetText("Authenticating");
|
await lazyLoader.SetText("Authenticating");
|
||||||
var token = await cookieService.GetValue("token");
|
var token = await cookieService.GetValue("token");
|
||||||
await identityService.Authenticate(token);
|
await identityService.Authenticate(token);
|
||||||
|
|
||||||
// - Session
|
// - Session
|
||||||
await lazyLoader.SetText("Starting session");
|
await lazyLoader.SetText("Starting session");
|
||||||
var scopedStorageService = context.ServiceProvider.GetRequiredService<ScopedStorageService>();
|
var scopedStorageService = context.ServiceProvider.GetRequiredService<ScopedStorageService>();
|
||||||
var sessionService = context.ServiceProvider.GetRequiredService<SessionService>();
|
var sessionService = context.ServiceProvider.GetRequiredService<SessionService>();
|
||||||
|
|
||||||
var navigationManager = context.ServiceProvider.GetRequiredService<NavigationManager>();
|
var navigationManager = context.ServiceProvider.GetRequiredService<NavigationManager>();
|
||||||
var alertService = context.ServiceProvider.GetRequiredService<AlertService>();
|
var alertService = context.ServiceProvider.GetRequiredService<AlertService>();
|
||||||
|
|
||||||
@@ -253,15 +305,12 @@ public class CoreFeature : MoonlightFeature
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Setup updating
|
// Setup updating
|
||||||
navigationManager.LocationChanged += (_, _) =>
|
navigationManager.LocationChanged += (_, _) => { session.UpdatedAt = DateTime.UtcNow; };
|
||||||
{
|
|
||||||
session.UpdatedAt = DateTime.UtcNow;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save session and session service to view storage
|
// Save session and session service to view storage
|
||||||
scopedStorageService.Set("Session", session);
|
scopedStorageService.Set("Session", session);
|
||||||
scopedStorageService.Set("SessionService", sessionService);
|
scopedStorageService.Set("SessionService", sessionService);
|
||||||
|
|
||||||
// Register session
|
// Register session
|
||||||
await sessionService.Add(session);
|
await sessionService.Add(session);
|
||||||
}
|
}
|
||||||
|
|||||||
53
Moonlight/Core/Http/Controllers/ApiReferenceController.cs
Normal file
53
Moonlight/Core/Http/Controllers/ApiReferenceController.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using MoonCore.Services;
|
||||||
|
using Moonlight.Core.Attributes;
|
||||||
|
using Moonlight.Core.Configuration;
|
||||||
|
using Moonlight.Core.Models;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Moonlight.Core.Http.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[ApiDocument("internal")]
|
||||||
|
[Route("/api/core/reference")]
|
||||||
|
public class ApiReferenceController : Controller
|
||||||
|
{
|
||||||
|
private readonly ConfigService<CoreConfiguration> ConfigService;
|
||||||
|
|
||||||
|
public ApiReferenceController(ConfigService<CoreConfiguration> configService)
|
||||||
|
{
|
||||||
|
ConfigService = configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> Get([FromQuery] string document)
|
||||||
|
{
|
||||||
|
if (!ConfigService.Get().Development.EnableApiReference)
|
||||||
|
return BadRequest("Api reference is disabled");
|
||||||
|
|
||||||
|
var options = new ScalarOptions();
|
||||||
|
var optionsJson = JsonConvert.SerializeObject(options, Formatting.Indented);
|
||||||
|
|
||||||
|
var html = "<!doctype html>\n" +
|
||||||
|
"<html>\n" +
|
||||||
|
"<head>\n" +
|
||||||
|
"<title>Moonlight Api Reference</title>\n" +
|
||||||
|
"<meta charset=\"utf-8\" />\n" +
|
||||||
|
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n" +
|
||||||
|
"</head>\n" +
|
||||||
|
"<body>\n" +
|
||||||
|
$"<script id=\"api-reference\" data-url=\"/api/core/reference/openapi/{document}\"></script>\n" +
|
||||||
|
"<script>\n" +
|
||||||
|
"var configuration =\n" +
|
||||||
|
$"{optionsJson}\n" +
|
||||||
|
"\n" +
|
||||||
|
"document.getElementById('api-reference').dataset.configuration =\n" +
|
||||||
|
"JSON.stringify(configuration)\n" +
|
||||||
|
"</script>\n" +
|
||||||
|
"<script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n" +
|
||||||
|
"</body>\n" +
|
||||||
|
"</html>";
|
||||||
|
|
||||||
|
return Content(html, "text/html");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
using Moonlight.Core.Attributes;
|
||||||
|
|
||||||
namespace Moonlight.Core.Http.Controllers;
|
namespace Moonlight.Core.Http.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
[ApiDocument("internal")]
|
||||||
[Route("api/core/asset")]
|
[Route("api/core/asset")]
|
||||||
public class AssetController : Controller
|
public class AssetController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using MoonCore.Abstractions;
|
using MoonCore.Abstractions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.Services;
|
using MoonCore.Services;
|
||||||
|
using Moonlight.Core.Attributes;
|
||||||
using Moonlight.Core.Configuration;
|
using Moonlight.Core.Configuration;
|
||||||
using Moonlight.Core.Database.Entities;
|
using Moonlight.Core.Database.Entities;
|
||||||
using Moonlight.Core.Services;
|
using Moonlight.Core.Services;
|
||||||
@@ -11,6 +12,7 @@ using Moonlight.Core.Services;
|
|||||||
namespace Moonlight.Core.Http.Controllers;
|
namespace Moonlight.Core.Http.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
[ApiDocument("internal")]
|
||||||
[Route("api/core/avatar")]
|
[Route("api/core/avatar")]
|
||||||
public class AvatarController : Controller
|
public class AvatarController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using Moonlight.Core.Interfaces;
|
||||||
|
|
||||||
|
namespace Moonlight.Core.Implementations.ApiDefinition;
|
||||||
|
|
||||||
|
public class InternalApiDefinition : IApiDefinition
|
||||||
|
{
|
||||||
|
public string GetId() => "internal";
|
||||||
|
|
||||||
|
public string GetName() => "Internal API";
|
||||||
|
|
||||||
|
public string GetVersion() => "v2";
|
||||||
|
|
||||||
|
public string[] GetPermissions() => [];
|
||||||
|
}
|
||||||
9
Moonlight/Core/Interfaces/IApiDefinition.cs
Normal file
9
Moonlight/Core/Interfaces/IApiDefinition.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Moonlight.Core.Interfaces;
|
||||||
|
|
||||||
|
public interface IApiDefinition
|
||||||
|
{
|
||||||
|
public string GetId();
|
||||||
|
public string GetName();
|
||||||
|
public string GetVersion();
|
||||||
|
public string[] GetPermissions();
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Moonlight.Core.Services;
|
||||||
|
|
||||||
namespace Moonlight.Core.Models.Abstractions.Feature;
|
namespace Moonlight.Core.Models.Abstractions.Feature;
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ public class PreInitContext
|
|||||||
public WebApplicationBuilder Builder { get; set; }
|
public WebApplicationBuilder Builder { get; set; }
|
||||||
public List<Assembly> DiAssemblies { get; set; } = new();
|
public List<Assembly> DiAssemblies { get; set; } = new();
|
||||||
public Dictionary<string, List<string>> Assets { get; set; } = new();
|
public Dictionary<string, List<string>> Assets { get; set; } = new();
|
||||||
|
public PluginService Plugins { get; set; }
|
||||||
|
|
||||||
public void EnableDependencyInjection<T>()
|
public void EnableDependencyInjection<T>()
|
||||||
{
|
{
|
||||||
|
|||||||
43
Moonlight/Core/Models/ScalarOptions.cs
Normal file
43
Moonlight/Core/Models/ScalarOptions.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
namespace Moonlight.Core.Models;
|
||||||
|
|
||||||
|
// From https://github.com/scalar/scalar/blob/main/packages/scalar.aspnetcore/ScalarOptions.cs
|
||||||
|
|
||||||
|
public class ScalarOptions
|
||||||
|
{
|
||||||
|
public string Theme { get; set; } = "purple";
|
||||||
|
|
||||||
|
public bool? DarkMode { get; set; }
|
||||||
|
public bool? HideDownloadButton { get; set; }
|
||||||
|
public bool? ShowSideBar { get; set; }
|
||||||
|
|
||||||
|
public bool? WithDefaultFonts { get; set; }
|
||||||
|
|
||||||
|
public string? Layout { get; set; }
|
||||||
|
|
||||||
|
public string? CustomCss { get; set; }
|
||||||
|
|
||||||
|
public string? SearchHotkey { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string>? Metadata { get; set; }
|
||||||
|
|
||||||
|
public ScalarAuthenticationOptions? Authentication { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScalarAuthenticationOptions
|
||||||
|
{
|
||||||
|
public string? PreferredSecurityScheme { get; set; }
|
||||||
|
|
||||||
|
public ScalarAuthenticationApiKey? ApiKey { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScalarAuthenticationoAuth2
|
||||||
|
{
|
||||||
|
public string? ClientId { get; set; }
|
||||||
|
|
||||||
|
public List<string>? Scopes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScalarAuthenticationApiKey
|
||||||
|
{
|
||||||
|
public string? Token { get; set; }
|
||||||
|
}
|
||||||
@@ -55,11 +55,12 @@ public class FeatureService
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PreInit(WebApplicationBuilder builder)
|
public async Task PreInit(WebApplicationBuilder builder, PluginService pluginService)
|
||||||
{
|
{
|
||||||
Logger.Info("Pre-initializing features");
|
Logger.Info("Pre-initializing features");
|
||||||
|
|
||||||
PreInitContext.Builder = builder;
|
PreInitContext.Builder = builder;
|
||||||
|
PreInitContext.Plugins = pluginService;
|
||||||
|
|
||||||
foreach (var feature in Features)
|
foreach (var feature in Features)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ builder.Services.AddSingleton(configService);
|
|||||||
builder.Services.AddSingleton(pluginService);
|
builder.Services.AddSingleton(pluginService);
|
||||||
|
|
||||||
// Feature hook
|
// Feature hook
|
||||||
await featureService.PreInit(builder);
|
await featureService.PreInit(builder, pluginService);
|
||||||
|
|
||||||
// Plugin hook
|
// Plugin hook
|
||||||
await pluginService.PreInitialize(builder);
|
await pluginService.PreInitialize(builder);
|
||||||
|
|||||||
Reference in New Issue
Block a user