Merge pull request #431 from Moonlight-Panel/v2_AdminApi
Added admin api 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;
|
||||
}
|
||||
}
|
||||
11
Moonlight/Core/Attributes/ApiPermissionAttribute.cs
Normal file
11
Moonlight/Core/Attributes/ApiPermissionAttribute.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Moonlight.Core.Attributes;
|
||||
|
||||
public class ApiPermissionAttribute : Attribute
|
||||
{
|
||||
public string Permission { get; set; }
|
||||
|
||||
public ApiPermissionAttribute(string permission)
|
||||
{
|
||||
Permission = permission;
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,14 @@ public class CoreConfiguration
|
||||
[JsonProperty("Customisation")] public CustomisationData Customisation { 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
|
||||
{
|
||||
|
||||
@@ -20,7 +20,11 @@ using Moonlight.Core.Models.Abstractions.Feature;
|
||||
using Moonlight.Core.Models.Enums;
|
||||
using Moonlight.Core.Repositories;
|
||||
using Moonlight.Core.Services;
|
||||
using Moonlight.Core.UI.Components.Cards;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Moonlight.Core.Attributes;
|
||||
using Moonlight.Core.Http.Middleware;
|
||||
using Moonlight.Core.Implementations.ApiDefinition;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace Moonlight.Core;
|
||||
|
||||
@@ -32,7 +36,7 @@ public class CoreFeature : MoonlightFeature
|
||||
Author = "MasuOwO and contributors";
|
||||
IssueTracker = "https://github.com/Moonlight-Panel/Moonlight/issues";
|
||||
}
|
||||
|
||||
|
||||
public override Task OnPreInitialized(PreInitContext context)
|
||||
{
|
||||
// Load configuration
|
||||
@@ -41,17 +45,17 @@ public class CoreFeature : MoonlightFeature
|
||||
);
|
||||
|
||||
var config = configService.Get();
|
||||
|
||||
|
||||
// Services
|
||||
context.EnableDependencyInjection<CoreFeature>();
|
||||
|
||||
|
||||
var builder = context.Builder;
|
||||
|
||||
|
||||
builder.Services.AddDbContext<DataContext>();
|
||||
|
||||
|
||||
//
|
||||
builder.Services.AddSingleton(new JwtService<CoreJwtType>(config.Security.Token));
|
||||
|
||||
|
||||
// Mooncore services
|
||||
builder.Services.AddScoped(typeof(Repository<>), typeof(GenericRepository<>));
|
||||
builder.Services.AddScoped<CookieService>();
|
||||
@@ -60,7 +64,7 @@ public class CoreFeature : MoonlightFeature
|
||||
builder.Services.AddScoped<ToastService>();
|
||||
builder.Services.AddScoped<ClipboardService>();
|
||||
builder.Services.AddScoped<ModalService>();
|
||||
|
||||
|
||||
builder.Services.AddMoonCoreUi(configuration =>
|
||||
{
|
||||
configuration.ToastJavascriptPrefix = "moonlight.toasts";
|
||||
@@ -69,13 +73,13 @@ public class CoreFeature : MoonlightFeature
|
||||
configuration.ClipboardJavascriptPrefix = "moonlight.clipboard";
|
||||
configuration.FileDownloadJavascriptPrefix = "moonlight.utils";
|
||||
});
|
||||
|
||||
|
||||
// Add external services and blazor/asp.net stuff
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddBlazorTable();
|
||||
|
||||
|
||||
// Configure blazor pipeline in detail
|
||||
builder.Services.AddServerSideBlazor().AddHubOptions(options =>
|
||||
{
|
||||
@@ -85,15 +89,15 @@ public class CoreFeature : MoonlightFeature
|
||||
// Setup authentication if required
|
||||
if (config.Authentication.UseDefaultAuthentication)
|
||||
builder.Services.AddScoped<IAuthenticationProvider, DefaultAuthenticationProvider>();
|
||||
|
||||
|
||||
// Setup http upload limit
|
||||
context.Builder.WebHost.ConfigureKestrel(options =>
|
||||
{
|
||||
options.Limits.MaxRequestBodySize = ByteSizeValue.FromMegaBytes(config.Http.UploadLimit).Bytes;
|
||||
});
|
||||
|
||||
|
||||
// Assets
|
||||
|
||||
|
||||
// - Javascript
|
||||
context.AddAsset("Core", "js/bootstrap.js");
|
||||
context.AddAsset("Core", "js/moonlight.js");
|
||||
@@ -101,24 +105,58 @@ public class CoreFeature : MoonlightFeature
|
||||
context.AddAsset("Core", "js/toaster.js");
|
||||
context.AddAsset("Core", "js/sidebar.js");
|
||||
context.AddAsset("Core", "js/alerter.js");
|
||||
|
||||
|
||||
// - Css
|
||||
context.AddAsset("Core", "css/blazor.css");
|
||||
context.AddAsset("Core", "css/boxicons.css");
|
||||
context.AddAsset("Core", "css/sweetalert2dark.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;
|
||||
}
|
||||
|
||||
public override async Task OnInitialized(InitContext context)
|
||||
{
|
||||
var app = context.Application;
|
||||
|
||||
|
||||
// Config
|
||||
var configService = app.Services.GetRequiredService<ConfigService<CoreConfiguration>>();
|
||||
var config = configService.Get();
|
||||
|
||||
// Allow MoonlightService to access the app
|
||||
var moonlightService = app.Services.GetRequiredService<MoonlightService>();
|
||||
moonlightService.Application = app;
|
||||
|
||||
|
||||
// Define permissions
|
||||
var permissionService = app.Services.GetRequiredService<PermissionService>();
|
||||
|
||||
@@ -127,25 +165,31 @@ public class CoreFeature : MoonlightFeature
|
||||
Name = "See Admin Page",
|
||||
Description = "Allows access to the admin page and the connected stats (server and user count)"
|
||||
});
|
||||
|
||||
|
||||
await permissionService.Register(1000, new()
|
||||
{
|
||||
Name = "Manage users",
|
||||
Description = "Allows access to users and their sessions"
|
||||
});
|
||||
|
||||
|
||||
await permissionService.Register(9000, new()
|
||||
{
|
||||
Name = "View exceptions",
|
||||
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()
|
||||
{
|
||||
Name = "Manage system",
|
||||
Description = "Allows access to the core system if moonlight and all configuration files"
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
@@ -153,7 +197,7 @@ public class CoreFeature : MoonlightFeature
|
||||
app.MapFallbackToPage("/_Host");
|
||||
app.MapControllers();
|
||||
app.UseWebSockets();
|
||||
|
||||
|
||||
// Plugins
|
||||
var pluginService = app.Services.GetRequiredService<PluginService>();
|
||||
|
||||
@@ -162,26 +206,26 @@ public class CoreFeature : MoonlightFeature
|
||||
await pluginService.RegisterImplementation<IDiagnoseAction>(new PluginsDiagnoseAction());
|
||||
await pluginService.RegisterImplementation<IDiagnoseAction>(new FeatureDiagnoseAction());
|
||||
await pluginService.RegisterImplementation<IDiagnoseAction>(new LogDiagnoseAction());
|
||||
|
||||
|
||||
// UI
|
||||
await pluginService.RegisterImplementation<IAdminDashboardColumn>(new UserCount());
|
||||
await pluginService.RegisterImplementation<IUserDashboardComponent>(new GreetingMessages());
|
||||
|
||||
|
||||
// Startup job services
|
||||
var startupJobService = app.Services.GetRequiredService<StartupJobService>();
|
||||
|
||||
await startupJobService.AddJob("Default user creation", TimeSpan.FromSeconds(3), async provider =>
|
||||
{
|
||||
using var scope = provider.CreateScope();
|
||||
|
||||
|
||||
var configService = scope.ServiceProvider.GetRequiredService<ConfigService<CoreConfiguration>>();
|
||||
var userRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
|
||||
var authenticationProvider = scope.ServiceProvider.GetRequiredService<IAuthenticationProvider>();
|
||||
|
||||
if(!configService.Get().Authentication.UseDefaultAuthentication)
|
||||
|
||||
if (!configService.Get().Authentication.UseDefaultAuthentication)
|
||||
return;
|
||||
|
||||
if(userRepo.Get().Any())
|
||||
|
||||
if (userRepo.Get().Any())
|
||||
return;
|
||||
|
||||
// Define credentials
|
||||
@@ -202,43 +246,53 @@ public class CoreFeature : MoonlightFeature
|
||||
var user = userRepo.Get().First(x => x.Username == username);
|
||||
user.Permissions = 9999;
|
||||
userRepo.Update(user);
|
||||
|
||||
|
||||
Logger.Info($"Default login: Email: '{email}' Password: '{password}'");
|
||||
});
|
||||
|
||||
// Api
|
||||
if (config.Development.EnableApiReference)
|
||||
app.MapSwagger("/api/core/reference/openapi/{documentName}");
|
||||
|
||||
app.UseMiddleware<ApiPermissionMiddleware>();
|
||||
|
||||
await pluginService.RegisterImplementation<IApiDefinition>(new InternalApiDefinition());
|
||||
}
|
||||
|
||||
public override Task OnUiInitialized(UiInitContext context)
|
||||
{
|
||||
context.EnablePages<CoreFeature>();
|
||||
|
||||
|
||||
// User pages
|
||||
context.AddSidebarItem("Dashboard", "bxs-dashboard", "/", needsExactMatch: true, index: int.MinValue);
|
||||
|
||||
|
||||
// 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("API", "bx-code-curly", "/admin/api", needsExactMatch: false, isAdmin: true);
|
||||
context.AddSidebarItem("System", "bxs-component", "/admin/sys", needsExactMatch: false, isAdmin: true);
|
||||
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override async Task OnSessionInitialized(SessionInitContext context)
|
||||
{
|
||||
var lazyLoader = context.LazyLoader;
|
||||
|
||||
|
||||
// - Authentication
|
||||
var cookieService = context.ServiceProvider.GetRequiredService<CookieService>();
|
||||
var identityService = context.ServiceProvider.GetRequiredService<IdentityService>();
|
||||
|
||||
|
||||
await lazyLoader.SetText("Authenticating");
|
||||
var token = await cookieService.GetValue("token");
|
||||
await identityService.Authenticate(token);
|
||||
|
||||
|
||||
// - Session
|
||||
await lazyLoader.SetText("Starting session");
|
||||
var scopedStorageService = context.ServiceProvider.GetRequiredService<ScopedStorageService>();
|
||||
var sessionService = context.ServiceProvider.GetRequiredService<SessionService>();
|
||||
|
||||
|
||||
var navigationManager = context.ServiceProvider.GetRequiredService<NavigationManager>();
|
||||
var alertService = context.ServiceProvider.GetRequiredService<AlertService>();
|
||||
|
||||
@@ -253,15 +307,12 @@ public class CoreFeature : MoonlightFeature
|
||||
};
|
||||
|
||||
// Setup updating
|
||||
navigationManager.LocationChanged += (_, _) =>
|
||||
{
|
||||
session.UpdatedAt = DateTime.UtcNow;
|
||||
};
|
||||
|
||||
navigationManager.LocationChanged += (_, _) => { session.UpdatedAt = DateTime.UtcNow; };
|
||||
|
||||
// Save session and session service to view storage
|
||||
scopedStorageService.Set("Session", session);
|
||||
scopedStorageService.Set("SessionService", sessionService);
|
||||
|
||||
|
||||
// Register session
|
||||
await sessionService.Add(session);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public class DataContext : DbContext
|
||||
|
||||
// Core
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<ApiKey> ApiKeys { get; set; }
|
||||
|
||||
// Servers
|
||||
public DbSet<Server> Servers { get; set; }
|
||||
|
||||
11
Moonlight/Core/Database/Entities/ApiKey.cs
Normal file
11
Moonlight/Core/Database/Entities/ApiKey.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Moonlight.Core.Database.Entities;
|
||||
|
||||
public class ApiKey
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Key { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
public DateTime ExpiresAt { get; set; } = DateTime.UtcNow;
|
||||
public string PermissionJson { get; set; } = "[]";
|
||||
}
|
||||
657
Moonlight/Core/Database/Migrations/20240605120928_AddedApiKeys.Designer.cs
generated
Normal file
657
Moonlight/Core/Database/Migrations/20240605120928_AddedApiKeys.Designer.cs
generated
Normal file
@@ -0,0 +1,657 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Moonlight.Core.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.Core.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20240605120928_AddedApiKeys")]
|
||||
partial class AddedApiKeys
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.6")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Moonlight.Core.Database.Entities.ApiKey", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PermissionJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApiKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Core.Database.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Flags")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Permissions")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("TokenValidTimestamp")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<bool>("Totp")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("TotpSecret")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.Server", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("Cpu")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("DisablePublicNetwork")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("Disk")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("DockerImageIndex")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ImageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MainAllocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Memory")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("NetworkId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("NodeId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("OverrideStartupCommand")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("UseVirtualDisk")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ImageId");
|
||||
|
||||
b.HasIndex("MainAllocationId");
|
||||
|
||||
b.HasIndex("NetworkId");
|
||||
|
||||
b.HasIndex("NodeId");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("Servers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerAllocation", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("IpAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Note")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Port")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ServerNodeId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("ServerNodeId");
|
||||
|
||||
b.ToTable("ServerAllocations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerBackup", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("Completed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Size")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Successful")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("ServerBackup");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerDockerImage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("AutoPull")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("ServerImageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerImageId");
|
||||
|
||||
b.ToTable("ServerDockerImages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerImage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AllocationsNeeded")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("AllowDockerImageChange")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Author")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("DefaultDockerImage")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("DonateUrl")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("InstallDockerImage")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("InstallScript")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("InstallShell")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("OnlineDetection")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ParseConfiguration")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("StartupCommand")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("StopCommand")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("UpdateUrl")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ServerImages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerImageVariable", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("AllowEdit")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("AllowView")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("DefaultValue")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Filter")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("ServerImageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerImageId");
|
||||
|
||||
b.ToTable("ServerImageVariables");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerNetwork", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("NodeId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NodeId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ServerNetworks");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerNode", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Fqdn")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("FtpPort")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HttpPort")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("Ssl")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Token")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ServerNodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerSchedule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("ExecutionSeconds")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("LastRun")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("ServerSchedules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerScheduleItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Action")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("DataJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ServerScheduleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerScheduleId");
|
||||
|
||||
b.ToTable("ServerScheduleItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerVariable", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("ServerVariables");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.Server", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerImage", "Image")
|
||||
.WithMany()
|
||||
.HasForeignKey("ImageId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerAllocation", "MainAllocation")
|
||||
.WithMany()
|
||||
.HasForeignKey("MainAllocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerNetwork", "Network")
|
||||
.WithMany()
|
||||
.HasForeignKey("NetworkId");
|
||||
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerNode", "Node")
|
||||
.WithMany()
|
||||
.HasForeignKey("NodeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.Core.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Image");
|
||||
|
||||
b.Navigation("MainAllocation");
|
||||
|
||||
b.Navigation("Network");
|
||||
|
||||
b.Navigation("Node");
|
||||
|
||||
b.Navigation("Owner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerAllocation", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.Server", null)
|
||||
.WithMany("Allocations")
|
||||
.HasForeignKey("ServerId");
|
||||
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerNode", null)
|
||||
.WithMany("Allocations")
|
||||
.HasForeignKey("ServerNodeId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerBackup", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.Server", null)
|
||||
.WithMany("Backups")
|
||||
.HasForeignKey("ServerId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerDockerImage", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerImage", null)
|
||||
.WithMany("DockerImages")
|
||||
.HasForeignKey("ServerImageId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerImageVariable", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerImage", null)
|
||||
.WithMany("Variables")
|
||||
.HasForeignKey("ServerImageId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerNetwork", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerNode", "Node")
|
||||
.WithMany()
|
||||
.HasForeignKey("NodeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.Core.Database.Entities.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Node");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerSchedule", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.Server", null)
|
||||
.WithMany("Schedules")
|
||||
.HasForeignKey("ServerId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerScheduleItem", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.ServerSchedule", null)
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("ServerScheduleId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerVariable", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.Features.Servers.Entities.Server", null)
|
||||
.WithMany("Variables")
|
||||
.HasForeignKey("ServerId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.Server", b =>
|
||||
{
|
||||
b.Navigation("Allocations");
|
||||
|
||||
b.Navigation("Backups");
|
||||
|
||||
b.Navigation("Schedules");
|
||||
|
||||
b.Navigation("Variables");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerImage", b =>
|
||||
{
|
||||
b.Navigation("DockerImages");
|
||||
|
||||
b.Navigation("Variables");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerNode", b =>
|
||||
{
|
||||
b.Navigation("Allocations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Features.Servers.Entities.ServerSchedule", b =>
|
||||
{
|
||||
b.Navigation("Items");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.Core.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedApiKeys : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ApiKeys",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Key = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Description = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
ExpiresAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||
PermissionJson = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ApiKeys", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ApiKeys");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Moonlight.Core.Database;
|
||||
|
||||
@@ -16,15 +17,50 @@ namespace Moonlight.Core.Database.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.2")
|
||||
.HasAnnotation("ProductVersion", "8.0.6")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Moonlight.Core.Database.Entities.ApiKey", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PermissionJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ApiKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.Core.Database.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
@@ -68,6 +104,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("Cpu")
|
||||
.HasColumnType("int");
|
||||
|
||||
@@ -129,6 +167,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("IpAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -161,6 +201,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("Completed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
@@ -189,6 +231,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("AutoPull")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
@@ -216,6 +260,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AllocationsNeeded")
|
||||
.HasColumnType("int");
|
||||
|
||||
@@ -278,6 +324,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("AllowEdit")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
@@ -322,6 +370,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -347,6 +397,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Fqdn")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -379,6 +431,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("ExecutionSeconds")
|
||||
.HasColumnType("int");
|
||||
|
||||
@@ -405,6 +459,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Action")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
@@ -432,6 +488,8 @@ namespace Moonlight.Core.Database.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
55
Moonlight/Core/Http/Controllers/ApiReferenceController.cs
Normal file
55
Moonlight/Core/Http/Controllers/ApiReferenceController.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
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][RegularExpression("^[a-z0-9_\\-]+$")] 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" +
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/api/core/asset/Core/css/scalar.css\" />\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 MoonCore.Helpers;
|
||||
using Moonlight.Core.Attributes;
|
||||
|
||||
namespace Moonlight.Core.Http.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[ApiDocument("internal")]
|
||||
[Route("api/core/asset")]
|
||||
public class AssetController : Controller
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using MoonCore.Abstractions;
|
||||
using MoonCore.Helpers;
|
||||
using MoonCore.Services;
|
||||
using Moonlight.Core.Attributes;
|
||||
using Moonlight.Core.Configuration;
|
||||
using Moonlight.Core.Database.Entities;
|
||||
using Moonlight.Core.Services;
|
||||
@@ -11,6 +12,7 @@ using Moonlight.Core.Services;
|
||||
namespace Moonlight.Core.Http.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[ApiDocument("internal")]
|
||||
[Route("api/core/avatar")]
|
||||
public class AvatarController : Controller
|
||||
{
|
||||
|
||||
97
Moonlight/Core/Http/Middleware/ApiPermissionMiddleware.cs
Normal file
97
Moonlight/Core/Http/Middleware/ApiPermissionMiddleware.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using MoonCore.Abstractions;
|
||||
using Moonlight.Core.Attributes;
|
||||
using Moonlight.Core.Database.Entities;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Moonlight.Core.Http.Middleware;
|
||||
|
||||
public class ApiPermissionMiddleware
|
||||
{
|
||||
private RequestDelegate Next;
|
||||
private readonly IServiceProvider Provider;
|
||||
|
||||
public ApiPermissionMiddleware(RequestDelegate next, IServiceProvider provider)
|
||||
{
|
||||
Next = next;
|
||||
Provider = provider;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
if (CheckRequest(context))
|
||||
await Next(context);
|
||||
else
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
await context.Response.WriteAsync("Permission denied");
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckRequest(HttpContext context)
|
||||
{
|
||||
var endpoint = context.GetEndpoint();
|
||||
|
||||
if (endpoint == null)
|
||||
return true;
|
||||
|
||||
var metadata = endpoint
|
||||
.Metadata
|
||||
.GetMetadata<ControllerActionDescriptor>();
|
||||
|
||||
if (metadata == null)
|
||||
return true;
|
||||
|
||||
var controllerAttrInfo = metadata.ControllerTypeInfo.CustomAttributes
|
||||
.FirstOrDefault(x => x.AttributeType == typeof(ApiPermissionAttribute));
|
||||
|
||||
var methodAttrInfo = metadata.MethodInfo.CustomAttributes
|
||||
.FirstOrDefault(x => x.AttributeType == typeof(ApiPermissionAttribute));
|
||||
|
||||
if (methodAttrInfo == null && controllerAttrInfo == null)
|
||||
return true;
|
||||
|
||||
if (!context.Request.Headers.TryGetValue("Authorization", out var apiKeySv))
|
||||
return false;
|
||||
|
||||
// Entity framework won't work with the StringValues type returned by the Headers.TryGetValue method
|
||||
// that's why we convert that to a regular string here
|
||||
var apiKey = apiKeySv.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(apiKey))
|
||||
return false;
|
||||
|
||||
using var scope = Provider.CreateScope();
|
||||
var apiKeyRepo = scope.ServiceProvider.GetRequiredService<Repository<ApiKey>>();
|
||||
|
||||
var apiKeyModel = apiKeyRepo
|
||||
.Get()
|
||||
.FirstOrDefault(x => x.Key == apiKey);
|
||||
|
||||
if (apiKeyModel == null)
|
||||
return false;
|
||||
|
||||
if (apiKeyModel.ExpiresAt < DateTime.UtcNow)
|
||||
return false;
|
||||
|
||||
var permissions = JsonConvert.DeserializeObject<string[]>(apiKeyModel.PermissionJson) ?? Array.Empty<string>();
|
||||
|
||||
if (controllerAttrInfo != null)
|
||||
{
|
||||
var permissionToLookFor = controllerAttrInfo.ConstructorArguments.First().Value as string;
|
||||
|
||||
if (permissionToLookFor != null && !permissions.Contains(permissionToLookFor))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodAttrInfo != null)
|
||||
{
|
||||
var permissionToLookFor = methodAttrInfo.ConstructorArguments.First().Value as string;
|
||||
|
||||
if (permissionToLookFor != null && !permissions.Contains(permissionToLookFor))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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 Moonlight.Core.Services;
|
||||
|
||||
namespace Moonlight.Core.Models.Abstractions.Feature;
|
||||
|
||||
@@ -7,6 +8,7 @@ public class PreInitContext
|
||||
public WebApplicationBuilder Builder { get; set; }
|
||||
public List<Assembly> DiAssemblies { get; set; } = new();
|
||||
public Dictionary<string, List<string>> Assets { get; set; } = new();
|
||||
public PluginService Plugins { get; set; }
|
||||
|
||||
public void EnableDependencyInjection<T>()
|
||||
{
|
||||
|
||||
19
Moonlight/Core/Models/Forms/ApiKeys/CreateApiKeyForm.cs
Normal file
19
Moonlight/Core/Models/Forms/ApiKeys/CreateApiKeyForm.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Core.Models.Forms.ApiKeys;
|
||||
|
||||
public class CreateApiKeyForm
|
||||
{
|
||||
[Required(ErrorMessage = "You need to provide a description")]
|
||||
[Description("Write a note here for which application the api key is used for")]
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to specify the expiration date of the api key")]
|
||||
[Description("Specify when the api key should expire")]
|
||||
public DateTime ExpiresAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[Required(ErrorMessage = "You need to specify what permissions the api key should have")]
|
||||
[DisplayName("Permissions")]
|
||||
public string PermissionJson { get; set; } = "[]";
|
||||
}
|
||||
19
Moonlight/Core/Models/Forms/ApiKeys/UpdateApiKeyForm.cs
Normal file
19
Moonlight/Core/Models/Forms/ApiKeys/UpdateApiKeyForm.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Core.Models.Forms.ApiKeys;
|
||||
|
||||
public class UpdateApiKeyForm
|
||||
{
|
||||
[Required(ErrorMessage = "You need to provide a description")]
|
||||
[Description("Write a note here for which application the api key is used for")]
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
[Required(ErrorMessage = "You need to specify the expiration date of the api key")]
|
||||
[Description("Specify when the api key should expire")]
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "You need to specify what permissions the api key should have")]
|
||||
[DisplayName("Permissions")]
|
||||
public string PermissionJson { get; set; } = "[]";
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public async Task PreInit(WebApplicationBuilder builder)
|
||||
public async Task PreInit(WebApplicationBuilder builder, PluginService pluginService)
|
||||
{
|
||||
Logger.Info("Pre-initializing features");
|
||||
|
||||
PreInitContext.Builder = builder;
|
||||
PreInitContext.Plugins = pluginService;
|
||||
|
||||
foreach (var feature in Features)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="row mb-3">
|
||||
<ul class="nav nav-tabs nav-line-tabs nav-line-tabs-2x mb-5 fs-6 border-bottom-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-white @(Index == 0 ? "active" : "")" href="/admin/api">Registered APIs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-white @(Index == 1 ? "active" : "")" href="/admin/api/keys">API Keys</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter] public int Index { get; set; } = 0;
|
||||
}
|
||||
80
Moonlight/Core/UI/Views/Admin/Api/Index.razor
Normal file
80
Moonlight/Core/UI/Views/Admin/Api/Index.razor
Normal file
@@ -0,0 +1,80 @@
|
||||
@page "/admin/api"
|
||||
|
||||
@using MoonCore.Services
|
||||
@using Moonlight.Core.Configuration
|
||||
@using Moonlight.Core.Interfaces
|
||||
@using Moonlight.Core.Services
|
||||
@using Moonlight.Core.UI.Components.Navigations
|
||||
|
||||
@inject PluginService PluginService
|
||||
@inject ConfigService<CoreConfiguration> ConfigService
|
||||
|
||||
@attribute [RequirePermission(9998)]
|
||||
|
||||
<AdminApiNavigation Index="0" />
|
||||
|
||||
<Tooltip>
|
||||
These apis allow other applications to communicate with moonlight and for example create a new user.
|
||||
These apis are still work in progress and might change a lot so dont be mad at me if i change how they work.
|
||||
</Tooltip>
|
||||
|
||||
<div class="mt-5">
|
||||
<div class="card card-body py-3 px-5">
|
||||
<LazyLoader Load="LoadApis">
|
||||
<CrudTable TItem="ApiModel" ItemSource="Apis" PageSize="100" ShowPagination="false">
|
||||
<CrudColumn TItem="ApiModel" Field="@(x => x.Id)" Title="Id" />
|
||||
<CrudColumn TItem="ApiModel" Field="@(x => x.Name)" Title="Name" />
|
||||
<CrudColumn TItem="ApiModel" Field="@(x => x.Version)" Title="Version" />
|
||||
<CrudColumn TItem="ApiModel">
|
||||
<Template>
|
||||
<div class="text-end">
|
||||
@if (ConfigService.Get().Development.EnableApiReference)
|
||||
{
|
||||
<a href="/api/core/reference?document=@(context.Id)" target="_blank" class="btn btn-primary">
|
||||
<i class="bx bx-sm bx-link"></i>
|
||||
Reference
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-primary disabled" disabled="disabled">
|
||||
<i class="bx bx-sm bx-link"></i>
|
||||
Enable reference in settings
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</Template>
|
||||
</CrudColumn>
|
||||
</CrudTable>
|
||||
</LazyLoader>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private ApiModel[] Apis;
|
||||
|
||||
private async Task LoadApis(LazyLoader _)
|
||||
{
|
||||
List<ApiModel> models = new();
|
||||
|
||||
foreach (var definition in await PluginService.GetImplementations<IApiDefinition>())
|
||||
{
|
||||
models.Add(new()
|
||||
{
|
||||
Id = definition.GetId(),
|
||||
Name = definition.GetName(),
|
||||
Version = definition.GetVersion()
|
||||
});
|
||||
}
|
||||
|
||||
Apis = models.ToArray();
|
||||
}
|
||||
|
||||
class ApiModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Version { get; set; }
|
||||
}
|
||||
}
|
||||
70
Moonlight/Core/UI/Views/Admin/Api/Keys.razor
Normal file
70
Moonlight/Core/UI/Views/Admin/Api/Keys.razor
Normal file
@@ -0,0 +1,70 @@
|
||||
@page "/admin/api/keys"
|
||||
|
||||
@using MoonCore.Abstractions
|
||||
@using MoonCore.Helpers
|
||||
@using MoonCoreUI.Services
|
||||
@using Moonlight.Core.Database.Entities
|
||||
@using Moonlight.Core.Models.Forms.ApiKeys
|
||||
@using Moonlight.Core.UI.Components.Navigations
|
||||
|
||||
@inject ClipboardService ClipboardService
|
||||
@inject ToastService ToastService
|
||||
|
||||
@attribute [RequirePermission(9998)]
|
||||
|
||||
<AdminApiNavigation Index="1"/>
|
||||
|
||||
<div class="mt-5">
|
||||
<AutoCrud TItem="ApiKey"
|
||||
TCreateForm="CreateApiKeyForm"
|
||||
TUpdateForm="UpdateApiKeyForm"
|
||||
Loader="ApiKeysLoader"
|
||||
ValidateAdd="ValidateAdd">
|
||||
<View>
|
||||
<CrudColumn TItem="ApiKey" Field="@(x => x.Key)" Title="Key">
|
||||
<Template>
|
||||
@{
|
||||
var apiKeyHalf = Formatter.CutInHalf(context!.Key);
|
||||
var bogusHalf = Formatter.IntToStringWithLeadingZeros(69, apiKeyHalf.Length);
|
||||
}
|
||||
|
||||
<div>
|
||||
<span class="blur-unless-hover">
|
||||
@apiKeyHalf
|
||||
[...]
|
||||
</span>
|
||||
</div>
|
||||
</Template>
|
||||
</CrudColumn>
|
||||
<CrudColumn TItem="ApiKey" Field="@(x => x.Description)" Title="Description"/>
|
||||
<CrudColumn TItem="ApiKey" Field="@(x => x.CreatedAt)" Title="Created at">
|
||||
<Template>
|
||||
@Formatter.FormatDate(context!.CreatedAt)
|
||||
</Template>
|
||||
</CrudColumn>
|
||||
<CrudColumn TItem="ApiKey" Field="@(x => x.ExpiresAt)" Title="Expires at">
|
||||
<Template>
|
||||
@Formatter.FormatDate(context!.ExpiresAt)
|
||||
</Template>
|
||||
</CrudColumn>
|
||||
<CrudColumn TItem="ApiKey" Field="@(x => x.PermissionJson)" Title="Permissions"/>
|
||||
</View>
|
||||
</AutoCrud>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private IEnumerable<ApiKey> ApiKeysLoader(Repository<ApiKey> repository)
|
||||
{
|
||||
return repository.Get();
|
||||
}
|
||||
|
||||
private async Task ValidateAdd(ApiKey apiKey)
|
||||
{
|
||||
var key = Formatter.GenerateString(32);
|
||||
apiKey.Key = key;
|
||||
|
||||
await ClipboardService.Copy(key);
|
||||
await ToastService.Info("Copied api key into your clipboard");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
@@ -85,14 +85,19 @@
|
||||
<PackageReference Include="Blazor.ContextMenu" Version="1.17.0" />
|
||||
<PackageReference Include="BlazorTable" Version="1.17.0" />
|
||||
<PackageReference Include="JWT" Version="10.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MimeTypes" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MoonCore" Version="1.3.4" />
|
||||
<PackageReference Include="MoonCoreUI" Version="1.2.0" />
|
||||
<PackageReference Include="MoonCore" Version="1.3.5" />
|
||||
<PackageReference Include="MoonCoreUI" Version="1.2.1" />
|
||||
<PackageReference Include="Otp.NET" Version="1.3.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
||||
<PackageReference Include="XtermBlazor" Version="1.10.2" />
|
||||
<PackageReference Include="Z.Blazor.Diagrams" Version="3.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -105,7 +105,7 @@ builder.Services.AddSingleton(configService);
|
||||
builder.Services.AddSingleton(pluginService);
|
||||
|
||||
// Feature hook
|
||||
await featureService.PreInit(builder);
|
||||
await featureService.PreInit(builder, pluginService);
|
||||
|
||||
// Plugin hook
|
||||
await pluginService.PreInitialize(builder);
|
||||
|
||||
Reference in New Issue
Block a user