Made moonlight able to compile and somehwat run with MoonCore.Blazor and the new logging system
This commit is contained in:
@@ -3,14 +3,10 @@ using Microsoft.AspNetCore.Components;
|
|||||||
using MoonCore.Abstractions;
|
using MoonCore.Abstractions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.Services;
|
using MoonCore.Services;
|
||||||
using MoonCoreUI.Extensions;
|
|
||||||
using MoonCoreUI.Services;
|
|
||||||
using Moonlight.Core.Configuration;
|
using Moonlight.Core.Configuration;
|
||||||
using Moonlight.Core.Database;
|
using Moonlight.Core.Database;
|
||||||
using Moonlight.Core.Database.Entities;
|
using Moonlight.Core.Database.Entities;
|
||||||
using Moonlight.Core.Implementations.Diagnose;
|
using Moonlight.Core.Implementations.Diagnose;
|
||||||
using Moonlight.Core.Implementations.UI.Admin.AdminColumns;
|
|
||||||
using Moonlight.Core.Implementations.UI.Index;
|
|
||||||
using Moonlight.Core.Interfaces;
|
using Moonlight.Core.Interfaces;
|
||||||
using Moonlight.Core.Interfaces.Ui.Admin;
|
using Moonlight.Core.Interfaces.Ui.Admin;
|
||||||
using Moonlight.Core.Interfaces.UI.User;
|
using Moonlight.Core.Interfaces.UI.User;
|
||||||
@@ -21,10 +17,16 @@ using Moonlight.Core.Models.Enums;
|
|||||||
using Moonlight.Core.Repositories;
|
using Moonlight.Core.Repositories;
|
||||||
using Moonlight.Core.Services;
|
using Moonlight.Core.Services;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using MoonCore.Blazor.Extensions;
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
|
using MoonCore.Extensions;
|
||||||
using Moonlight.Core.Attributes;
|
using Moonlight.Core.Attributes;
|
||||||
using Moonlight.Core.Http.Middleware;
|
using Moonlight.Core.Http.Middleware;
|
||||||
|
using Moonlight.Core.Implementations.AdminDashboard;
|
||||||
using Moonlight.Core.Implementations.ApiDefinition;
|
using Moonlight.Core.Implementations.ApiDefinition;
|
||||||
|
using Moonlight.Core.Implementations.UserDashboard;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using IdentityService = Moonlight.Core.Services.IdentityService;
|
||||||
|
|
||||||
namespace Moonlight.Core;
|
namespace Moonlight.Core;
|
||||||
|
|
||||||
@@ -54,25 +56,21 @@ public class CoreFeature : MoonlightFeature
|
|||||||
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,
|
||||||
|
context.LoggerFactory.CreateLogger<JwtService<CoreJwtType>>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// 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<FileDownloadService>();
|
builder.Services.AddMoonCore(configuration =>
|
||||||
builder.Services.AddScoped<AlertService>();
|
|
||||||
builder.Services.AddScoped<ToastService>();
|
|
||||||
builder.Services.AddScoped<ClipboardService>();
|
|
||||||
builder.Services.AddScoped<ModalService>();
|
|
||||||
|
|
||||||
builder.Services.AddMoonCoreUi(configuration =>
|
|
||||||
{
|
{
|
||||||
configuration.ToastJavascriptPrefix = "moonlight.toasts";
|
configuration.Identity.Token = config.Security.Token;
|
||||||
configuration.ModalJavascriptPrefix = "moonlight.modals";
|
|
||||||
configuration.AlertJavascriptPrefix = "moonlight.alerts";
|
|
||||||
configuration.ClipboardJavascriptPrefix = "moonlight.clipboard";
|
|
||||||
configuration.FileDownloadJavascriptPrefix = "moonlight.utils";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.Services.AddMoonCoreBlazor();
|
||||||
|
|
||||||
// Add external services and blazor/asp.net stuff
|
// Add external services and blazor/asp.net stuff
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
@@ -183,7 +181,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
Name = "Manage admin api access",
|
Name = "Manage admin api access",
|
||||||
Description = "Allows access to manage api keys and their permissions"
|
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",
|
||||||
@@ -218,9 +216,9 @@ public class CoreFeature : MoonlightFeature
|
|||||||
{
|
{
|
||||||
using var scope = provider.CreateScope();
|
using var scope = provider.CreateScope();
|
||||||
|
|
||||||
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>();
|
||||||
|
var logger = scope.ServiceProvider.GetRequiredService<ILogger<CoreFeature>>();
|
||||||
|
|
||||||
if (!configService.Get().Authentication.UseDefaultAuthentication)
|
if (!configService.Get().Authentication.UseDefaultAuthentication)
|
||||||
return;
|
return;
|
||||||
@@ -238,7 +236,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
|
|
||||||
if (registeredUser == null)
|
if (registeredUser == null)
|
||||||
{
|
{
|
||||||
Logger.Warn("Unable to create default user. Register function returned null");
|
logger.LogWarning("Unable to create default user. Register function returned null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +245,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
user.Permissions = 9999;
|
user.Permissions = 9999;
|
||||||
userRepo.Update(user);
|
userRepo.Update(user);
|
||||||
|
|
||||||
Logger.Info($"Default login: Email: '{email}' Password: '{password}'");
|
logger.LogInformation("Default login: Email: '{email}' Password: '{password}'", email, password);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Api
|
// Api
|
||||||
@@ -255,7 +253,7 @@ public class CoreFeature : MoonlightFeature
|
|||||||
app.MapSwagger("/api/core/reference/openapi/{documentName}");
|
app.MapSwagger("/api/core/reference/openapi/{documentName}");
|
||||||
|
|
||||||
app.UseMiddleware<ApiPermissionMiddleware>();
|
app.UseMiddleware<ApiPermissionMiddleware>();
|
||||||
|
|
||||||
await pluginService.RegisterImplementation<IApiDefinition>(new InternalApiDefinition());
|
await pluginService.RegisterImplementation<IApiDefinition>(new InternalApiDefinition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
using MoonCore.Helpers;
|
using MoonCore.Attributes;
|
||||||
|
using MoonCore.Helpers;
|
||||||
|
|
||||||
namespace Moonlight.Core.Events;
|
namespace Moonlight.Core.Events;
|
||||||
|
|
||||||
|
[Singleton]
|
||||||
public class CoreEvents
|
public class CoreEvents
|
||||||
{
|
{
|
||||||
public static SmartEventHandler OnMoonlightRestart { get; set; } = new();
|
public CoreEvents(ILogger<SmartEventHandler> logger)
|
||||||
|
{
|
||||||
|
OnMoonlightRestart = new(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmartEventHandler OnMoonlightRestart { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,21 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using MoonCore.Attributes;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
|
||||||
namespace Moonlight.Core.Helpers;
|
namespace Moonlight.Core.Helpers;
|
||||||
|
|
||||||
public static class HostSystemHelper
|
[Singleton]
|
||||||
|
public class HostSystemHelper
|
||||||
{
|
{
|
||||||
public static Task<string> GetOsName()
|
private readonly ILogger<HostSystemHelper> Logger;
|
||||||
|
|
||||||
|
public HostSystemHelper(ILogger<HostSystemHelper> logger)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> GetOsName()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -48,21 +57,20 @@ public static class HostSystemHelper
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn("Error retrieving os information");
|
Logger.LogWarning("Error retrieving os information: {e}", e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
return Task.FromResult("N/A");
|
return Task.FromResult("N/A");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<long> GetMemoryUsage()
|
public Task<long> GetMemoryUsage()
|
||||||
{
|
{
|
||||||
var process = Process.GetCurrentProcess();
|
var process = Process.GetCurrentProcess();
|
||||||
var bytes = process.PrivateMemorySize64;
|
var bytes = process.PrivateMemorySize64;
|
||||||
return Task.FromResult(bytes);
|
return Task.FromResult(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<int> GetCpuUsage()
|
public Task<int> GetCpuUsage()
|
||||||
{
|
{
|
||||||
var process = Process.GetCurrentProcess();
|
var process = Process.GetCurrentProcess();
|
||||||
var cpuTime = process.TotalProcessorTime;
|
var cpuTime = process.TotalProcessorTime;
|
||||||
|
|||||||
@@ -9,13 +9,20 @@ namespace Moonlight.Core.Http.Controllers;
|
|||||||
[Route("api/core/asset")]
|
[Route("api/core/asset")]
|
||||||
public class AssetController : Controller
|
public class AssetController : Controller
|
||||||
{
|
{
|
||||||
|
private readonly ILogger<AssetController> Logger;
|
||||||
|
|
||||||
|
public AssetController(ILogger<AssetController> logger)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("{name}/{*path}")]
|
[HttpGet("{name}/{*path}")]
|
||||||
public async Task<ActionResult> Get(string name, string path)
|
public async Task<ActionResult> Get(string name, string path)
|
||||||
{
|
{
|
||||||
// Check for path transversal attacks
|
// Check for path transversal attacks
|
||||||
if (path.Contains("..") || name.Contains(".."))
|
if (path.Contains("..") || name.Contains(".."))
|
||||||
{
|
{
|
||||||
Logger.Warn($"{HttpContext.Connection.RemoteIpAddress} tried to use path transversal attack: {name}/{path}");
|
Logger.LogWarning("{remoteIp} tried to use path transversal attack: {name}/{path}", HttpContext.Connection.RemoteIpAddress, name, path);
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ 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;
|
||||||
|
using IdentityService = Moonlight.Core.Services.IdentityService;
|
||||||
|
|
||||||
namespace Moonlight.Core.Http.Controllers;
|
namespace Moonlight.Core.Http.Controllers;
|
||||||
|
|
||||||
@@ -19,15 +20,17 @@ public class AvatarController : Controller
|
|||||||
private readonly Repository<User> UserRepository;
|
private readonly Repository<User> UserRepository;
|
||||||
private readonly ConfigService<CoreConfiguration> ConfigService;
|
private readonly ConfigService<CoreConfiguration> ConfigService;
|
||||||
private readonly IdentityService IdentityService;
|
private readonly IdentityService IdentityService;
|
||||||
|
private readonly ILogger<AvatarController> Logger;
|
||||||
|
|
||||||
public AvatarController(
|
public AvatarController(
|
||||||
Repository<User> userRepository,
|
Repository<User> userRepository,
|
||||||
IdentityService identityService,
|
IdentityService identityService,
|
||||||
ConfigService<CoreConfiguration> configService)
|
ConfigService<CoreConfiguration> configService, ILogger<AvatarController> logger)
|
||||||
{
|
{
|
||||||
UserRepository = userRepository;
|
UserRepository = userRepository;
|
||||||
IdentityService = identityService;
|
IdentityService = identityService;
|
||||||
ConfigService = configService;
|
ConfigService = configService;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -88,11 +91,10 @@ public class AvatarController : Controller
|
|||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if(e is HttpRequestException requestException && requestException.InnerException is IOException ioException)
|
if(e is HttpRequestException requestException && requestException.InnerException is IOException ioException)
|
||||||
Logger.Warn($"Unable to fetch gravatar for user {user.Id}. Is moonlight inside a proxy requiring network?: {ioException.Message}");
|
Logger.LogWarning("Unable to fetch gravatar for user {userId}. Is moonlight inside a proxy requiring network?: {message}", user.Id, ioException.Message);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unable to fetch gravatar for user {user.Id}");
|
Logger.LogWarning("Unable to fetch gravatar for user {userId}: {e}", user.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MemoryStream();
|
return new MemoryStream();
|
||||||
|
|||||||
@@ -4,16 +4,18 @@ namespace Moonlight.Core.Http.Middleware;
|
|||||||
|
|
||||||
public class DebugLogMiddleware
|
public class DebugLogMiddleware
|
||||||
{
|
{
|
||||||
|
private readonly ILogger<DebugLogMiddleware> Logger;
|
||||||
private RequestDelegate Next;
|
private RequestDelegate Next;
|
||||||
|
|
||||||
public DebugLogMiddleware(RequestDelegate next)
|
public DebugLogMiddleware(RequestDelegate next, ILogger<DebugLogMiddleware> logger)
|
||||||
{
|
{
|
||||||
Next = next;
|
Next = next;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
Logger.Debug($"[{context.Request.Method.ToUpper()}] {context.Request.Path}");
|
Logger.LogDebug("[{method}] {path}", context.Request.Method.ToUpper(), context.Request.Path);
|
||||||
|
|
||||||
await Next(context);
|
await Next(context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using MoonCoreUI.Helpers;
|
using MoonCore.Blazor.Helpers;
|
||||||
using Moonlight.Core.Interfaces.Ui.Admin;
|
using Moonlight.Core.Interfaces.Ui.Admin;
|
||||||
using Moonlight.Core.Models.Abstractions;
|
using Moonlight.Core.Models.Abstractions;
|
||||||
using Moonlight.Core.UI.Components.Cards;
|
using Moonlight.Core.UI.Components.Cards;
|
||||||
|
|
||||||
namespace Moonlight.Core.Implementations.UI.Admin.AdminColumns;
|
namespace Moonlight.Core.Implementations.AdminDashboard;
|
||||||
|
|
||||||
public class UserCount : IAdminDashboardColumn
|
public class UserCount : IAdminDashboardColumn
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using MoonCoreUI.Helpers;
|
using MoonCore.Blazor.Helpers;
|
||||||
using Moonlight.Core.Interfaces.UI.User;
|
using Moonlight.Core.Interfaces.UI.User;
|
||||||
using Moonlight.Core.Models.Abstractions;
|
using Moonlight.Core.Models.Abstractions;
|
||||||
using Moonlight.Core.UI.Components.Cards;
|
using Moonlight.Core.UI.Components.Cards;
|
||||||
|
|
||||||
namespace Moonlight.Core.Implementations.UI.Index;
|
namespace Moonlight.Core.Implementations.UserDashboard;
|
||||||
|
|
||||||
public class GreetingMessages : IUserDashboardComponent
|
public class GreetingMessages : IUserDashboardComponent
|
||||||
{
|
{
|
||||||
@@ -9,6 +9,7 @@ public class PreInitContext
|
|||||||
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 PluginService Plugins { get; set; }
|
||||||
|
public ILoggerFactory LoggerFactory { get; set; }
|
||||||
|
|
||||||
public void EnableDependencyInjection<T>()
|
public void EnableDependencyInjection<T>()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MoonCoreUI.Components;
|
using MoonCore.Blazor.Components;
|
||||||
|
|
||||||
namespace Moonlight.Core.Models.Abstractions.Feature;
|
namespace Moonlight.Core.Models.Abstractions.Feature;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using MoonCoreUI.Attributes;
|
|
||||||
|
|
||||||
namespace Moonlight.Core.Models.Forms;
|
namespace Moonlight.Core.Models.Forms;
|
||||||
|
|
||||||
@@ -8,12 +7,12 @@ public class ChangePasswordForm
|
|||||||
[Required(ErrorMessage = "You need to provide a password")]
|
[Required(ErrorMessage = "You need to provide a password")]
|
||||||
[MinLength(8, ErrorMessage = "The password must be at least 8 characters long")]
|
[MinLength(8, ErrorMessage = "The password must be at least 8 characters long")]
|
||||||
[MaxLength(256, ErrorMessage = "The password must not be longer than 256 characters")]
|
[MaxLength(256, ErrorMessage = "The password must not be longer than 256 characters")]
|
||||||
[CustomFormType(Type = "password")]
|
//TODO: [CustomFormType(Type = "password")]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
[Required(ErrorMessage = "You need to provide a password")]
|
[Required(ErrorMessage = "You need to provide a password")]
|
||||||
[MinLength(8, ErrorMessage = "The password must be at least 8 characters long")]
|
[MinLength(8, ErrorMessage = "The password must be at least 8 characters long")]
|
||||||
[MaxLength(256, ErrorMessage = "The password must not be longer than 256 characters")]
|
[MaxLength(256, ErrorMessage = "The password must not be longer than 256 characters")]
|
||||||
[CustomFormType(Type = "password")]
|
//TODO: [CustomFormType(Type = "password")]
|
||||||
public string RepeatedPassword { get; set; }
|
public string RepeatedPassword { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using MoonCoreUI.Attributes;
|
|
||||||
|
|
||||||
namespace Moonlight.Core.Models.Forms.Users;
|
namespace Moonlight.Core.Models.Forms.Users;
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ public class UpdateUserForm
|
|||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
[Description("This toggles the use of the two factor authentication")]
|
[Description("This toggles the use of the two factor authentication")]
|
||||||
[RadioButtonBool("Enabled", "Disabled", TrueIcon = "bx-lock-alt", FalseIcon = "bx-lock-open-alt")]
|
//TODO: [RadioButtonBool("Enabled", "Disabled", TrueIcon = "bx-lock-alt", FalseIcon = "bx-lock-open-alt")]
|
||||||
[DisplayName("Two factor authentication")]
|
[DisplayName("Two factor authentication")]
|
||||||
public bool Totp { get; set; } = false;
|
public bool Totp { get; set; } = false;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MoonCoreUI.Services;
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Core.Services;
|
using Moonlight.Core.Services;
|
||||||
|
|
||||||
namespace Moonlight.Core.Models;
|
namespace Moonlight.Core.Models;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using MoonCore.Blazor.Components;
|
||||||
using MoonCore.Extensions;
|
using MoonCore.Extensions;
|
||||||
using MoonCore.Helpers;
|
|
||||||
using MoonCore.Services;
|
using MoonCore.Services;
|
||||||
using MoonCoreUI.Components;
|
|
||||||
using Moonlight.Core.Configuration;
|
using Moonlight.Core.Configuration;
|
||||||
using Moonlight.Core.Models.Abstractions.Feature;
|
using Moonlight.Core.Models.Abstractions.Feature;
|
||||||
|
|
||||||
@@ -15,15 +14,18 @@ public class FeatureService
|
|||||||
|
|
||||||
private readonly List<MoonlightFeature> Features = new();
|
private readonly List<MoonlightFeature> Features = new();
|
||||||
private readonly ConfigService<CoreConfiguration> ConfigService;
|
private readonly ConfigService<CoreConfiguration> ConfigService;
|
||||||
|
|
||||||
|
private readonly ILogger<FeatureService> Logger;
|
||||||
|
|
||||||
public FeatureService(ConfigService<CoreConfiguration> configService)
|
public FeatureService(ConfigService<CoreConfiguration> configService, ILogger<FeatureService> logger)
|
||||||
{
|
{
|
||||||
ConfigService = configService;
|
ConfigService = configService;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Load()
|
public Task Load()
|
||||||
{
|
{
|
||||||
Logger.Info("Loading features");
|
Logger.LogInformation("Loading features");
|
||||||
|
|
||||||
// TODO: Add dll loading here as well
|
// TODO: Add dll loading here as well
|
||||||
|
|
||||||
@@ -43,24 +45,25 @@ public class FeatureService
|
|||||||
|
|
||||||
if (feature == null)
|
if (feature == null)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unable to construct {featureType.FullName} feature");
|
Logger.LogWarning("Unable to construct '{name}' feature", featureType.FullName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Features.Add(feature);
|
Features.Add(feature);
|
||||||
|
|
||||||
Logger.Info($"Loaded feature '{feature.Name}' by '{feature.Author}'");
|
Logger.LogInformation("Loaded feature '{name}' by '{author}'", feature.Name, feature.Author);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PreInit(WebApplicationBuilder builder, PluginService pluginService)
|
public async Task PreInit(WebApplicationBuilder builder, PluginService pluginService, ILoggerFactory preRunLoggerFactory)
|
||||||
{
|
{
|
||||||
Logger.Info("Pre-initializing features");
|
Logger.LogInformation("Pre-initializing features");
|
||||||
|
|
||||||
PreInitContext.Builder = builder;
|
PreInitContext.Builder = builder;
|
||||||
PreInitContext.Plugins = pluginService;
|
PreInitContext.Plugins = pluginService;
|
||||||
|
PreInitContext.LoggerFactory = preRunLoggerFactory;
|
||||||
|
|
||||||
foreach (var feature in Features)
|
foreach (var feature in Features)
|
||||||
{
|
{
|
||||||
@@ -70,8 +73,7 @@ public class FeatureService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error($"An error occured while performing pre init for feature '{feature.Name}'");
|
Logger.LogError("An error occured while performing pre init for feature '{name}': {e}", feature.Name, e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +84,7 @@ public class FeatureService
|
|||||||
|
|
||||||
public async Task Init(WebApplication application)
|
public async Task Init(WebApplication application)
|
||||||
{
|
{
|
||||||
Logger.Info("Initializing features");
|
Logger.LogInformation("Initializing features");
|
||||||
|
|
||||||
var initContext = new InitContext()
|
var initContext = new InitContext()
|
||||||
{
|
{
|
||||||
@@ -97,15 +99,14 @@ public class FeatureService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error($"An error occured while performing init for feature '{feature.Name}'");
|
Logger.LogError("An error occured while performing init for feature '{name}': {e}", feature.Name, e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UiInit()
|
public async Task UiInit()
|
||||||
{
|
{
|
||||||
Logger.Info("Initializing feature uis");
|
Logger.LogInformation("Initializing feature uis");
|
||||||
|
|
||||||
foreach (var feature in Features)
|
foreach (var feature in Features)
|
||||||
{
|
{
|
||||||
@@ -115,8 +116,7 @@ public class FeatureService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error($"An error occured while performing ui init for feature '{feature.Name}'");
|
Logger.LogError("An error occured while performing ui init for feature '{name}': {e}", feature.Name, e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,8 +138,7 @@ public class FeatureService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error($"An error occured while performing session init for feature '{feature.Name}'");
|
Logger.LogError("An error occured while performing session init for feature '{name}': {e}", feature.Name, e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,8 +158,7 @@ public class FeatureService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error($"An error occured while performing session dispose for feature '{feature.Name}'");
|
Logger.LogError("An error occured while performing session dispose for feature '{name}': {e}", feature.Name, e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ public class HotKeyService
|
|||||||
private readonly IJSRuntime JsRuntime;
|
private readonly IJSRuntime JsRuntime;
|
||||||
private readonly List<HotKeyModel> HotKeys = new();
|
private readonly List<HotKeyModel> HotKeys = new();
|
||||||
|
|
||||||
public SmartEventHandler<string> HotKeyPressed { get; set; } = new();
|
public SmartEventHandler<string> HotKeyPressed { get; set; }
|
||||||
|
|
||||||
public HotKeyService(IJSRuntime jsRuntime)
|
public HotKeyService(IJSRuntime jsRuntime, ILogger<SmartEventHandler> eventHandlerLogger)
|
||||||
{
|
{
|
||||||
JsRuntime = jsRuntime;
|
JsRuntime = jsRuntime;
|
||||||
|
|
||||||
|
HotKeyPressed = new(eventHandlerLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RegisterHotkey(string key, string modifier, string action)
|
public async Task RegisterHotkey(string key, string modifier, string action)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class IdentityService : IDisposable
|
|||||||
public User? CurrentUserNullable { get; private set; }
|
public User? CurrentUserNullable { get; private set; }
|
||||||
public User CurrentUser => CurrentUserNullable!;
|
public User CurrentUser => CurrentUserNullable!;
|
||||||
public bool IsLoggedIn => CurrentUserNullable != null;
|
public bool IsLoggedIn => CurrentUserNullable != null;
|
||||||
public SmartEventHandler OnAuthenticationStateChanged { get; set; } = new();
|
public SmartEventHandler OnAuthenticationStateChanged { get; set; }
|
||||||
|
|
||||||
private string Token = "";
|
private string Token = "";
|
||||||
|
|
||||||
@@ -26,11 +26,14 @@ public class IdentityService : IDisposable
|
|||||||
public IdentityService(
|
public IdentityService(
|
||||||
JwtService<CoreJwtType> jwtService,
|
JwtService<CoreJwtType> jwtService,
|
||||||
ConfigService<CoreConfiguration> configService,
|
ConfigService<CoreConfiguration> configService,
|
||||||
Repository<User> userRepository)
|
Repository<User> userRepository,
|
||||||
|
ILogger<SmartEventHandler> eventHandlerLogger)
|
||||||
{
|
{
|
||||||
JwtService = jwtService;
|
JwtService = jwtService;
|
||||||
ConfigService = configService;
|
ConfigService = configService;
|
||||||
UserRepository = userRepository;
|
UserRepository = userRepository;
|
||||||
|
|
||||||
|
OnAuthenticationStateChanged = new(eventHandlerLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> Authenticate(User user)
|
public async Task<string> Authenticate(User user)
|
||||||
|
|||||||
@@ -10,10 +10,18 @@ public class MoonlightService
|
|||||||
public WebApplication Application { get; set; } // Do NOT modify using a plugin
|
public WebApplication Application { get; set; } // Do NOT modify using a plugin
|
||||||
|
|
||||||
private readonly DateTime StartTimestamp = DateTime.UtcNow;
|
private readonly DateTime StartTimestamp = DateTime.UtcNow;
|
||||||
|
private readonly CoreEvents CoreEvents;
|
||||||
|
private readonly ILogger<MoonlightService> Logger;
|
||||||
|
|
||||||
|
public MoonlightService(CoreEvents coreEvents, ILogger<MoonlightService> logger)
|
||||||
|
{
|
||||||
|
CoreEvents = coreEvents;
|
||||||
|
Logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Restart()
|
public async Task Restart()
|
||||||
{
|
{
|
||||||
Logger.Info("Restarting moonlight");
|
Logger.LogInformation("Restarting moonlight");
|
||||||
|
|
||||||
// Notify all users that this instance will restart
|
// Notify all users that this instance will restart
|
||||||
await CoreEvents.OnMoonlightRestart.Invoke();
|
await CoreEvents.OnMoonlightRestart.Invoke();
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ public class PluginService
|
|||||||
private readonly Dictionary<Type, List<object>> ImplementationCache = new();
|
private readonly Dictionary<Type, List<object>> ImplementationCache = new();
|
||||||
private readonly List<MoonlightPlugin> Plugins = new();
|
private readonly List<MoonlightPlugin> Plugins = new();
|
||||||
|
|
||||||
public PluginService()
|
private readonly ILogger<PluginService> Logger;
|
||||||
|
|
||||||
|
public PluginService(ILogger<PluginService> logger)
|
||||||
{
|
{
|
||||||
|
Logger = logger;
|
||||||
|
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins"));
|
Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +140,7 @@ public class PluginService
|
|||||||
|
|
||||||
if (pluginTypes.Length == 0)
|
if (pluginTypes.Length == 0)
|
||||||
{
|
{
|
||||||
Logger.Info($"Loaded assembly as library. {dllFile}");
|
Logger.LogInformation("Loaded assembly as library: {dllFile}", dllFile);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,19 +150,17 @@ public class PluginService
|
|||||||
{
|
{
|
||||||
var plugin = await LoadFromType(pluginType);
|
var plugin = await LoadFromType(pluginType);
|
||||||
|
|
||||||
Logger.Info($"Loaded plugin '{plugin.Name}'. Created by '{plugin.Author}'");
|
Logger.LogInformation("Loaded plugin '{name}'. Created by '{author}'", plugin.Name, plugin.Author);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Fatal($"An error occured while loading plugin '{pluginType.FullName}'");
|
Logger.LogError("An error occured while loading plugin '{name}': {e}", pluginType.FullName, e);
|
||||||
Logger.Fatal(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Fatal($"An error occured while loading assembly '{dllFile}'");
|
Logger.LogError("An error occured while loading assembly '{dllFile}': {e}", dllFile, e);
|
||||||
Logger.Fatal(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ public class StartupJobService : BackgroundService
|
|||||||
{
|
{
|
||||||
private readonly List<StartupJob> Jobs = new();
|
private readonly List<StartupJob> Jobs = new();
|
||||||
private readonly IServiceProvider ServiceProvider;
|
private readonly IServiceProvider ServiceProvider;
|
||||||
|
private readonly ILogger<StartupJobService> Logger;
|
||||||
|
|
||||||
public StartupJobService(IServiceProvider serviceProvider)
|
public StartupJobService(IServiceProvider serviceProvider, ILogger<StartupJobService> logger)
|
||||||
{
|
{
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AddJob(string name, TimeSpan delay, Func<IServiceProvider, Task> action)
|
public Task AddJob(string name, TimeSpan delay, Func<IServiceProvider, Task> action)
|
||||||
@@ -29,7 +31,7 @@ public class StartupJobService : BackgroundService
|
|||||||
|
|
||||||
public override Task Run()
|
public override Task Run()
|
||||||
{
|
{
|
||||||
Logger.Info("Running startup jobs");
|
Logger.LogInformation("Running startup jobs");
|
||||||
|
|
||||||
foreach (var job in Jobs)
|
foreach (var job in Jobs)
|
||||||
{
|
{
|
||||||
@@ -42,8 +44,7 @@ public class StartupJobService : BackgroundService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"The startup job '{job.Name}' failed:");
|
Logger.LogWarning("The startup job '{name}' failed: {e}", job.Name, e);
|
||||||
Logger.Warn(e);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,17 @@ namespace Moonlight.Core.Services;
|
|||||||
[Scoped]
|
[Scoped]
|
||||||
public class UnloadService
|
public class UnloadService
|
||||||
{
|
{
|
||||||
public SmartEventHandler OnUnloaded { get; set; } = new();
|
public SmartEventHandler OnUnloaded { get; set; }
|
||||||
|
|
||||||
private readonly IJSRuntime JsRuntime;
|
private readonly IJSRuntime JsRuntime;
|
||||||
|
private readonly ILogger<UnloadService> Logger;
|
||||||
|
|
||||||
public UnloadService(IJSRuntime jsRuntime)
|
public UnloadService(IJSRuntime jsRuntime, ILogger<SmartEventHandler> eventHandlerLogger, ILogger<UnloadService> logger)
|
||||||
{
|
{
|
||||||
JsRuntime = jsRuntime;
|
JsRuntime = jsRuntime;
|
||||||
|
Logger = logger;
|
||||||
|
|
||||||
|
OnUnloaded = new(eventHandlerLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize()
|
public async Task Initialize()
|
||||||
@@ -28,8 +32,7 @@ public class UnloadService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error("An error occured while registering unload event handler");
|
Logger.LogError("An error occured while registering unload event handler: {e}", e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
@using Moonlight.Core.Models.Forms
|
@using Moonlight.Core.Models.Forms
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject IAuthenticationProvider AuthenticationProvider
|
@inject IAuthenticationProvider AuthenticationProvider
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@@ -93,7 +92,7 @@
|
|||||||
var token = await IdentityService.Authenticate(user);
|
var token = await IdentityService.Authenticate(user);
|
||||||
|
|
||||||
// Save token for later use
|
// Save token for later use
|
||||||
await CookieService.SetValue("token", token);
|
await CookieService.SetValue("token", token, 30); //TODO: Add days to config option
|
||||||
|
|
||||||
// Forward the user if not on the specific page
|
// Forward the user if not on the specific page
|
||||||
if(new Uri(Navigation.Uri).LocalPath.StartsWith("/login"))
|
if(new Uri(Navigation.Uri).LocalPath.StartsWith("/login"))
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
|
@using IdentityService = Moonlight.Core.Services.IdentityService
|
||||||
|
|
||||||
@inject IAuthenticationProvider AuthenticationProvider
|
@inject IAuthenticationProvider AuthenticationProvider
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
var token = await IdentityService.Authenticate(user);
|
var token = await IdentityService.Authenticate(user);
|
||||||
|
|
||||||
// Save token for later use
|
// Save token for later use
|
||||||
await CookieService.SetValue("token", token);
|
await CookieService.SetValue("token", token, 30); // TODO: config
|
||||||
|
|
||||||
// Forward the user if not on the specific page
|
// Forward the user if not on the specific page
|
||||||
if(new Uri(Navigation.Uri).LocalPath.StartsWith("/register"))
|
if(new Uri(Navigation.Uri).LocalPath.StartsWith("/register"))
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ else
|
|||||||
private string Key = "";
|
private string Key = "";
|
||||||
private TwoFactorCodeForm CodeForm = new();
|
private TwoFactorCodeForm CodeForm = new();
|
||||||
|
|
||||||
private async Task Disable()
|
private async Task Disable(ConfirmButton _)
|
||||||
{
|
{
|
||||||
await AuthenticationProvider.SetTwoFactorSecret(IdentityService.CurrentUser, "");
|
await AuthenticationProvider.SetTwoFactorSecret(IdentityService.CurrentUser, "");
|
||||||
await IdentityService.Authenticate(true);
|
await IdentityService.Authenticate(true);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
|
@using IdentityService = Moonlight.Core.Services.IdentityService
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject CookieService CookieService
|
@inject CookieService CookieService
|
||||||
@@ -94,7 +93,7 @@
|
|||||||
private async Task Logout()
|
private async Task Logout()
|
||||||
{
|
{
|
||||||
// Reset token
|
// Reset token
|
||||||
await CookieService.SetValue("token", "");
|
await CookieService.SetValue("token", "", 30);
|
||||||
|
|
||||||
// Reset token in identity service
|
// Reset token in identity service
|
||||||
await IdentityService.Authenticate("");
|
await IdentityService.Authenticate("");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
|
@using IdentityService = Moonlight.Core.Services.IdentityService
|
||||||
|
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
|
@inject ILogger<SoftErrorHandler> Logger
|
||||||
|
|
||||||
@inherits ErrorBoundaryBase
|
@inherits ErrorBoundaryBase
|
||||||
|
|
||||||
@@ -75,8 +76,7 @@ else
|
|||||||
Crashed = true;
|
Crashed = true;
|
||||||
|
|
||||||
var username = IdentityService.IsLoggedIn ? IdentityService.CurrentUser.Username : "Guest";
|
var username = IdentityService.IsLoggedIn ? IdentityService.CurrentUser.Username : "Guest";
|
||||||
Logger.Warn($"A crash occured in the view of '{username}'");
|
Logger.LogWarning("A crash occured in the view of '{username}': {exception}", username, exception);
|
||||||
Logger.Warn(exception);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Recover();
|
Recover();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
@using Moonlight.Core.Events
|
@using Moonlight.Core.Events
|
||||||
|
@using IdentityService = Moonlight.Core.Services.IdentityService
|
||||||
|
|
||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
@inject UnloadService UnloadService
|
@inject UnloadService UnloadService
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
@inject ScopedStorageService ScopedStorageService
|
@inject ScopedStorageService ScopedStorageService
|
||||||
|
@inject CoreEvents CoreEvents
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
@@ -99,6 +101,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ModalLaunchPoint />
|
||||||
|
<ToastLaunchPoint />
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private bool IsInitialized = false;
|
private bool IsInitialized = false;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using Moonlight.Core.Models.Forms
|
@using Moonlight.Core.Models.Forms
|
||||||
@using Mappy.Net
|
@using Mappy.Net
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Models.Abstractions
|
@using Moonlight.Core.Models.Abstractions
|
||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@
|
|||||||
|
|
||||||
<AccountNavigation Index="0"/>
|
<AccountNavigation Index="0"/>
|
||||||
|
|
||||||
<LazyLoader Load="Load" ShowAsCard="true">
|
<LazyLoader Load="Load">
|
||||||
|
|
||||||
<div class="row g-5">
|
<div class="row g-5">
|
||||||
<div class="col-md-3 col-12">
|
<div class="col-md-3 col-12">
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@using Moonlight.Core.Models.Forms
|
@using Moonlight.Core.Models.Forms
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Models.Abstractions
|
@using Moonlight.Core.Models.Abstractions
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using Moonlight.Core.UI.Components.Auth
|
@using Moonlight.Core.UI.Components.Auth
|
||||||
|
|||||||
@@ -21,11 +21,11 @@
|
|||||||
<div class="mt-5">
|
<div class="mt-5">
|
||||||
<div class="card card-body py-3 px-5">
|
<div class="card card-body py-3 px-5">
|
||||||
<LazyLoader Load="LoadApis">
|
<LazyLoader Load="LoadApis">
|
||||||
<CrudTable TItem="ApiModel" ItemSource="Apis" PageSize="100" ShowPagination="false">
|
<MCBTable TItem="ApiModel" ItemSource="Apis" PageSize="100" ShowPagination="false">
|
||||||
<CrudColumn TItem="ApiModel" Field="@(x => x.Id)" Title="Id" />
|
<MCBColumn TItem="ApiModel" Field="@(x => x.Id)" Title="Id" />
|
||||||
<CrudColumn TItem="ApiModel" Field="@(x => x.Name)" Title="Name" />
|
<MCBColumn TItem="ApiModel" Field="@(x => x.Name)" Title="Name" />
|
||||||
<CrudColumn TItem="ApiModel" Field="@(x => x.Version)" Title="Version" />
|
<MCBColumn TItem="ApiModel" Field="@(x => x.Version)" Title="Version" />
|
||||||
<CrudColumn TItem="ApiModel">
|
<MCBColumn TItem="ApiModel">
|
||||||
<Template>
|
<Template>
|
||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
@if (ConfigService.Get().Development.EnableApiReference)
|
@if (ConfigService.Get().Development.EnableApiReference)
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</CrudTable>
|
</MCBTable>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@page "/admin/api/keys"
|
@page "/admin/api/keys"
|
||||||
|
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
|
@using MoonCore.Blazor.Models.Forms
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Database.Entities
|
@using Moonlight.Core.Database.Entities
|
||||||
@using Moonlight.Core.Models.Forms.ApiKeys
|
@using Moonlight.Core.Models.Forms.ApiKeys
|
||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@@ -19,9 +19,9 @@
|
|||||||
TCreateForm="CreateApiKeyForm"
|
TCreateForm="CreateApiKeyForm"
|
||||||
TUpdateForm="UpdateApiKeyForm"
|
TUpdateForm="UpdateApiKeyForm"
|
||||||
Loader="ApiKeysLoader"
|
Loader="ApiKeysLoader"
|
||||||
ValidateAdd="ValidateAdd">
|
OnConfigure="OnConfigure">
|
||||||
<View>
|
<View>
|
||||||
<CrudColumn TItem="ApiKey" Field="@(x => x.Key)" Title="Key">
|
<MCBColumn TItem="ApiKey" Field="@(x => x.Key)" Title="Key">
|
||||||
<Template>
|
<Template>
|
||||||
@{
|
@{
|
||||||
var apiKeyHalf = Formatter.CutInHalf(context!.Key);
|
var apiKeyHalf = Formatter.CutInHalf(context!.Key);
|
||||||
@@ -35,19 +35,19 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ApiKey" Field="@(x => x.Description)" Title="Description"/>
|
<MCBColumn TItem="ApiKey" Field="@(x => x.Description)" Title="Description"/>
|
||||||
<CrudColumn TItem="ApiKey" Field="@(x => x.CreatedAt)" Title="Created at">
|
<MCBColumn TItem="ApiKey" Field="@(x => x.CreatedAt)" Title="Created at">
|
||||||
<Template>
|
<Template>
|
||||||
@Formatter.FormatDate(context!.CreatedAt)
|
@Formatter.FormatDate(context!.CreatedAt)
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ApiKey" Field="@(x => x.ExpiresAt)" Title="Expires at">
|
<MCBColumn TItem="ApiKey" Field="@(x => x.ExpiresAt)" Title="Expires at">
|
||||||
<Template>
|
<Template>
|
||||||
@Formatter.FormatDate(context!.ExpiresAt)
|
@Formatter.FormatDate(context!.ExpiresAt)
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ApiKey" Field="@(x => x.PermissionJson)" Title="Permissions"/>
|
<MCBColumn TItem="ApiKey" Field="@(x => x.PermissionJson)" Title="Permissions"/>
|
||||||
</View>
|
</View>
|
||||||
</AutoCrud>
|
</AutoCrud>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,12 +59,15 @@
|
|||||||
return repository.Get();
|
return repository.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ValidateAdd(ApiKey apiKey)
|
private void OnConfigure(AutoCrudConfiguration<ApiKey> configuration)
|
||||||
{
|
{
|
||||||
var key = Formatter.GenerateString(32);
|
configuration.ValidateAdd = async apiKey =>
|
||||||
apiKey.Key = key;
|
{
|
||||||
|
var key = Formatter.GenerateString(32);
|
||||||
|
apiKey.Key = key;
|
||||||
|
|
||||||
await ClipboardService.Copy(key);
|
await ClipboardService.Copy(key);
|
||||||
await ToastService.Info("Copied api key into your clipboard");
|
await ToastService.Info("Copied api key into your clipboard");
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
@page "/admin/sys/diagnose"
|
@page "/admin/sys/diagnose"
|
||||||
|
|
||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
|
|
||||||
@inject FileDownloadService DownloadService
|
@inject DownloadService DownloadService
|
||||||
@inject DiagnoseService DiagnoseService
|
@inject DiagnoseService DiagnoseService
|
||||||
|
|
||||||
@attribute [RequirePermission(9999)]
|
@attribute [RequirePermission(9999)]
|
||||||
@@ -31,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<div class="card card-body p-5">
|
<div class="card card-body p-5">
|
||||||
<WButton OnClick="DownloadReport" Text="Download diagnose report" CssClasses="btn btn-primary"/>
|
<WButton OnClick="DownloadReport" CssClasses="btn btn-primary">Download diagnose report</WButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
|
|
||||||
@inject MoonlightService MoonlightService
|
@inject MoonlightService MoonlightService
|
||||||
|
@inject HostSystemHelper HostSystemHelper
|
||||||
|
|
||||||
@attribute [RequirePermission(9999)]
|
@attribute [RequirePermission(9999)]
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@
|
|||||||
<i class="bx bx-lg text-white align-middle bx-refresh"></i>
|
<i class="bx bx-lg text-white align-middle bx-refresh"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-9 d-flex align-items-center">
|
<div class="col-9 d-flex align-items-center">
|
||||||
<ConfirmButton OnClick="MoonlightService.Restart" Text="Restart" CssClasses="btn btn-lg btn-danger w-100"/>
|
<ConfirmButton OnClick="_ => MoonlightService.Restart()" CssClasses="btn btn-lg btn-danger w-100">Restart</ConfirmButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Database.Entities
|
@using Moonlight.Core.Database.Entities
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<div class="card card-body p-5">
|
<div class="card card-body p-5">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<SmartDropdown @bind-Value="SelectedUser"
|
<MCBDropdown @bind-Value="SelectedUser"
|
||||||
Items="Users"
|
Items="Users"
|
||||||
Placeholder="Select a user"
|
Placeholder="Select a user"
|
||||||
DisplayFunc="@(x => x.Username)"
|
DisplayFunc="@(x => x.Username)"
|
||||||
@@ -58,14 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card card-body p-5 d-flex justify-content-center mt-5">
|
<div class="card card-body p-5 d-flex justify-content-center mt-5">
|
||||||
@if (SelectedUser == null)
|
<WButton OnClick="SavePermissions" CssClasses="btn btn-primary">Apply</WButton>
|
||||||
{
|
|
||||||
<button class="btn btn-primary disabled" disabled="">Apply</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<WButton OnClick="SavePermissions" CssClasses="btn btn-primary" Text="Apply"/>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@using System.Reflection
|
@using System.Reflection
|
||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using MoonCoreUI.Helpers
|
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
|
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
@@ -85,6 +83,8 @@ else
|
|||||||
<div class="card card-body">
|
<div class="card card-body">
|
||||||
<div class="row g-5">
|
<div class="row g-5">
|
||||||
<LazyLoader @ref="LazyLoader" Load="Load">
|
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||||
|
<AutoFormGenerator Model="ModelToShow" />
|
||||||
|
@*
|
||||||
@foreach (var prop in Properties)
|
@foreach (var prop in Properties)
|
||||||
{
|
{
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
@@ -96,10 +96,10 @@ else
|
|||||||
parameters.Add("Property", prop);
|
parameters.Add("Property", prop);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@rf
|
@rf
|
||||||
</div>
|
</div>
|
||||||
}
|
}*@
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using Moonlight.Core.Database.Entities
|
@using Moonlight.Core.Database.Entities
|
||||||
@using BlazorTable
|
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Models.Abstractions
|
@using Moonlight.Core.Models.Abstractions
|
||||||
@using Moonlight.Core.Models.Forms.Users
|
@using Moonlight.Core.Models.Forms.Users
|
||||||
|
|
||||||
@@ -23,17 +21,17 @@
|
|||||||
CustomAdd="Add"
|
CustomAdd="Add"
|
||||||
ValidateUpdate="ValidateUpdate">
|
ValidateUpdate="ValidateUpdate">
|
||||||
<View>
|
<View>
|
||||||
<CrudColumn TItem="User" Field="@(x => x.Id)" Title="Id" Filterable="true"/>
|
<MCBColumn TItem="User" Field="@(x => x.Id)" Title="Id" Filterable="true"/>
|
||||||
<CrudColumn TItem="User" Field="@(x => x.Email)" Title="Email" Filterable="true"/>
|
<MCBColumn TItem="User" Field="@(x => x.Email)" Title="Email" Filterable="true"/>
|
||||||
<CrudColumn TItem="User" Field="@(x => x.Username)" Title="Username" Filterable="true"/>
|
<MCBColumn TItem="User" Field="@(x => x.Username)" Title="Username" Filterable="true"/>
|
||||||
<CrudColumn TItem="User" Field="@(x => x.CreatedAt)" Title="Created at"/>
|
<MCBColumn TItem="User" Field="@(x => x.CreatedAt)" Title="Created at"/>
|
||||||
</View>
|
</View>@*
|
||||||
<UpdateActions>
|
<UpdateActions>
|
||||||
<WButton OnClick="() => ChangePassword(context)" CssClasses="btn btn-info me-2">
|
<WButton OnClick="() => ChangePassword(context)" CssClasses="btn btn-info me-2">
|
||||||
<i class="bx bx-sm bxs-key"></i>
|
<i class="bx bx-sm bxs-key"></i>
|
||||||
Change password
|
Change password
|
||||||
</WButton>
|
</WButton>
|
||||||
</UpdateActions>
|
</UpdateActions>*@
|
||||||
</AutoCrud>
|
</AutoCrud>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
@@ -45,13 +43,14 @@
|
|||||||
|
|
||||||
private async Task ChangePassword(User user)
|
private async Task ChangePassword(User user)
|
||||||
{
|
{
|
||||||
var newPassword = await AlertService.Text($"Enter a new password for {user.Username}", "");
|
await AlertService.Text("", "Enter a new password for {user.Username}", async newPassword =>
|
||||||
|
{
|
||||||
|
// This handles empty and canceled input
|
||||||
|
if (string.IsNullOrEmpty(newPassword))
|
||||||
|
return;
|
||||||
|
|
||||||
// This handles empty and canceled input
|
await AuthenticationProvider.ChangePassword(user, newPassword);
|
||||||
if (string.IsNullOrEmpty(newPassword))
|
});
|
||||||
return;
|
|
||||||
|
|
||||||
await AuthenticationProvider.ChangePassword(user, newPassword);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Add(User user)
|
private async Task Add(User user)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
@using Moonlight.Core.UI.Components.Navigations
|
@using Moonlight.Core.UI.Components.Navigations
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Models
|
@using Moonlight.Core.Models
|
||||||
|
|
||||||
@inject SessionService SessionService
|
@inject SessionService SessionService
|
||||||
@@ -24,11 +23,11 @@
|
|||||||
<div class="card mt-5">
|
<div class="card mt-5">
|
||||||
<div class="card-body px-6 py-4">
|
<div class="card-body px-6 py-4">
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<CrudTable @ref="Table"
|
<MCBTable @ref="Table"
|
||||||
TItem="Session"
|
TItem="Session"
|
||||||
ItemSource="SessionService.Sessions"
|
ItemSource="SessionService.Sessions"
|
||||||
PageSize="50">
|
PageSize="50">
|
||||||
<CrudColumn TItem="Session" Title="User" Field="@(x => x.CreatedAt)">
|
<MCBColumn TItem="Session" Title="User" Field="@(x => x.CreatedAt)">
|
||||||
<Template>
|
<Template>
|
||||||
@if (context.IdentityService.IsLoggedIn)
|
@if (context.IdentityService.IsLoggedIn)
|
||||||
{
|
{
|
||||||
@@ -41,25 +40,25 @@
|
|||||||
<span>Guest</span>
|
<span>Guest</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="Session" Title="URL" Field="@(x => x.CreatedAt)">
|
<MCBColumn TItem="Session" Title="URL" Field="@(x => x.CreatedAt)">
|
||||||
<Template>
|
<Template>
|
||||||
<a target="_blank" href="@(context.NavigationManager.Uri)">
|
<a target="_blank" href="@(context.NavigationManager.Uri)">
|
||||||
@(context.NavigationManager.Uri)
|
@(context.NavigationManager.Uri)
|
||||||
</a>
|
</a>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="Session" Title="Last activity" Field="@(x => x.UpdatedAt)" Filterable="true">
|
<MCBColumn TItem="Session" Title="Last activity" Field="@(x => x.UpdatedAt)" Filterable="true">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(Formatter.FormatUptime(DateTime.UtcNow - context.UpdatedAt))</span>
|
<span>@(Formatter.FormatUptime(DateTime.UtcNow - context.UpdatedAt))</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="Session" Title="Connected since" Field="@(x => x.CreatedAt)" Filterable="true">
|
<MCBColumn TItem="Session" Title="Connected since" Field="@(x => x.CreatedAt)" Filterable="true">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(Formatter.FormatUptime(DateTime.UtcNow - context.CreatedAt))</span>
|
<span>@(Formatter.FormatUptime(DateTime.UtcNow - context.CreatedAt))</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="Session" Title="Actions">
|
<MCBColumn TItem="Session" Title="Actions">
|
||||||
<Template>
|
<Template>
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
<div class="btn btn-group">
|
<div class="btn btn-group">
|
||||||
@@ -68,8 +67,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</CrudTable>
|
</MCBTable>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,7 +76,7 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private CrudTable<Session>? Table;
|
private MCBTable<Session>? Table;
|
||||||
private Timer? UpdateTimer;
|
private Timer? UpdateTimer;
|
||||||
|
|
||||||
private Task Load(LazyLoader _)
|
private Task Load(LazyLoader _)
|
||||||
@@ -93,40 +92,42 @@
|
|||||||
|
|
||||||
private async Task Redirect(Session session)
|
private async Task Redirect(Session session)
|
||||||
{
|
{
|
||||||
var url = await AlertService.Text("Enter the target url to redirect to");
|
await AlertService.Text("Redirect to", "Enter the target url to redirect to", async url =>
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(url))
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
session.NavigationManager.NavigateTo(url);
|
if (string.IsNullOrEmpty(url))
|
||||||
|
return;
|
||||||
|
|
||||||
await ToastService.Success("Successfully redirected user session");
|
try
|
||||||
}
|
{
|
||||||
catch (Exception)
|
session.NavigationManager.NavigateTo(url);
|
||||||
{
|
|
||||||
await ToastService.Danger("Unable to redirect user. The user is probably no longer connect with moonlight");
|
await ToastService.Success("Successfully redirected user session");
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
await ToastService.Danger("Unable to redirect user. The user is probably no longer connect with moonlight");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Message(Session session)
|
private async Task Message(Session session)
|
||||||
{
|
{
|
||||||
var message = await AlertService.Text("Enter the message you want to send");
|
await AlertService.Text("Send message", "Enter the message you want to send", async message =>
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(message))
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
await session.AlertService.Info(message);
|
if (string.IsNullOrEmpty(message))
|
||||||
|
return;
|
||||||
|
|
||||||
await ToastService.Success("Successfully sent message to user session");
|
try
|
||||||
}
|
{
|
||||||
catch (Exception)
|
await session.AlertService.Info(message);
|
||||||
{
|
|
||||||
await ToastService.Danger("Unable to send message. The user is probably no longer connect with moonlight");
|
await ToastService.Success("Successfully sent message to user session");
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
await ToastService.Danger("Unable to send message. The user is probably no longer connect with moonlight");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -24,7 +24,13 @@ public class FileManagerFeature : MoonlightFeature
|
|||||||
|
|
||||||
//
|
//
|
||||||
var config = new ConfigService<CoreConfiguration>(PathBuilder.File("storage", "configs", "core.json"));
|
var config = new ConfigService<CoreConfiguration>(PathBuilder.File("storage", "configs", "core.json"));
|
||||||
context.Builder.Services.AddSingleton(new JwtService<FileManagerJwtType>(config.Get().Security.Token));
|
|
||||||
|
context.Builder.Services.AddSingleton(
|
||||||
|
new JwtService<FileManagerJwtType>(
|
||||||
|
config.Get().Security.Token,
|
||||||
|
context.LoggerFactory.CreateLogger<JwtService<FileManagerJwtType>>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
context.AddAsset("FileManager", "js/filemanager.js");
|
context.AddAsset("FileManager", "js/filemanager.js");
|
||||||
context.AddAsset("FileManager", "editor/ace.css");
|
context.AddAsset("FileManager", "editor/ace.css");
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ public class DownloadController : Controller
|
|||||||
{
|
{
|
||||||
private readonly JwtService<FileManagerJwtType> JwtService;
|
private readonly JwtService<FileManagerJwtType> JwtService;
|
||||||
private readonly SharedFileAccessService SharedFileAccessService;
|
private readonly SharedFileAccessService SharedFileAccessService;
|
||||||
|
private readonly ILogger<DownloadController> Logger;
|
||||||
|
|
||||||
public DownloadController(JwtService<FileManagerJwtType> jwtService, SharedFileAccessService sharedFileAccessService)
|
public DownloadController(JwtService<FileManagerJwtType> jwtService, SharedFileAccessService sharedFileAccessService, ILogger<DownloadController> logger)
|
||||||
{
|
{
|
||||||
JwtService = jwtService;
|
JwtService = jwtService;
|
||||||
SharedFileAccessService = sharedFileAccessService;
|
SharedFileAccessService = sharedFileAccessService;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -25,7 +27,7 @@ public class DownloadController : Controller
|
|||||||
{
|
{
|
||||||
if (name.Contains(".."))
|
if (name.Contains(".."))
|
||||||
{
|
{
|
||||||
Logger.Warn($"A user tried to access a file via path transversal. Name: {name}");
|
Logger.LogWarning("A user tried to access a file via path transversal. Name: {name}", name);
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,15 @@ public class UploadController : Controller
|
|||||||
{
|
{
|
||||||
private readonly JwtService<FileManagerJwtType> JwtService;
|
private readonly JwtService<FileManagerJwtType> JwtService;
|
||||||
private readonly SharedFileAccessService SharedFileAccessService;
|
private readonly SharedFileAccessService SharedFileAccessService;
|
||||||
|
private readonly ILogger<UploadController> Logger;
|
||||||
|
|
||||||
public UploadController(
|
public UploadController(
|
||||||
JwtService<FileManagerJwtType> jwtService,
|
JwtService<FileManagerJwtType> jwtService,
|
||||||
SharedFileAccessService sharedFileAccessService)
|
SharedFileAccessService sharedFileAccessService, ILogger<UploadController> logger)
|
||||||
{
|
{
|
||||||
JwtService = jwtService;
|
JwtService = jwtService;
|
||||||
SharedFileAccessService = sharedFileAccessService;
|
SharedFileAccessService = sharedFileAccessService;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following method/api endpoint needs some explanation:
|
// The following method/api endpoint needs some explanation:
|
||||||
@@ -57,7 +59,7 @@ public class UploadController : Controller
|
|||||||
|
|
||||||
if (path.Contains(".."))
|
if (path.Contains(".."))
|
||||||
{
|
{
|
||||||
Logger.Warn("A path transversal attack has been detected while processing upload path", "security");
|
Logger.LogWarning("A path transversal attack has been detected while processing upload path: {path}", path);
|
||||||
return BadRequest("Invalid path. This attempt has been logged ;)");
|
return BadRequest("Invalid path. This attempt has been logged ;)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCoreUI.Services;
|
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
@@ -23,37 +23,39 @@ public class ArchiveContextAction : IFileManagerContextAction
|
|||||||
|
|
||||||
var alertService = provider.GetRequiredService<AlertService>();
|
var alertService = provider.GetRequiredService<AlertService>();
|
||||||
|
|
||||||
var fileName = await alertService.Text("Enter the archive file name", "",
|
await alertService.Text("Create an archive", "Enter the archive file name",
|
||||||
|
async fileName =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
||||||
|
return;
|
||||||
|
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
|
await toastService.CreateProgress("fileManagerArchive", "Archiving... Please be patient");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await archiveAccess.Archive(
|
||||||
|
access.CurrentDirectory + fileName,
|
||||||
|
new[] { access.CurrentDirectory + entry.Name }
|
||||||
|
);
|
||||||
|
|
||||||
|
await toastService.Success("Successfully created archive");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
var logger = provider.GetRequiredService<ILogger<ArchiveContextAction>>();
|
||||||
|
logger.LogWarning("An error occured while archiving item ({name}): {e}", entry.Name, e);
|
||||||
|
|
||||||
|
await toastService.Danger("An unknown error occured while creating archive");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await toastService.DeleteProgress("fileManagerArchive");
|
||||||
|
}
|
||||||
|
|
||||||
|
await fileManager.View.Refresh();
|
||||||
|
},
|
||||||
Formatter.FormatDate(DateTime.UtcNow) + ".tar.gz");
|
Formatter.FormatDate(DateTime.UtcNow) + ".tar.gz");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
|
||||||
return;
|
|
||||||
|
|
||||||
var toastService = provider.GetRequiredService<ToastService>();
|
|
||||||
|
|
||||||
await toastService.CreateProgress("fileManagerArchive", "Archiving... Please be patient");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await archiveAccess.Archive(
|
|
||||||
access.CurrentDirectory + fileName,
|
|
||||||
new[] { access.CurrentDirectory + entry.Name }
|
|
||||||
);
|
|
||||||
|
|
||||||
await toastService.Success("Successfully created archive");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Warn($"An error occured while archiving item ({entry.Name}):");
|
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await toastService.Danger("An unknown error occured while creating archive");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await toastService.RemoveProgress("fileManagerArchive");
|
|
||||||
}
|
|
||||||
|
|
||||||
await fileManager.View.Refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCoreUI.Services;
|
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
@@ -21,35 +21,36 @@ public class ArchiveSelectionAction : IFileManagerSelectionAction
|
|||||||
|
|
||||||
var alertService = provider.GetRequiredService<AlertService>();
|
var alertService = provider.GetRequiredService<AlertService>();
|
||||||
|
|
||||||
var fileName = await alertService.Text("Enter the archive file name", "",
|
await alertService.Text("Create an archive", "Enter the archive file name", async fileName =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
||||||
|
return;
|
||||||
|
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
|
await toastService.CreateProgress("fileManagerArchive", "Archiving... Please be patient");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await archiveAccess.Archive(
|
||||||
|
access.CurrentDirectory + fileName,
|
||||||
|
entries.Select(x => access.CurrentDirectory + x.Name).ToArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
await toastService.Success("Successfully created archive");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
var logger = provider.GetRequiredService<ILogger<ArchiveSelectionAction>>();
|
||||||
|
logger.LogWarning("An error occured while archiving items ({lenght}): {e}", entries.Length, e);
|
||||||
|
|
||||||
|
await toastService.Danger("An unknown error occured while creating archive");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await toastService.DeleteProgress("fileManagerArchive");
|
||||||
|
}
|
||||||
|
},
|
||||||
Formatter.FormatDate(DateTime.UtcNow) + ".tar.gz");
|
Formatter.FormatDate(DateTime.UtcNow) + ".tar.gz");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(fileName) || fileName.Contains("..")) // => canceled
|
|
||||||
return;
|
|
||||||
|
|
||||||
var toastService = provider.GetRequiredService<ToastService>();
|
|
||||||
|
|
||||||
await toastService.CreateProgress("fileManagerArchive", "Archiving... Please be patient");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await archiveAccess.Archive(
|
|
||||||
access.CurrentDirectory + fileName,
|
|
||||||
entries.Select(x => access.CurrentDirectory + x.Name).ToArray()
|
|
||||||
);
|
|
||||||
|
|
||||||
await toastService.Success("Successfully created archive");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Warn($"An error occured while archiving items ({entries.Length}):");
|
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await toastService.Danger("An unknown error occured while creating archive");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await toastService.RemoveProgress("fileManagerArchive");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using MoonCoreUI.Services;
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
@@ -14,21 +14,22 @@ public class CreateFileAction : IFileManagerCreateAction
|
|||||||
{
|
{
|
||||||
var alertService = provider.GetRequiredService<AlertService>();
|
var alertService = provider.GetRequiredService<AlertService>();
|
||||||
|
|
||||||
var name = await alertService.Text("Enter a name for the new file");
|
await alertService.Text("Create a new file","Enter a name for the new file", async name =>
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(name) || name.Contains(".."))
|
|
||||||
return;
|
|
||||||
|
|
||||||
await access.CreateFile(name);
|
|
||||||
|
|
||||||
// We build a virtual entry here so we dont need to fetch one
|
|
||||||
await fileManager.OpenEditor(new()
|
|
||||||
{
|
{
|
||||||
Name = name,
|
if (string.IsNullOrEmpty(name) || name.Contains(".."))
|
||||||
Size = 0,
|
return;
|
||||||
IsFile = true,
|
|
||||||
IsDirectory = false,
|
await access.CreateFile(name);
|
||||||
LastModifiedAt = DateTime.UtcNow
|
|
||||||
|
// We build a virtual entry here so we dont need to fetch one
|
||||||
|
await fileManager.OpenEditor(new()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Size = 0,
|
||||||
|
IsFile = true,
|
||||||
|
IsDirectory = false,
|
||||||
|
LastModifiedAt = DateTime.UtcNow
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using MoonCoreUI.Services;
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
using Moonlight.Features.FileManager.UI.Components;
|
using Moonlight.Features.FileManager.UI.Components;
|
||||||
@@ -16,14 +16,15 @@ public class CreateFolderAction : IFileManagerCreateAction
|
|||||||
var alertService = provider.GetRequiredService<AlertService>();
|
var alertService = provider.GetRequiredService<AlertService>();
|
||||||
var toastService = provider.GetRequiredService<ToastService>();
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
var name = await alertService.Text("Enter a name for the new directory");
|
await alertService.Text("Create a new folder", "Enter a name for the new directory", async name =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name) || name.Contains(".."))
|
||||||
|
return;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(name) || name.Contains(".."))
|
await access.CreateDirectory(name);
|
||||||
return;
|
|
||||||
|
|
||||||
await access.CreateDirectory(name);
|
await toastService.Success("Successfully created directory");
|
||||||
|
await fileManager.View.Refresh();
|
||||||
await toastService.Success("Successfully created directory");
|
});
|
||||||
await fileManager.View.Refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using MoonCoreUI.Services;
|
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
using Moonlight.Features.FileManager.UI.Components;
|
using Moonlight.Features.FileManager.UI.Components;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MoonCoreUI.Services;
|
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
using Moonlight.Features.FileManager.UI.Components;
|
using Moonlight.Features.FileManager.UI.Components;
|
||||||
@@ -42,23 +43,24 @@ public class DeleteSelectionAction : IFileManagerSelectionAction
|
|||||||
|
|
||||||
if (fileCount > showFileCount)
|
if (fileCount > showFileCount)
|
||||||
fileList += "And " + (fileCount - showFileCount) + " more files...";
|
fileList += "And " + (fileCount - showFileCount) + " more files...";
|
||||||
|
|
||||||
|
|
||||||
if(!await alertService.YesNo($"Do you really want to delete {folderCount + fileCount} item(s)? \n\n" + fileList))
|
|
||||||
return;
|
|
||||||
|
|
||||||
await toastService.CreateProgress("fileManagerSelectionDelete", "Deleting items");
|
|
||||||
|
|
||||||
foreach (var entry in entries)
|
await alertService.Confirm("Confirm file deletion",
|
||||||
{
|
$"Do you really want to delete {folderCount + fileCount} item(s)? \n\n" + fileList, async () =>
|
||||||
await toastService.ModifyProgress("fileManagerSelectionDelete", $"Deleting '{entry.Name}'");
|
{
|
||||||
|
await toastService.CreateProgress("fileManagerSelectionDelete", "Deleting items");
|
||||||
|
|
||||||
await access.Delete(entry);
|
foreach (var entry in entries)
|
||||||
}
|
{
|
||||||
|
await toastService.UpdateProgress("fileManagerSelectionDelete", $"Deleting '{entry.Name}'");
|
||||||
|
|
||||||
await toastService.RemoveProgress("fileManagerSelectionDelete");
|
await access.Delete(entry);
|
||||||
|
}
|
||||||
|
|
||||||
await toastService.Success("Successfully deleted selection");
|
await toastService.DeleteProgress("fileManagerSelectionDelete");
|
||||||
await fileManager.View.Refresh();
|
|
||||||
|
await toastService.Success("Successfully deleted selection");
|
||||||
|
await fileManager.View.Refresh();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCoreUI.Services;
|
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
using Moonlight.Features.FileManager.Services;
|
using Moonlight.Features.FileManager.Services;
|
||||||
@@ -15,11 +16,11 @@ public class DownloadContextAction : IFileManagerContextAction
|
|||||||
public string Color => "primary";
|
public string Color => "primary";
|
||||||
public Func<FileEntry, bool> Filter => entry => entry.IsFile;
|
public Func<FileEntry, bool> Filter => entry => entry.IsFile;
|
||||||
|
|
||||||
public async Task Execute(BaseFileAccess access, UI.Components.FileManager fileManager, FileEntry entry, IServiceProvider serviceProvider)
|
public async Task Execute(BaseFileAccess access, UI.Components.FileManager fileManager, FileEntry entry, IServiceProvider provider)
|
||||||
{
|
{
|
||||||
var fileAccessService = serviceProvider.GetRequiredService<SharedFileAccessService>();
|
var fileAccessService = provider.GetRequiredService<SharedFileAccessService>();
|
||||||
var navigation = serviceProvider.GetRequiredService<NavigationManager>();
|
var navigation = provider.GetRequiredService<NavigationManager>();
|
||||||
var toastService = serviceProvider.GetRequiredService<ToastService>();
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -31,8 +32,8 @@ public class DownloadContextAction : IFileManagerContextAction
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn("Unable to start download");
|
var logger = provider.GetRequiredService<ILogger<DownloadContextAction>>();
|
||||||
Logger.Warn(e);
|
logger.LogWarning("Unable to start download: {e}", e); ;
|
||||||
|
|
||||||
await toastService.Danger("Failed to start download");
|
await toastService.Danger("Failed to start download");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCoreUI.Services;
|
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
@@ -36,14 +37,14 @@ public class ExtractContextAction : IFileManagerContextAction
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An error occured while extracting archive ({entry.Name}):");
|
var logger = provider.GetRequiredService<ILogger<ExtractContextAction>>();
|
||||||
Logger.Warn(e);
|
logger.LogWarning("An error occured while extracting archive ({name}): {e}", entry.Name, e);
|
||||||
|
|
||||||
await toastService.Danger("An unknown error occured while extracting archive");
|
await toastService.Danger("An unknown error occured while extracting archive");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await toastService.RemoveProgress("fileManagerExtract");
|
await toastService.DeleteProgress("fileManagerExtract");
|
||||||
}
|
}
|
||||||
|
|
||||||
await fileManager.View.Refresh();
|
await fileManager.View.Refresh();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MoonCoreUI.Services;
|
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MoonCoreUI.Services;
|
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
@@ -19,12 +20,12 @@ public class MoveSelectionAction : IFileManagerSelectionAction
|
|||||||
|
|
||||||
foreach (var entry in entries)
|
foreach (var entry in entries)
|
||||||
{
|
{
|
||||||
await toastService.ModifyProgress("fileManagerSelectionMove", $"Moving '{entry.Name}'");
|
await toastService.UpdateProgress("fileManagerSelectionMove", $"Moving '{entry.Name}'");
|
||||||
|
|
||||||
await access.Move(entry, path + entry.Name);
|
await access.Move(entry, path + entry.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
await toastService.RemoveProgress("fileManagerSelectionMove");
|
await toastService.DeleteProgress("fileManagerSelectionMove");
|
||||||
|
|
||||||
await toastService.Success("Successfully moved selection");
|
await toastService.Success("Successfully moved selection");
|
||||||
await fileManager.View.Refresh();
|
await fileManager.View.Refresh();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using MoonCoreUI.Services;
|
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using Moonlight.Features.FileManager.Interfaces;
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
using Moonlight.Features.FileManager.UI.Components;
|
using Moonlight.Features.FileManager.UI.Components;
|
||||||
@@ -17,14 +18,15 @@ public class RenameContextAction : IFileManagerContextAction
|
|||||||
var alertService = provider.GetRequiredService<AlertService>();
|
var alertService = provider.GetRequiredService<AlertService>();
|
||||||
var toastService = provider.GetRequiredService<ToastService>();
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
var newName = await alertService.Text($"Enter a new name for '{entry.Name}'", "", entry.Name);
|
await alertService.Text("Rename file" , $"Enter a new name for '{entry.Name}'", async newName =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newName))
|
||||||
|
return;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(newName))
|
await access.Rename(entry.Name, newName);
|
||||||
return;
|
|
||||||
|
|
||||||
await access.Rename(entry.Name, newName);
|
await fileManager.View.Refresh();
|
||||||
|
await toastService.Success("Successfully renamed file");
|
||||||
await fileManager.View.Refresh();
|
}, entry.Name);
|
||||||
await toastService.Success("Successfully renamed file");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
|
using MoonCore.Blazor.Extensions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
|
||||||
namespace Moonlight.Features.FileManager.Services;
|
namespace Moonlight.Features.FileManager.Services;
|
||||||
@@ -9,32 +10,30 @@ public class FileManagerInteropService
|
|||||||
{
|
{
|
||||||
private readonly IJSRuntime JsRuntime;
|
private readonly IJSRuntime JsRuntime;
|
||||||
|
|
||||||
public SmartEventHandler OnUploadStateChanged { get; set; } = new();
|
public SmartEventHandler OnUploadStateChanged { get; set; }
|
||||||
|
|
||||||
public FileManagerInteropService(IJSRuntime jsRuntime)
|
public FileManagerInteropService(IJSRuntime jsRuntime, ILogger<SmartEventHandler> eventHandlerLogger)
|
||||||
{
|
{
|
||||||
JsRuntime = jsRuntime;
|
JsRuntime = jsRuntime;
|
||||||
|
|
||||||
|
OnUploadStateChanged = new(eventHandlerLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitDropzone(string id, string urlId)
|
public async Task InitDropzone(string id, string urlId)
|
||||||
{
|
{
|
||||||
var reference = DotNetObjectReference.Create(this);
|
var reference = DotNetObjectReference.Create(this);
|
||||||
await JsRuntime.InvokeVoidAsync("filemanager.dropzone.init", id, urlId, reference);
|
await JsRuntime.InvokeVoidAsyncHandled("filemanager.dropzone.init", id, urlId, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitFileSelect(string id, string urlId)
|
public async Task InitFileSelect(string id, string urlId)
|
||||||
{
|
{
|
||||||
var reference = DotNetObjectReference.Create(this);
|
var reference = DotNetObjectReference.Create(this);
|
||||||
await JsRuntime.InvokeVoidAsync("filemanager.fileselect.init", id, urlId, reference);
|
await JsRuntime.InvokeVoidAsyncHandled("filemanager.fileselect.init", id, urlId, reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateUrl(string urlId, string url)
|
public async Task UpdateUrl(string urlId, string url)
|
||||||
{
|
{
|
||||||
try
|
await JsRuntime.InvokeVoidAsyncHandled("filemanager.updateUrl", urlId, url);
|
||||||
{
|
|
||||||
await JsRuntime.InvokeVoidAsync("filemanager.updateUrl", urlId, url);
|
|
||||||
}
|
|
||||||
catch (TaskCanceledException) { /* ignored */ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Core.Helpers
|
@using Moonlight.Core.Helpers
|
||||||
@@ -7,6 +6,7 @@
|
|||||||
|
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject HotKeyService HotKeyService
|
@inject HotKeyService HotKeyService
|
||||||
|
@inject ILogger<FileEditor> Logger
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
@@ -76,8 +76,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An unhandled error has occured while saving a file using access type {FileAccess.GetType().FullName}");
|
Logger.LogWarning("An unhandled error has occured while saving a file using access type {name}: {e}", FileAccess.GetType().FullName, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await ToastService.Danger("An unknown error has occured while saving the file. Please try again later");
|
await ToastService.Danger("An unknown error has occured while saving the file. Please try again later");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
@using Moonlight.Features.FileManager.Interfaces
|
@using Moonlight.Features.FileManager.Interfaces
|
||||||
@@ -9,6 +8,7 @@
|
|||||||
|
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
@inject ModalService ModalService
|
||||||
@inject FileManagerInteropService FileManagerInteropService
|
@inject FileManagerInteropService FileManagerInteropService
|
||||||
@inject SharedFileAccessService FileAccessService
|
@inject SharedFileAccessService FileAccessService
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
@@ -111,28 +111,6 @@ else
|
|||||||
</ContextMenuTemplate>
|
</ContextMenuTemplate>
|
||||||
</FileView>
|
</FileView>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SmartModal @ref="FolderSelectModal" CssClasses="modal-lg modal-dialog-centered">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">@FolderSelectTitle</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="HideFolderSelect"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<FileView @ref="FolderSelectView"
|
|
||||||
FileAccess="FolderSelectFileAccess"
|
|
||||||
Filter="FolderSelectFilter"
|
|
||||||
ShowDate="false"
|
|
||||||
ShowSelect="false"
|
|
||||||
ShowSize="false"
|
|
||||||
OnEntryClicked="EntryClickFolderSelect"
|
|
||||||
OnNavigateUpClicked="NavigateUpFolderSelect"
|
|
||||||
EnableContextMenu="false"/>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="HideFolderSelect">Cancel</button>
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="SubmitFolderSelect">Submit</button>
|
|
||||||
</div>
|
|
||||||
</SmartModal>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@code
|
@code
|
||||||
@@ -151,15 +129,6 @@ else
|
|||||||
private FileEntry FileToEdit;
|
private FileEntry FileToEdit;
|
||||||
private bool ShowEditor = false;
|
private bool ShowEditor = false;
|
||||||
|
|
||||||
// Folder select dialog
|
|
||||||
private bool FolderSelectIsOpen = false;
|
|
||||||
private SmartModal FolderSelectModal;
|
|
||||||
private BaseFileAccess FolderSelectFileAccess;
|
|
||||||
private string FolderSelectTitle;
|
|
||||||
private Func<string, Task> FolderSelectResult;
|
|
||||||
private FileView FolderSelectView;
|
|
||||||
private Func<FileEntry, bool> FolderSelectFilter => entry => entry.IsDirectory;
|
|
||||||
|
|
||||||
private Timer? UploadTokenTimer;
|
private Timer? UploadTokenTimer;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
@@ -174,8 +143,7 @@ else
|
|||||||
{
|
{
|
||||||
if (!firstRender)
|
if (!firstRender)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
// Setup upload url update timer
|
// Setup upload url update timer
|
||||||
UploadTokenTimer = new(async _ =>
|
UploadTokenTimer = new(async _ =>
|
||||||
{
|
{
|
||||||
@@ -307,53 +275,17 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Selects
|
|
||||||
|
|
||||||
public async Task OpenFolderSelect(string title, Func<string, Task> onResult)
|
public async Task OpenFolderSelect(string title, Func<string, Task> onResult)
|
||||||
{
|
{
|
||||||
if (FolderSelectIsOpen)
|
await ModalService.Launch<FolderSelectModal>(cssClasses: "modal-lg modal-dialog-centered", buildAttributes: parameters =>
|
||||||
await HideFolderSelect();
|
{
|
||||||
|
parameters.Add("Title", title);
|
||||||
FolderSelectResult = onResult;
|
parameters.Add("OnResult", onResult);
|
||||||
FolderSelectTitle = title;
|
parameters.Add("FileAccess", FileAccess.Clone());
|
||||||
|
});
|
||||||
FolderSelectFileAccess = FileAccess.Clone();
|
|
||||||
await FolderSelectFileAccess.SetDirectory("/");
|
|
||||||
|
|
||||||
await FolderSelectModal.Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HideFolderSelect()
|
|
||||||
{
|
|
||||||
await FolderSelectModal.Hide();
|
|
||||||
FolderSelectIsOpen = false;
|
|
||||||
FolderSelectFileAccess.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SubmitFolderSelect()
|
|
||||||
{
|
|
||||||
var path = await FolderSelectFileAccess.GetCurrentDirectory();
|
|
||||||
|
|
||||||
await HideFolderSelect();
|
|
||||||
|
|
||||||
await FolderSelectResult.Invoke(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task NavigateUpFolderSelect()
|
|
||||||
{
|
|
||||||
await FolderSelectFileAccess.ChangeDirectory("..");
|
|
||||||
await FolderSelectView.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task EntryClickFolderSelect(FileEntry entry)
|
|
||||||
{
|
|
||||||
await FolderSelectFileAccess.ChangeDirectory(entry.Name);
|
|
||||||
await FolderSelectView.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public async void Dispose()
|
public async void Dispose()
|
||||||
{
|
{
|
||||||
if (UploadTokenTimer != null)
|
if (UploadTokenTimer != null)
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
@using Moonlight.Features.FileManager.Models.Abstractions.FileAccess
|
||||||
|
|
||||||
|
@implements IDisposable
|
||||||
|
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">@Title</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<FileView @ref="View"
|
||||||
|
FileAccess="FileAccess"
|
||||||
|
Filter="Filter"
|
||||||
|
ShowDate="false"
|
||||||
|
ShowSelect="false"
|
||||||
|
ShowSize="false"
|
||||||
|
OnEntryClicked="EntryClickFolderSelect"
|
||||||
|
OnNavigateUpClicked="NavigateUpFolderSelect"
|
||||||
|
EnableContextMenu="false"/>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="SubmitFolderSelect">Submit</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter] public BaseFileAccess FileAccess { get; set; }
|
||||||
|
[Parameter] public string Title { get; set; }
|
||||||
|
[Parameter] public Func<string, Task> OnResult { get; set; }
|
||||||
|
|
||||||
|
private FileView View;
|
||||||
|
private Func<FileEntry, bool> Filter => entry => entry.IsDirectory;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await FileAccess.SetDirectory("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SubmitFolderSelect()
|
||||||
|
{
|
||||||
|
var path = await FileAccess.GetCurrentDirectory();
|
||||||
|
await OnResult.Invoke(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task NavigateUpFolderSelect()
|
||||||
|
{
|
||||||
|
await FileAccess.ChangeDirectory("..");
|
||||||
|
await View.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task EntryClickFolderSelect(FileEntry entry)
|
||||||
|
{
|
||||||
|
await FileAccess.ChangeDirectory(entry.Name);
|
||||||
|
await View.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
FileAccess.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
using MoonCore.Helpers;
|
using MoonCore.Attributes;
|
||||||
|
using MoonCore.Helpers;
|
||||||
using Moonlight.Features.Servers.Entities;
|
using Moonlight.Features.Servers.Entities;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Events;
|
namespace Moonlight.Features.Servers.Events;
|
||||||
|
|
||||||
|
[Singleton]
|
||||||
public class ServerEvents
|
public class ServerEvents
|
||||||
{
|
{
|
||||||
public static SmartEventHandler<(Server, ServerBackup)> OnBackupCompleted { get; set; } = new();
|
public SmartEventHandler<(Server, ServerBackup)> OnBackupCompleted { get; set; }
|
||||||
|
|
||||||
|
public ServerEvents(ILogger<SmartEventHandler> eventHandlerLogger)
|
||||||
|
{
|
||||||
|
OnBackupCompleted = new(eventHandlerLogger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,8 +16,13 @@ public static class NodeExtensions
|
|||||||
return new HttpApiClient<NodeException>(remoteUrl, node.Token);
|
return new HttpApiClient<NodeException>(remoteUrl, node.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JwtService<ServersJwtType> CreateJwtService(this ServerNode node)
|
public static JwtService<ServersJwtType> CreateJwtService(this ServerNode node, ILoggerFactory factory)
|
||||||
{
|
{
|
||||||
return new JwtService<ServersJwtType>(node.Token);
|
return node.CreateJwtService(factory.CreateLogger<JwtService<ServersJwtType>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JwtService<ServersJwtType> CreateJwtService(this ServerNode node, ILogger<JwtService<ServersJwtType>> logger)
|
||||||
|
{
|
||||||
|
return new JwtService<ServersJwtType>(node.Token, logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,10 +8,10 @@ namespace Moonlight.Features.Servers.Helpers;
|
|||||||
|
|
||||||
public class ServerConsole : IDisposable
|
public class ServerConsole : IDisposable
|
||||||
{
|
{
|
||||||
public SmartEventHandler<ServerState> OnStateChange { get; set; } = new();
|
public SmartEventHandler<ServerState> OnStateChange { get; set; }
|
||||||
public SmartEventHandler<ServerStats> OnStatsChange { get; set; } = new();
|
public SmartEventHandler<ServerStats> OnStatsChange { get; set; }
|
||||||
public SmartEventHandler<string> OnNewMessage { get; set; } = new();
|
public SmartEventHandler<string> OnNewMessage { get; set; }
|
||||||
public SmartEventHandler OnDisconnected { get; set; } = new();
|
public SmartEventHandler OnDisconnected { get; set; }
|
||||||
|
|
||||||
public ServerState State { get; private set; } = ServerState.Offline;
|
public ServerState State { get; private set; } = ServerState.Offline;
|
||||||
public ServerStats Stats { get; private set; } = new();
|
public ServerStats Stats { get; private set; } = new();
|
||||||
@@ -20,18 +20,29 @@ public class ServerConsole : IDisposable
|
|||||||
|
|
||||||
private readonly List<string> MessageCache = new();
|
private readonly List<string> MessageCache = new();
|
||||||
private readonly Server Server;
|
private readonly Server Server;
|
||||||
|
private readonly ILogger<ServerConsole> Logger;
|
||||||
|
private readonly ILogger<AdvancedWebsocketStream> AwsLogger;
|
||||||
|
|
||||||
private ClientWebSocket WebSocket;
|
private ClientWebSocket WebSocket;
|
||||||
private AdvancedWebsocketStream WebsocketStream;
|
private AdvancedWebsocketStream WebsocketStream;
|
||||||
|
|
||||||
private CancellationTokenSource Cancellation = new();
|
private CancellationTokenSource Cancellation = new();
|
||||||
|
|
||||||
public ServerConsole(Server server)
|
public ServerConsole(Server server, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
if (server.Node == null)
|
if (server.Node == null)
|
||||||
throw new ArgumentNullException(nameof(server.Node));
|
throw new ArgumentNullException(nameof(server.Node));
|
||||||
|
|
||||||
Server = server;
|
Server = server;
|
||||||
|
|
||||||
|
Logger = loggerFactory.CreateLogger<ServerConsole>();
|
||||||
|
AwsLogger = loggerFactory.CreateLogger<AdvancedWebsocketStream>();
|
||||||
|
|
||||||
|
var eventHandlerLogger = loggerFactory.CreateLogger<SmartEventHandler>();
|
||||||
|
OnStateChange = new(eventHandlerLogger);
|
||||||
|
OnStatsChange = new(eventHandlerLogger);
|
||||||
|
OnDisconnected = new(eventHandlerLogger);
|
||||||
|
OnNewMessage = new(eventHandlerLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Connect()
|
public async Task Connect()
|
||||||
@@ -49,7 +60,7 @@ public class ServerConsole : IDisposable
|
|||||||
wsUrl = $"ws://{Server.Node.Fqdn}:{Server.Node.HttpPort}/servers/{Server.Id}/ws";
|
wsUrl = $"ws://{Server.Node.Fqdn}:{Server.Node.HttpPort}/servers/{Server.Id}/ws";
|
||||||
|
|
||||||
await WebSocket.ConnectAsync(new Uri(wsUrl), CancellationToken.None);
|
await WebSocket.ConnectAsync(new Uri(wsUrl), CancellationToken.None);
|
||||||
WebsocketStream = new AdvancedWebsocketStream(WebSocket);
|
WebsocketStream = new AdvancedWebsocketStream(AwsLogger, WebSocket);
|
||||||
|
|
||||||
WebsocketStream.RegisterPacket<string>(1);
|
WebsocketStream.RegisterPacket<string>(1);
|
||||||
WebsocketStream.RegisterPacket<ServerState>(2);
|
WebsocketStream.RegisterPacket<ServerState>(2);
|
||||||
@@ -103,11 +114,10 @@ public class ServerConsole : IDisposable
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (e is WebSocketException)
|
if (e is WebSocketException)
|
||||||
Logger.Warn($"Lost connection to daemon server websocket: {e.Message}");
|
Logger.LogWarning("Lost connection to daemon server websocket: {message}", e.Message);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warn("Server console ws disconnected because of application error:");
|
Logger.LogWarning("Server console ws disconnected because of application error: {e}", e);
|
||||||
Logger.Warn(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -18,11 +18,17 @@ public class ServersController : Controller
|
|||||||
{
|
{
|
||||||
private readonly Repository<Server> ServerRepository;
|
private readonly Repository<Server> ServerRepository;
|
||||||
private readonly Repository<ServerBackup> BackupRepository;
|
private readonly Repository<ServerBackup> BackupRepository;
|
||||||
|
private readonly ILogger<ServersController> Logger;
|
||||||
|
private readonly ILogger<AdvancedWebsocketStream> WebSocketLogger;
|
||||||
|
private readonly ServerEvents ServerEvents;
|
||||||
|
|
||||||
public ServersController(Repository<Server> serverRepository, Repository<ServerBackup> backupRepository)
|
public ServersController(Repository<Server> serverRepository, Repository<ServerBackup> backupRepository, ILogger<ServersController> logger, ILogger<AdvancedWebsocketStream> webSocketLogger, ServerEvents serverEvents)
|
||||||
{
|
{
|
||||||
ServerRepository = serverRepository;
|
ServerRepository = serverRepository;
|
||||||
BackupRepository = backupRepository;
|
BackupRepository = backupRepository;
|
||||||
|
Logger = logger;
|
||||||
|
WebSocketLogger = webSocketLogger;
|
||||||
|
ServerEvents = serverEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("ws")]
|
[HttpGet("ws")]
|
||||||
@@ -36,7 +42,7 @@ public class ServersController : Controller
|
|||||||
var websocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
var websocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||||
|
|
||||||
// Build connection wrapper
|
// Build connection wrapper
|
||||||
var websocketStream = new AdvancedWebsocketStream(websocket);
|
var websocketStream = new AdvancedWebsocketStream(WebSocketLogger, websocket);
|
||||||
websocketStream.RegisterPacket<int>(1);
|
websocketStream.RegisterPacket<int>(1);
|
||||||
websocketStream.RegisterPacket<ServerConfiguration>(2);
|
websocketStream.RegisterPacket<ServerConfiguration>(2);
|
||||||
|
|
||||||
@@ -66,8 +72,7 @@ public class ServersController : Controller
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error($"An error occured while sending server {server.Id} (Image: {server.Image.Name}) to daemon. This may indicate a corrupt or broken image/server. Skipping this server");
|
Logger.LogError("An error occured while sending server {serverId} (Image: {name}) to daemon. This may indicate a corrupt or broken image/server. Skipping this server. Error: {e}", server.Id, server.Image.Name, e);
|
||||||
Logger.Error(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +151,7 @@ public class ServersController : Controller
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
if(!status.Successful)
|
if(!status.Successful)
|
||||||
Logger.Warn($"A node reported an error for a backup for the server {server.Id}");
|
Logger.LogWarning("A node reported an error for a backup for the server {serverId}", server.Id);
|
||||||
|
|
||||||
backup.Successful = status.Successful;
|
backup.Successful = status.Successful;
|
||||||
backup.Completed = true;
|
backup.Completed = true;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using MoonCoreUI.Helpers;
|
using MoonCore.Blazor.Helpers;
|
||||||
using Moonlight.Core.Interfaces.Ui.Admin;
|
using Moonlight.Core.Interfaces.Ui.Admin;
|
||||||
using Moonlight.Core.Models.Abstractions;
|
using Moonlight.Core.Models.Abstractions;
|
||||||
using Moonlight.Features.Servers.UI.Components.Cards;
|
using Moonlight.Features.Servers.UI.Components.Cards;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Implementations.UI.Admin.AdminColumns;
|
namespace Moonlight.Features.Servers.Implementations.AdminDashboard.Columns;
|
||||||
|
|
||||||
public class ServerCount : IAdminDashboardColumn
|
public class ServerCount : IAdminDashboardColumn
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using MoonCoreUI.Helpers;
|
using MoonCore.Blazor.Helpers;
|
||||||
using Moonlight.Core.Interfaces.Ui.Admin;
|
using Moonlight.Core.Interfaces.Ui.Admin;
|
||||||
using Moonlight.Core.Models.Abstractions;
|
using Moonlight.Core.Models.Abstractions;
|
||||||
using Moonlight.Features.Servers.UI.Components.Cards;
|
using Moonlight.Features.Servers.UI.Components.Cards;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Implementations.UI.Admin.AdminComponents;
|
namespace Moonlight.Features.Servers.Implementations.AdminDashboard.Components;
|
||||||
|
|
||||||
public class NodeOverview : IAdminDashboardComponent
|
public class NodeOverview : IAdminDashboardComponent
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using MoonCoreUI.Helpers;
|
using MoonCore.Blazor.Helpers;
|
||||||
using Moonlight.Core.Interfaces.UI.User;
|
using Moonlight.Core.Interfaces.UI.User;
|
||||||
using Moonlight.Core.Models.Abstractions;
|
using Moonlight.Core.Models.Abstractions;
|
||||||
using Moonlight.Features.Servers.UI.Components.Cards;
|
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Implementations.UI.UserDashboard.Components;
|
namespace Moonlight.Features.Servers.Implementations.UserDashboard.Components;
|
||||||
|
|
||||||
public class UserDashboardServerCount : IUserDashboardComponent
|
public class UserDashboardServerCount : IUserDashboardComponent
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using MoonCoreUI.Attributes;
|
using MoonCore.Blazor.Attributes.Auto;
|
||||||
using Moonlight.Core.Database.Entities;
|
using Moonlight.Core.Database.Entities;
|
||||||
using Moonlight.Features.Servers.Entities;
|
using Moonlight.Features.Servers.Entities;
|
||||||
|
|
||||||
@@ -12,11 +12,11 @@ public class CreateServerForm
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Required(ErrorMessage = "You need to specify a server owner")]
|
[Required(ErrorMessage = "You need to specify a server owner")]
|
||||||
[Selector(SelectorProp = "Username", DisplayProp = "Username", UseDropdown = true)]
|
//[Selector(SelectorProp = "Username", DisplayProp = "Username", UseDropdown = true)]
|
||||||
public User Owner { get; set; }
|
public User Owner { get; set; }
|
||||||
|
|
||||||
[Required(ErrorMessage = "You need to specify a server image")]
|
[Required(ErrorMessage = "You need to specify a server image")]
|
||||||
[Selector(SelectorProp = "Name", DisplayProp = "Name", UseDropdown = true)]
|
//[Selector(SelectorProp = "Name", DisplayProp = "Name", UseDropdown = true)]
|
||||||
public ServerImage Image { get; set; }
|
public ServerImage Image { get; set; }
|
||||||
|
|
||||||
[Range(1, int.MaxValue, ErrorMessage = "Enter a valid cpu value")]
|
[Range(1, int.MaxValue, ErrorMessage = "Enter a valid cpu value")]
|
||||||
@@ -26,31 +26,31 @@ public class CreateServerForm
|
|||||||
|
|
||||||
[Range(1, int.MaxValue, ErrorMessage = "Enter a valid memory value")]
|
[Range(1, int.MaxValue, ErrorMessage = "Enter a valid memory value")]
|
||||||
[Description("The amount of memory this server will be able to use")]
|
[Description("The amount of memory this server will be able to use")]
|
||||||
[ByteSize(MinimumUnit = 1, Converter = 1, DefaultUnit = 2)]
|
//[ByteSize(MinimumUnit = 1, Converter = 1, DefaultUnit = 2)]
|
||||||
[Section("Resources", Icon = "bxs-chip")]
|
[Section("Resources", Icon = "bxs-chip")]
|
||||||
public int Memory { get; set; }
|
public int Memory { get; set; }
|
||||||
|
|
||||||
[Range(1, int.MaxValue, ErrorMessage = "Enter a valid disk value")]
|
[Range(1, int.MaxValue, ErrorMessage = "Enter a valid disk value")]
|
||||||
[Description("The amount of disk space this server will be able to use")]
|
[Description("The amount of disk space this server will be able to use")]
|
||||||
[ByteSize(MinimumUnit = 1, Converter = 1, DefaultUnit = 2)]
|
//[ByteSize(MinimumUnit = 1, Converter = 1, DefaultUnit = 2)]
|
||||||
[Section("Resources", Icon = "bxs-chip")]
|
[Section("Resources", Icon = "bxs-chip")]
|
||||||
public int Disk { get; set; }
|
public int Disk { get; set; }
|
||||||
|
|
||||||
[Description("Whether to use a virtual disk for storing server files. Dont use this if you want to overallocate as the virtual disks will fill out the space you allocate")]
|
[Description("Whether to use a virtual disk for storing server files. Dont use this if you want to overallocate as the virtual disks will fill out the space you allocate")]
|
||||||
[Section("Deployment", Icon = "bx-cube")]
|
[Section("Deployment", Icon = "bx-cube")]
|
||||||
[RadioButtonBool("Virtual Disk", "Simple Volume", TrueIcon = "bxs-hdd", FalseIcon = "bxs-data")]
|
//[RadioButtonBool("Virtual Disk", "Simple Volume", TrueIcon = "bxs-hdd", FalseIcon = "bxs-data")]
|
||||||
[DisplayName("Storage")]
|
[DisplayName("Storage")]
|
||||||
public bool UseVirtualDisk { get; set; }
|
public bool UseVirtualDisk { get; set; }
|
||||||
|
|
||||||
[Required(ErrorMessage = "You need to specify a server node")]
|
[Required(ErrorMessage = "You need to specify a server node")]
|
||||||
[Selector(SelectorProp = "Name", DisplayProp = "Name", UseDropdown = true)]
|
//[Selector(SelectorProp = "Name", DisplayProp = "Name", UseDropdown = true)]
|
||||||
[Section("Deployment", Icon = "bx-cube")]
|
[Section("Deployment", Icon = "bx-cube")]
|
||||||
public ServerNode Node { get; set; }
|
public ServerNode Node { get; set; }
|
||||||
|
|
||||||
[Description("The allocations the server should have")]
|
[Description("The allocations the server should have")]
|
||||||
[MultiSelection("Port", "Port", Icon = "bx-network-chart")]
|
//TODO: [MultiSelection("Port", "Port", Icon = "bx-network-chart")]
|
||||||
[Section("Deployment", Icon = "bx-cube")]
|
[Section("Deployment", Icon = "bx-cube")]
|
||||||
[CustomItemLoader("FreeAllocations")]
|
//[CustomItemLoader("FreeAllocations")]
|
||||||
[CustomDisplayFunction("AllocationWithIp")]
|
//[CustomDisplayFunction("AllocationWithIp")]
|
||||||
public List<ServerAllocation> Allocations { get; set; } = new();
|
public List<ServerAllocation> Allocations { get; set; } = new();
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using MoonCoreUI.Attributes;
|
|
||||||
using Moonlight.Features.Servers.Entities;
|
using Moonlight.Features.Servers.Entities;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers.Models.Forms.Users.Networks;
|
namespace Moonlight.Features.Servers.Models.Forms.Users.Networks;
|
||||||
@@ -10,6 +9,6 @@ public class CreateNetworkForm
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[Required(ErrorMessage = "You need to specify a node to create the network on")]
|
[Required(ErrorMessage = "You need to specify a node to create the network on")]
|
||||||
[Selector(SelectorProp = "Name", DisplayProp = "Name")]
|
//[Selector(SelectorProp = "Name", DisplayProp = "Name")]
|
||||||
public ServerNode Node { get; set; }
|
public ServerNode Node { get; set; }
|
||||||
}
|
}
|
||||||
@@ -9,13 +9,13 @@ using Moonlight.Core.Services;
|
|||||||
using Moonlight.Features.Servers.Actions;
|
using Moonlight.Features.Servers.Actions;
|
||||||
using Moonlight.Features.Servers.Configuration;
|
using Moonlight.Features.Servers.Configuration;
|
||||||
using Moonlight.Features.Servers.Http.Middleware;
|
using Moonlight.Features.Servers.Http.Middleware;
|
||||||
|
using Moonlight.Features.Servers.Implementations.AdminDashboard.Columns;
|
||||||
|
using Moonlight.Features.Servers.Implementations.AdminDashboard.Components;
|
||||||
using Moonlight.Features.Servers.Implementations.Diagnose;
|
using Moonlight.Features.Servers.Implementations.Diagnose;
|
||||||
using Moonlight.Features.Servers.Implementations.UI.Admin.AdminColumns;
|
|
||||||
using Moonlight.Features.Servers.Implementations.UI.Admin.AdminComponents;
|
|
||||||
using Moonlight.Features.Servers.Models.Enums;
|
using Moonlight.Features.Servers.Models.Enums;
|
||||||
using Moonlight.Features.Servers.Services;
|
using Moonlight.Features.Servers.Services;
|
||||||
using Moonlight.Features.Servers.UI.Components.Cards;
|
using Moonlight.Features.Servers.UI.Components.Cards;
|
||||||
using UserDashboardServerCount = Moonlight.Features.Servers.Implementations.UI.UserDashboard.Components.UserDashboardServerCount;
|
using UserDashboardServerCount = Moonlight.Features.Servers.Implementations.UserDashboard.Components.UserDashboardServerCount;
|
||||||
|
|
||||||
namespace Moonlight.Features.Servers;
|
namespace Moonlight.Features.Servers;
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ public class ServersFeature : MoonlightFeature
|
|||||||
|
|
||||||
//
|
//
|
||||||
var config = new ConfigService<CoreConfiguration>(PathBuilder.File("storage", "configs", "core.json"));
|
var config = new ConfigService<CoreConfiguration>(PathBuilder.File("storage", "configs", "core.json"));
|
||||||
context.Builder.Services.AddSingleton(new JwtService<ServersJwtType>(config.Get().Security.Token));
|
context.Builder.Services.AddSingleton(new JwtService<ServersJwtType>(config.Get().Security.Token, context.LoggerFactory.CreateLogger<JwtService<ServersJwtType>>()));
|
||||||
|
|
||||||
//
|
//
|
||||||
var configService = new ConfigService<ServersConfiguration>(PathBuilder.File("storage", "configs", "servers.json"));
|
var configService = new ConfigService<ServersConfiguration>(PathBuilder.File("storage", "configs", "servers.json"));
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ namespace Moonlight.Features.Servers.Services;
|
|||||||
public class NodeService
|
public class NodeService
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider ServiceProvider;
|
private readonly IServiceProvider ServiceProvider;
|
||||||
|
private readonly ILogger<NodeService> Logger;
|
||||||
|
|
||||||
public NodeService(IServiceProvider serviceProvider)
|
public NodeService(IServiceProvider serviceProvider, ILogger<NodeService> logger)
|
||||||
{
|
{
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Boot(ServerNode node)
|
public async Task Boot(ServerNode node)
|
||||||
@@ -42,8 +44,7 @@ public class NodeService
|
|||||||
{
|
{
|
||||||
//TODO: Add http exception check to reduce error logs
|
//TODO: Add http exception check to reduce error logs
|
||||||
|
|
||||||
Logger.Warn($"An error occured while booting node '{node.Name}'");
|
Logger.LogWarning("An error occured while booting node '{name}': {e}", node.Name, e);
|
||||||
Logger.Warn(e);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ public class ServerBackupService
|
|||||||
var remoteUrl = $"{protocol}://{node.Fqdn}:{node.HttpPort}/";
|
var remoteUrl = $"{protocol}://{node.Fqdn}:{node.HttpPort}/";
|
||||||
|
|
||||||
// Build jwt
|
// Build jwt
|
||||||
var jwtService = node.CreateJwtService();
|
var loggerFactory = ServiceProvider.GetRequiredService<ILoggerFactory>();
|
||||||
|
var jwtService = node.CreateJwtService(loggerFactory);
|
||||||
|
|
||||||
var jwt = await jwtService.Create(data =>
|
var jwt = await jwtService.Create(data =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ public class ServerScheduleService
|
|||||||
{
|
{
|
||||||
private readonly IServiceProvider ServiceProvider;
|
private readonly IServiceProvider ServiceProvider;
|
||||||
public readonly Dictionary<string, ScheduleAction> Actions = new();
|
public readonly Dictionary<string, ScheduleAction> Actions = new();
|
||||||
|
private readonly ILogger<ServerScheduleService> Logger;
|
||||||
|
|
||||||
public ServerScheduleService(IServiceProvider serviceProvider)
|
public ServerScheduleService(IServiceProvider serviceProvider, ILogger<ServerScheduleService> logger)
|
||||||
{
|
{
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task RegisterAction<T>(string id) where T : ScheduleAction
|
public Task RegisterAction<T>(string id) where T : ScheduleAction
|
||||||
@@ -50,7 +52,7 @@ public class ServerScheduleService
|
|||||||
{
|
{
|
||||||
if (!Actions.ContainsKey(scheduleItem.Action))
|
if (!Actions.ContainsKey(scheduleItem.Action))
|
||||||
{
|
{
|
||||||
Logger.Warn($"The server {server.Id} has a invalid action type '{scheduleItem.Action}'");
|
Logger.LogWarning("The server {serverId} has a invalid action type '{action}'", server.Id, scheduleItem.Action);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,8 +71,7 @@ public class ServerScheduleService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An unhandled error occured while running schedule {schedule.Name} for server {server.Id}");
|
Logger.LogWarning("An unhandled error occured while running schedule {name} for server {serverId}: {e}", schedule.Name, server.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,12 @@ public class ServerService
|
|||||||
public NodeService NodeService => ServiceProvider.GetRequiredService<NodeService>();
|
public NodeService NodeService => ServiceProvider.GetRequiredService<NodeService>();
|
||||||
|
|
||||||
private readonly IServiceProvider ServiceProvider;
|
private readonly IServiceProvider ServiceProvider;
|
||||||
|
private readonly ILogger<ServerService> Logger;
|
||||||
|
|
||||||
public ServerService(IServiceProvider serviceProvider)
|
public ServerService(IServiceProvider serviceProvider, ILogger<ServerService> logger)
|
||||||
{
|
{
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Sync(Server server)
|
public async Task Sync(Server server)
|
||||||
@@ -84,8 +86,7 @@ public class ServerService
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Could not establish to the node with the id {node.Id}");
|
Logger.LogWarning("Could not establish to the node with the id {nodeId}: {e}", node.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
throw new DisplayException($"Could not establish connection to the node: {e.Message}");
|
throw new DisplayException($"Could not establish connection to the node: {e.Message}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@using XtermBlazor
|
@using XtermBlazor
|
||||||
|
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject ClipboardService ClipboardService
|
@inject ClipboardService ClipboardService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject Repository<ServerVariable> ServerVariableRepository
|
@inject Repository<ServerVariable> ServerVariableRepository
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
|
||||||
@inject Repository<ServerVariable> ServerVariableRepository
|
@inject Repository<ServerVariable> ServerVariableRepository
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject Repository<ServerVariable> ServerVariableRepository
|
@inject Repository<ServerVariable> ServerVariableRepository
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
|
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
|
||||||
|
|
||||||
<div class="mt-5 card card-body p-8">
|
<div class="mt-5 card card-body p-8">
|
||||||
<div class="row g-5">
|
<div class="row g-5">@*
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
|
<input class="form-control"/>
|
||||||
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
||||||
Model="Form"
|
Model="Form"
|
||||||
Field="@(x => x.Name)"/>
|
Field="@(x => x.Name)"/>
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
||||||
Model="Form"
|
Model="Form"
|
||||||
Field="@(x => x.UpdateUrl)"/>
|
Field="@(x => x.UpdateUrl)"/>
|
||||||
</div>
|
</div>*@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="row g-8">
|
<div class="row g-8">
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<label class="form-label">Default docker image</label>
|
<label class="form-label">Default docker image</label>
|
||||||
<SmartSelect TField="ServerDockerImage"
|
<MCBSelect TField="ServerDockerImage"
|
||||||
@bind-Value="SelectedDockerImage"
|
@bind-Value="SelectedDockerImage"
|
||||||
Items="Image.DockerImages"
|
Items="Image.DockerImages"
|
||||||
DisplayField="@(x => x.Name)"
|
DisplayField="@(x => x.Name)"
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@*
|
||||||
<AutoListCrud TItem="ServerDockerImage"
|
<AutoListCrud TItem="ServerDockerImage"
|
||||||
TRootItem="ServerImage"
|
TRootItem="ServerImage"
|
||||||
TCreateForm="CreateDockerImage"
|
TCreateForm="CreateDockerImage"
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
</IconAlert>
|
</IconAlert>
|
||||||
</NoItemsView>
|
</NoItemsView>
|
||||||
</AutoListCrud>
|
</AutoListCrud>
|
||||||
|
*@
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
[Parameter] public ServerImage Image { get; set; }
|
[Parameter] public ServerImage Image { get; set; }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using Moonlight.Features.FileManager.UI.Components
|
@using Moonlight.Features.FileManager.UI.Components
|
||||||
|
|
||||||
<div class="mt-5 card card-body p-8">
|
<div class="mt-5 card card-body p-8">
|
||||||
<div class="row g-5">
|
<div class="row g-5">@*
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
||||||
Model="Form"
|
Model="Form"
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
||||||
Model="Form"
|
Model="Form"
|
||||||
Field="@(x => x.AllocationsNeeded)"/>
|
Field="@(x => x.AllocationsNeeded)"/>
|
||||||
</div>
|
</div>*@
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<Editor InitialContent="@Form.InstallScript"
|
<Editor InitialContent="@Form.InstallScript"
|
||||||
Mode="sh"
|
Mode="sh"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
|
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
|
||||||
|
|
||||||
<div class="mt-5 card card-body p-8">
|
<div class="mt-5 card card-body p-8">
|
||||||
<div class="row g-5">
|
<div class="row g-5">@*
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
||||||
Model="Form"
|
Model="Form"
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
<SingleAutoProperty TItem="UpdateImageDetailedForm"
|
||||||
Model="Form"
|
Model="Form"
|
||||||
Field="@(x => x.OnlineDetection)"/>
|
Field="@(x => x.OnlineDetection)"/>
|
||||||
</div>
|
</div>*@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Images.Variables
|
@using Moonlight.Features.Servers.Models.Forms.Admin.Images.Variables
|
||||||
@using BlazorTable
|
@using BlazorTable
|
||||||
|
@*
|
||||||
<AutoListCrud TItem="ServerImageVariable"
|
<AutoListCrud TItem="ServerImageVariable"
|
||||||
TRootItem="ServerImage"
|
TRootItem="ServerImage"
|
||||||
TCreateForm="CreateImageVariable"
|
TCreateForm="CreateImageVariable"
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
</IconAlert>
|
</IconAlert>
|
||||||
</NoItemsView>
|
</NoItemsView>
|
||||||
</AutoListCrud>
|
</AutoListCrud>
|
||||||
|
*@
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
[Parameter] public ServerImage Image { get; set; }
|
[Parameter] public ServerImage Image { get; set; }
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
@using Moonlight.Features.Servers.UI.Components
|
@using Moonlight.Features.Servers.UI.Components
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using Moonlight.Features.Servers.Helpers
|
@using Moonlight.Features.Servers.Helpers
|
||||||
@using Moonlight.Features.Servers.UI.UserViews
|
@using Moonlight.Features.Servers.UI.UserViews
|
||||||
@@ -13,7 +12,8 @@
|
|||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using Moonlight.Features.Servers.Configuration
|
@using Moonlight.Features.Servers.Configuration
|
||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using Moonlight.Core.Services
|
@using IdentityService = Moonlight.Core.Services.IdentityService
|
||||||
|
@using MoonCore.Blazor.Forms.Router
|
||||||
|
|
||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@inject ServerService ServerService
|
@inject ServerService ServerService
|
||||||
@@ -21,10 +21,12 @@
|
|||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject ConfigService<ServersConfiguration> ConfigService
|
@inject ConfigService<ServersConfiguration> ConfigService
|
||||||
|
@inject ILogger<UserLayout> Logger
|
||||||
|
@inject ILoggerFactory LoggerFactory
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
<LazyLoader Load="Load" ShowAsCard="true">
|
<LazyLoader Load="Load">
|
||||||
<div class="card card-body pb-5 pt-5">
|
<div class="card card-body pb-5 pt-5">
|
||||||
<div>
|
<div>
|
||||||
<div class="row px-2">
|
<div class="row px-2">
|
||||||
@@ -43,21 +45,21 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="text-gray-900 fs-4">
|
<div class="text-gray-900 fs-4">
|
||||||
@{
|
@{
|
||||||
var color = ServerUtilsHelper.GetColorFromState(Console.State);
|
var color = ServerUtilsHelper.GetColorFromState(Console.State);
|
||||||
}
|
}
|
||||||
|
|
||||||
<i class="bx bx-sm bxs-circle text-@(color) @(Console.State != ServerState.Offline ? $"pulse pulse-{color}" : "") align-middle"></i>
|
<i class="bx bx-sm bxs-circle text-@(color) @(Console.State != ServerState.Offline ? $"pulse pulse-{color}" : "") align-middle"></i>
|
||||||
<span class="align-middle">
|
<span class="align-middle">
|
||||||
@(Console.State)
|
@(Console.State)
|
||||||
<span class="text-muted">(@(Formatter.FormatUptime(DateTime.UtcNow - Console.LastStateChangeTimestamp)))</span>
|
<span class="text-muted">(@(Formatter.FormatUptime(DateTime.UtcNow - Console.LastStateChangeTimestamp)))</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-gray-800 pt-3 fw-semibold fs-5 row">
|
<div class="text-gray-800 pt-3 fw-semibold fs-5 row">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<span>
|
<span>
|
||||||
<i class="bx bx-sm bx-globe align-middle text-info"></i>
|
<i class="bx bx-sm bx-globe align-middle text-info"></i>
|
||||||
<span class="align-middle">@(Server.Node.Fqdn):@(Server.MainAllocation.Port)</span>
|
<span class="align-middle">@(Server.Node.Fqdn):@(Server.MainAllocation.Port)</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@*
|
@*
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@@ -73,47 +75,47 @@
|
|||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
@if (Console.State == ServerState.Offline)
|
@if (Console.State == ServerState.Offline)
|
||||||
{
|
{
|
||||||
<WButton
|
<WButton
|
||||||
OnClick="Start"
|
OnClick="Start"
|
||||||
CssClasses="btn btn-light-success btn-icon me-1 my-1">
|
CssClasses="btn btn-light-success btn-icon me-1 my-1">
|
||||||
<i class="bx bx-sm bx-play"></i>
|
<i class="bx bx-sm bx-play"></i>
|
||||||
</WButton>
|
</WButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-light-success btn-icon me-1 my-1 disabled" disabled="">
|
<button type="button" class="btn btn-light-success btn-icon me-1 my-1 disabled" disabled="">
|
||||||
<i class="bx bx-sm bx-play"></i>
|
<i class="bx bx-sm bx-play"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Console.State == ServerState.Offline || Console.State == ServerState.Installing)
|
@if (Console.State == ServerState.Offline || Console.State == ServerState.Installing)
|
||||||
{
|
{
|
||||||
<button class="btn btn-light-warning btn-icon me-1 my-1 disabled" disabled="">
|
<button class="btn btn-light-warning btn-icon me-1 my-1 disabled" disabled="">
|
||||||
<i class="bx bx-sm bx-power-off"></i>
|
<i class="bx bx-sm bx-power-off"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<WButton
|
<WButton
|
||||||
OnClick="Stop"
|
OnClick="Stop"
|
||||||
CssClasses="btn btn-light-warning btn-icon me-1 my-1">
|
CssClasses="btn btn-light-warning btn-icon me-1 my-1">
|
||||||
<i class="bx bx-sm bx-power-off"></i>
|
<i class="bx bx-sm bx-power-off"></i>
|
||||||
</WButton>
|
</WButton>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Console.State == ServerState.Offline || Console.State == ServerState.Installing)
|
@if (Console.State == ServerState.Offline || Console.State == ServerState.Installing)
|
||||||
{
|
{
|
||||||
<button class="btn btn-light-danger btn-icon me-1 my-1 disabled" disabled="">
|
<button class="btn btn-light-danger btn-icon me-1 my-1 disabled" disabled="">
|
||||||
<i class="bx bx-sm bx-bomb"></i>
|
<i class="bx bx-sm bx-bomb"></i>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<WButton
|
<WButton
|
||||||
OnClick="Kill"
|
OnClick="Kill"
|
||||||
CssClasses="btn btn-light-danger btn-icon me-1 my-1">
|
CssClasses="btn btn-light-danger btn-icon me-1 my-1">
|
||||||
<i class="bx bx-sm bx-bomb"></i>
|
<i class="bx bx-sm bx-bomb"></i>
|
||||||
</WButton>
|
</WButton>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,7 +156,7 @@
|
|||||||
{
|
{
|
||||||
<CascadingValue Value="Server">
|
<CascadingValue Value="Server">
|
||||||
<CascadingValue Value="Console">
|
<CascadingValue Value="Console">
|
||||||
<SmartRouter Route="@Route">
|
<MCBRouter Route="@Route">
|
||||||
<Route Path="/">
|
<Route Path="/">
|
||||||
<Console/>
|
<Console/>
|
||||||
</Route>
|
</Route>
|
||||||
@@ -186,7 +188,7 @@
|
|||||||
<Route Path="/reset">
|
<Route Path="/reset">
|
||||||
<Reset/>
|
<Reset/>
|
||||||
</Route>
|
</Route>
|
||||||
</SmartRouter>
|
</MCBRouter>
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
}
|
}
|
||||||
@@ -233,7 +235,7 @@
|
|||||||
await lazyLoader.SetText("Establishing a connection to the server");
|
await lazyLoader.SetText("Establishing a connection to the server");
|
||||||
|
|
||||||
// Create console wrapper
|
// Create console wrapper
|
||||||
Console = new ServerConsole(Server);
|
Console = new ServerConsole(Server, LoggerFactory);
|
||||||
|
|
||||||
// Configure
|
// Configure
|
||||||
Console.OnStateChange += async state => await HandleStateChange(state);
|
Console.OnStateChange += async state => await HandleStateChange(state);
|
||||||
@@ -266,7 +268,7 @@
|
|||||||
if (httpRequestException.InnerException is not SocketException socketException)
|
if (httpRequestException.InnerException is not SocketException socketException)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
Logger.Warn($"Unable to access the node's websocket endpoint: {socketException.Message}");
|
Logger.LogWarning("Unable to access the node's websocket endpoint: {socketException}", socketException);
|
||||||
|
|
||||||
// Change the ui and...
|
// Change the ui and...
|
||||||
IsNodeOffline = true;
|
IsNodeOffline = true;
|
||||||
@@ -328,8 +330,13 @@
|
|||||||
{
|
{
|
||||||
if (!ConfigService.Get().DisableServerKillWarning)
|
if (!ConfigService.Get().DisableServerKillWarning)
|
||||||
{
|
{
|
||||||
if (!await AlertService.YesNo("Do you really want to kill the server? This can result in data loss or corrupted server files"))
|
await AlertService.Confirm(
|
||||||
return;
|
"Server kill confirmation",
|
||||||
|
"Do you really want to kill the server? This can result in data loss or corrupted server files",
|
||||||
|
async () => await SendSignalHandled(PowerAction.Kill)
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await SendSignalHandled(PowerAction.Kill);
|
await SendSignalHandled(PowerAction.Kill);
|
||||||
@@ -347,8 +354,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An error occured while sending power action {action} to server {Server.Id}:");
|
Logger.LogWarning("An error occured while sending power action {action} to server {serverId}: {e}", action, Server.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await ToastService.Danger("An error occured while sending power action to server. Check the console for more information");
|
await ToastService.Danger("An error occured while sending power action to server. Check the console for more information");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@using BlazorTable
|
@using BlazorTable
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject Repository<ServerNode> NodeRepository
|
@inject Repository<ServerNode> NodeRepository
|
||||||
@inject Repository<ServerAllocation> AllocationRepository
|
@inject Repository<ServerAllocation> AllocationRepository
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8 col-12">
|
<div class="col-md-8 col-12">@*
|
||||||
<AutoListCrud TRootItem="ServerNode"
|
<AutoListCrud TRootItem="ServerNode"
|
||||||
TItem="ServerAllocation"
|
TItem="ServerAllocation"
|
||||||
TCreateForm="CreateAllocationForm"
|
TCreateForm="CreateAllocationForm"
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
In order for a server to be deployed on this node allocations need to be created here
|
In order for a server to be deployed on this node allocations need to be created here
|
||||||
</IconAlert>
|
</IconAlert>
|
||||||
</NoItemsView>
|
</NoItemsView>
|
||||||
</AutoListCrud>
|
</AutoListCrud>*@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
[Parameter] public ServerNode Node { get; set; }
|
[Parameter] public ServerNode Node { get; set; }
|
||||||
|
|
||||||
// A bit long, lol
|
// A bit long, lol
|
||||||
private AutoListCrud<ServerAllocation, ServerNode, CreateAllocationForm, UpdateAllocationForm> Crud;
|
//private AutoListCrud<ServerAllocation, ServerNode, CreateAllocationForm, UpdateAllocationForm> Crud;
|
||||||
|
|
||||||
// Quick add values
|
// Quick add values
|
||||||
private string IpAddress = "0.0.0.0";
|
private string IpAddress = "0.0.0.0";
|
||||||
@@ -101,31 +101,31 @@
|
|||||||
NodeRepository.Update(Node!);
|
NodeRepository.Update(Node!);
|
||||||
|
|
||||||
await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations");
|
await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations");
|
||||||
await Crud.Reload();
|
//await Crud.Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteAllAllocations()
|
private async Task DeleteAllAllocations()
|
||||||
{
|
{
|
||||||
if (!await AlertService.YesNo("Do you really want to delete all allocations?", "Yes", "No"))
|
await AlertService.Confirm("Confirm mass deletion", "Do you really want to delete all allocations?", async () =>
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var allocation in Node!.Allocations.ToArray()) // To array in order to prevent collection modified exception
|
|
||||||
{
|
{
|
||||||
// Check if a server is using this allocation before deleting
|
foreach (var allocation in Node!.Allocations.ToArray()) // To array in order to prevent collection modified exception
|
||||||
|
|
||||||
if (ServerRepository
|
|
||||||
.Get()
|
|
||||||
.Any(x => x.Allocations.Any(y => y.Id == allocation.Id)))
|
|
||||||
{
|
{
|
||||||
await ToastService.Danger($"Unable to delete allocation with port {allocation.Port} due to a server using this allocation");
|
// Check if a server is using this allocation before deleting
|
||||||
continue;
|
|
||||||
|
if (ServerRepository
|
||||||
|
.Get()
|
||||||
|
.Any(x => x.Allocations.Any(y => y.Id == allocation.Id)))
|
||||||
|
{
|
||||||
|
await ToastService.Danger($"Unable to delete allocation with port {allocation.Port} due to a server using this allocation");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AllocationRepository.Delete(allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocationRepository.Delete(allocation);
|
await ToastService.Success("Successfully deleted allocations");
|
||||||
}
|
//await Crud.Reload();
|
||||||
|
});
|
||||||
await ToastService.Success("Successfully deleted allocations");
|
|
||||||
await Crud.Reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task ValidateDelete(ServerAllocation allocation)
|
private Task ValidateDelete(ServerAllocation allocation)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
@using Moonlight.Features.Servers.Services
|
@using Moonlight.Features.Servers.Services
|
||||||
|
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
@inject NodeService NodeService
|
@inject NodeService NodeService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
@inject ILogger<NodeLogs> Logger
|
||||||
|
|
||||||
<div class="card card-body mb-5 p-3">
|
<div class="card card-body mb-5 p-3">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
@@ -69,8 +70,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An error occured while fetching logs from node '{Node.Name}'");
|
Logger.LogWarning("An error occured while fetching logs from node '{name}': {e}", Node.Name, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await ToastService.Danger("An error occured while fetching logs. Please try again later");
|
await ToastService.Danger("An error occured while fetching logs. Please try again later");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
@using MoonCore.Services
|
@using MoonCore.Services
|
||||||
@using Moonlight.Core.Configuration
|
@using Moonlight.Core.Configuration
|
||||||
@using Moonlight.Core.Services
|
@using Moonlight.Core.Services
|
||||||
|
@using IdentityService = Moonlight.Core.Services.IdentityService
|
||||||
|
|
||||||
@inject ConfigService<CoreConfiguration> ConfigService
|
@inject ConfigService<CoreConfiguration> ConfigService
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Features.Servers.Events
|
@using Moonlight.Features.Servers.Events
|
||||||
@using Moonlight.Features.Servers.Helpers
|
@using Moonlight.Features.Servers.Helpers
|
||||||
@using Moonlight.Features.Servers.Models.Enums
|
@using Moonlight.Features.Servers.Models.Enums
|
||||||
@@ -13,13 +13,14 @@
|
|||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
@inject ServerEvents ServerEvents
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
<LazyLoader @ref="LazyLoader" Load="Load">
|
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||||
<div class="card card-body px-5 py-3 mb-5">
|
<div class="card card-body px-5 py-3 mb-5">
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
<WButton OnClick="Create" CssClasses="btn btn-primary" Text="Create backup"/>
|
<WButton OnClick="Create" CssClasses="btn btn-primary">Create backup</WButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -171,23 +172,23 @@
|
|||||||
|
|
||||||
public async Task Restore(ServerBackup backup)
|
public async Task Restore(ServerBackup backup)
|
||||||
{
|
{
|
||||||
if(!await AlertService.YesNo("Do you really want to restore this backup? All files on the server will be deleted and replaced by the backup"))
|
await AlertService.Confirm("Confirm backup restore", "Do you really want to restore this backup? All files on the server will be deleted and replaced by the backup", async () =>
|
||||||
return;
|
{
|
||||||
|
await ServerService.Backup.Restore(Server, backup);
|
||||||
await ServerService.Backup.Restore(Server, backup);
|
|
||||||
|
|
||||||
await ToastService.Success("Successfully restored backup");
|
await ToastService.Success("Successfully restored backup");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(ServerBackup backup, bool safeDelete = true)
|
public async Task Delete(ServerBackup backup, bool safeDelete = true)
|
||||||
{
|
{
|
||||||
if(!await AlertService.YesNo("Do you really want to delete this backup? Deleted backups cannot be restored"))
|
await AlertService.Confirm("Confirm backup deletion", "Do you really want to delete this backup? Deleted backups cannot be restored", async () =>
|
||||||
return;
|
{
|
||||||
|
await ServerService.Backup.Delete(Server, backup, safeDelete);
|
||||||
await ServerService.Backup.Delete(Server, backup, safeDelete);
|
|
||||||
|
|
||||||
await ToastService.Success("Successfully deleted backup");
|
await ToastService.Success("Successfully deleted backup");
|
||||||
await LazyLoader.Reload();
|
await LazyLoader.Reload();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Download(ServerBackup backup)
|
private async Task Download(ServerBackup backup)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input @bind="CommandInput" @bind:event="onchange" @onkeyup="OnEnterPressed" class="form-control form-control-transparent text-white" placeholder="Enter command"/>
|
<input @bind="CommandInput" @bind:event="onchange" @onkeyup="OnEnterPressed" class="form-control form-control-transparent text-white" placeholder="Enter command"/>
|
||||||
<WButton CssClasses="btn btn-secondary rounded-start" Text="Execute" OnClick="SendCommand"/>
|
<WButton CssClasses="btn btn-secondary rounded-start" OnClick="SendCommand">Execute</WButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
<LazyLoader Load="Load" ShowAsCard="true">
|
<LazyLoader Load="Load">
|
||||||
<FileManager FileAccess="FileAccess" />
|
<FileManager FileAccess="FileAccess" />
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@inject Repository<ServerNetwork> NetworkRepository
|
@inject Repository<ServerNetwork> NetworkRepository
|
||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
<div class="card card-body mb-15 py-3 px-5">
|
<div class="card card-body mb-15 py-3 px-5">
|
||||||
@if (!Server.DisablePublicNetwork)
|
@if (!Server.DisablePublicNetwork)
|
||||||
{
|
{
|
||||||
<CrudTable TItem="ServerAllocation" ItemSource="Server.Allocations" PageSize="25" ShowPagination="false">
|
<MCBTable TItem="ServerAllocation" ItemSource="Server.Allocations" PageSize="25" ShowPagination="false">
|
||||||
<CrudColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="FQDN or dedicated IP">
|
<MCBColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="FQDN or dedicated IP">
|
||||||
<Template>
|
<Template>
|
||||||
@if (context!.IpAddress == "0.0.0.0")
|
@if (context!.IpAddress == "0.0.0.0")
|
||||||
{
|
{
|
||||||
@@ -52,8 +52,8 @@
|
|||||||
<span>@context.IpAddress</span>
|
<span>@context.IpAddress</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="IP address">
|
<MCBColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="IP address">
|
||||||
<Template>
|
<Template>
|
||||||
@if (context!.IpAddress == "0.0.0.0")
|
@if (context!.IpAddress == "0.0.0.0")
|
||||||
{
|
{
|
||||||
@@ -71,14 +71,14 @@
|
|||||||
<span>-</span>
|
<span>-</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerAllocation" Field="@(x => x.Port)" Title="Port"/>
|
<MCBColumn TItem="ServerAllocation" Field="@(x => x.Port)" Title="Port"/>
|
||||||
<CrudColumn TItem="ServerAllocation" Field="@(x => x.Note)" Title="Notes">
|
<MCBColumn TItem="ServerAllocation" Field="@(x => x.Note)" Title="Notes">
|
||||||
<Template>
|
<Template>
|
||||||
<input class="form-control" placeholder="What is this allocation for?"/>
|
<input class="form-control" placeholder="What is this allocation for?"/>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerAllocation">
|
<MCBColumn TItem="ServerAllocation">
|
||||||
<Template>
|
<Template>
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
<WButton CssClasses="btn btn-icon btn-danger disabled">
|
<WButton CssClasses="btn btn-icon btn-danger disabled">
|
||||||
@@ -86,8 +86,8 @@
|
|||||||
</WButton>
|
</WButton>
|
||||||
</div>
|
</div>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</CrudTable>
|
</MCBTable>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
@using Moonlight.Features.Servers.Models.Abstractions
|
@using Moonlight.Features.Servers.Models.Abstractions
|
||||||
@using Moonlight.Features.Servers.Models.Enums
|
@using Moonlight.Features.Servers.Models.Enums
|
||||||
@using Moonlight.Features.Servers.Services
|
@using Moonlight.Features.Servers.Services
|
||||||
@using MoonCoreUI.Services
|
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
</p>
|
</p>
|
||||||
@if (Console.State == ServerState.Offline)
|
@if (Console.State == ServerState.Offline)
|
||||||
{
|
{
|
||||||
<WButton OnClick="Reinstall" CssClasses="btn btn-primary mt-auto" Text="Reinstall"/>
|
<WButton OnClick="Reinstall" CssClasses="btn btn-primary mt-auto">Reinstall</WButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
</p>
|
</p>
|
||||||
@if (Console.State == ServerState.Offline)
|
@if (Console.State == ServerState.Offline)
|
||||||
{
|
{
|
||||||
<WButton OnClick="ResetServer" CssClasses="btn btn-warning mt-auto" Text="Reset"/>
|
<WButton OnClick="ResetServer" CssClasses="btn btn-warning mt-auto">Reset</WButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -43,14 +43,15 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 col-12"> @* TODO: Make deleting configurable to show or not *@
|
<div class="col-md-6 col-12">
|
||||||
|
@* TODO: Make deleting configurable to show or not *@
|
||||||
<div class="card card-body p-8 h-100">
|
<div class="card card-body p-8 h-100">
|
||||||
<p class="fs-6">
|
<p class="fs-6">
|
||||||
This deletes your server. The deleted data is not recoverable. Please make sure you have a backup of the data before deleting the server
|
This deletes your server. The deleted data is not recoverable. Please make sure you have a backup of the data before deleting the server
|
||||||
</p>
|
</p>
|
||||||
@if (Console.State == ServerState.Offline)
|
@if (Console.State == ServerState.Offline)
|
||||||
{
|
{
|
||||||
<WButton OnClick="Delete" CssClasses="btn btn-danger mt-auto" Text="Delete"/>
|
<WButton OnClick="Delete" CssClasses="btn btn-danger mt-auto">Delete</WButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -78,50 +79,48 @@
|
|||||||
|
|
||||||
private async Task Reinstall()
|
private async Task Reinstall()
|
||||||
{
|
{
|
||||||
if (!await AlertService.YesNo("Do you want to reinstall this server? This may replace/delete some files"))
|
await AlertService.Confirm("Confirm reinstall", "Do you want to reinstall this server? This may replace/delete some files", async () => { await ServerService.Console.SendAction(Server, PowerAction.Install); });
|
||||||
return;
|
|
||||||
|
|
||||||
await ServerService.Console.SendAction(Server, PowerAction.Install);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ResetServer()
|
private async Task ResetServer()
|
||||||
{
|
{
|
||||||
if (!await AlertService.YesNo("Do you want to reset this server? This will delete all files and run the install script"))
|
await AlertService.Confirm("Confirm server reset", "Do you want to reset this server? This will delete all files and run the install script", async () =>
|
||||||
return;
|
|
||||||
|
|
||||||
await ToastService.CreateProgress("serverReset", "Reset: Deleting files");
|
|
||||||
|
|
||||||
using var fileAccess = await ServerService.OpenFileAccess(Server);
|
|
||||||
|
|
||||||
var files = await fileAccess.List();
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
foreach (var fileEntry in files)
|
|
||||||
{
|
{
|
||||||
i++;
|
await ToastService.CreateProgress("serverReset", "Reset: Deleting files");
|
||||||
|
|
||||||
await ToastService.ModifyProgress("serverReset", $"Reset: Deleting files [{i} / {files.Length}]");
|
using var fileAccess = await ServerService.OpenFileAccess(Server);
|
||||||
await fileAccess.Delete(fileEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
await ToastService.ModifyProgress("serverReset", "Reset: Starting install script");
|
var files = await fileAccess.List();
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
await ServerService.Console.SendAction(Server, PowerAction.Install);
|
foreach (var fileEntry in files)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
|
||||||
await ToastService.RemoveProgress("serverReset");
|
await ToastService.UpdateProgress("serverReset", $"Reset: Deleting files [{i} / {files.Length}]");
|
||||||
|
await fileAccess.Delete(fileEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ToastService.UpdateProgress("serverReset", "Reset: Starting install script");
|
||||||
|
|
||||||
|
await ServerService.Console.SendAction(Server, PowerAction.Install);
|
||||||
|
|
||||||
|
await ToastService.DeleteProgress("serverReset");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Delete()
|
private async Task Delete()
|
||||||
{
|
{
|
||||||
var input = await AlertService.Text($"Please type '{Server.Name}' to confirm deleting this server");
|
await AlertService.Text("Server deletion", $"Please type '{Server.Name}' to confirm deleting this server", async input =>
|
||||||
|
{
|
||||||
if(input != Server.Name)
|
if (input != Server.Name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await ServerService.Delete(Server);
|
await ServerService.Delete(Server);
|
||||||
|
|
||||||
await ToastService.Success("Successfully deleted server");
|
await ToastService.Success("Successfully deleted server");
|
||||||
Navigation.NavigateTo("/servers");
|
Navigation.NavigateTo("/servers");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnStateChanged(ServerState _) => await InvokeAsync(StateHasChanged);
|
private async Task OnStateChanged(ServerState _) => await InvokeAsync(StateHasChanged);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Features.Servers.Models.Forms.Users.Schedules
|
@using Moonlight.Features.Servers.Models.Forms.Users.Schedules
|
||||||
@using Moonlight.Features.Servers.Services
|
@using Moonlight.Features.Servers.Services
|
||||||
@using Newtonsoft.Json
|
@using Newtonsoft.Json
|
||||||
@@ -19,11 +19,13 @@
|
|||||||
<div class="col-md-3 col-12">
|
<div class="col-md-3 col-12">
|
||||||
<div class="card card-body p-5">
|
<div class="card card-body p-5">
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<WButton OnClick="CreateSchedule" CssClasses="btn btn-primary my-3 mb-5" Text="Create new schedule"/>
|
<WButton OnClick="CreateSchedule" CssClasses="btn btn-primary my-3 mb-5">Create new schedule</WButton>
|
||||||
|
|
||||||
@foreach (var schedule in ServerWithSchedules.Schedules)
|
@foreach (var schedule in ServerWithSchedules.Schedules)
|
||||||
{
|
{
|
||||||
<WButton OnClick="() => SelectSchedule(schedule)" CssClasses="btn btn-secondary my-3" Text="@schedule.Name"/>
|
<WButton OnClick="() => SelectSchedule(schedule)" CssClasses="btn btn-secondary my-3">
|
||||||
|
@schedule.Name
|
||||||
|
</WButton>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -158,15 +160,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
|
|
||||||
<FormModalLauncher @ref="Launcher"/>
|
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
[CascadingParameter] public Server Server { get; set; }
|
[CascadingParameter] public Server Server { get; set; }
|
||||||
|
|
||||||
private Server ServerWithSchedules;
|
private Server ServerWithSchedules;
|
||||||
private LazyLoader LazyLoader;
|
private LazyLoader LazyLoader;
|
||||||
private FormModalLauncher Launcher;
|
|
||||||
|
|
||||||
private ServerSchedule? SelectedSchedule;
|
private ServerSchedule? SelectedSchedule;
|
||||||
private List<ServerScheduleItem> SortedItems = new();
|
private List<ServerScheduleItem> SortedItems = new();
|
||||||
@@ -208,11 +207,11 @@
|
|||||||
|
|
||||||
private async Task CreateSchedule()
|
private async Task CreateSchedule()
|
||||||
{
|
{
|
||||||
await Launcher.Show<CreateScheduleForm>("Create a new schedule", async form =>
|
await AlertService.Text("New schedule", "Create a new schedule", async name =>
|
||||||
{
|
{
|
||||||
ServerWithSchedules.Schedules.Add(new()
|
ServerWithSchedules.Schedules.Add(new()
|
||||||
{
|
{
|
||||||
Name = form.Name
|
Name = name
|
||||||
});
|
});
|
||||||
|
|
||||||
ServerRepository.Update(ServerWithSchedules);
|
ServerRepository.Update(ServerWithSchedules);
|
||||||
@@ -243,7 +242,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Launcher.Show("Configure action", async formData => { await AddScheduleAction(NewItemActionType, SelectedSchedule.Items.Count, formData); }, action.FormType);
|
// TODO: Redo everything here
|
||||||
|
//await Launcher.Show("Configure action", async formData => { await AddScheduleAction(NewItemActionType, SelectedSchedule.Items.Count, formData); }, action.FormType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddScheduleAction(string type, int priority, object data)
|
private async Task AddScheduleAction(string type, int priority, object data)
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
var action = ScheduleService.Actions.First(x => x.Key == item.Action).Value;
|
var action = ScheduleService.Actions.First(x => x.Key == item.Action).Value;
|
||||||
|
|
||||||
var formModel = JsonConvert.DeserializeObject(item.DataJson, action.FormType)!;
|
var formModel = JsonConvert.DeserializeObject(item.DataJson, action.FormType)!;
|
||||||
|
/*
|
||||||
await Launcher.Show("Configure action", async formData =>
|
await Launcher.Show("Configure action", async formData =>
|
||||||
{
|
{
|
||||||
item.DataJson = JsonConvert.SerializeObject(formData);
|
item.DataJson = JsonConvert.SerializeObject(formData);
|
||||||
@@ -284,7 +284,7 @@
|
|||||||
ScheduleItemRepository.Update(item);
|
ScheduleItemRepository.Update(item);
|
||||||
|
|
||||||
await ToastService.Success("Successfully updated action");
|
await ToastService.Success("Successfully updated action");
|
||||||
}, action.FormType, formModel: formModel);
|
}, action.FormType, formModel: formModel);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task MoveItem(ServerScheduleItem item, int move)
|
private async Task MoveItem(ServerScheduleItem item, int move)
|
||||||
@@ -312,18 +312,18 @@
|
|||||||
if (SelectedSchedule == null)
|
if (SelectedSchedule == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!await AlertService.YesNo("Do you really want to delete this action? This cannot be undone"))
|
await AlertService.Confirm("Confirm schedule item deletion", "Do you really want to delete this action? This cannot be undone", async () =>
|
||||||
return;
|
{
|
||||||
|
SortedItems.Remove(item);
|
||||||
|
SelectedSchedule.Items.Remove(item);
|
||||||
|
|
||||||
SortedItems.Remove(item);
|
ScheduleRepository.Update(SelectedSchedule);
|
||||||
SelectedSchedule.Items.Remove(item);
|
|
||||||
|
|
||||||
ScheduleRepository.Update(SelectedSchedule);
|
await FixPriorities();
|
||||||
|
|
||||||
await FixPriorities();
|
await ToastService.Success("Successfully deleted action");
|
||||||
|
await LazyLoader.Reload();
|
||||||
await ToastService.Success("Successfully deleted action");
|
});
|
||||||
await LazyLoader.Reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task FixPriorities()
|
private Task FixPriorities()
|
||||||
@@ -346,27 +346,27 @@
|
|||||||
if (SelectedSchedule == null)
|
if (SelectedSchedule == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!await AlertService.YesNo($"Do you really want to delete the schedule '{SelectedSchedule.Name}'? This cannot be undone"))
|
await AlertService.Confirm("Confirm schedule deletion", $"Do you really want to delete the schedule '{SelectedSchedule.Name}'? This cannot be undone", async () =>
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var item in SelectedSchedule.Items.ToArray())
|
|
||||||
{
|
{
|
||||||
try
|
foreach (var item in SelectedSchedule.Items.ToArray())
|
||||||
{
|
{
|
||||||
ScheduleItemRepository.Delete(item);
|
try
|
||||||
|
{
|
||||||
|
ScheduleItemRepository.Delete(item);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
/* this should not fail the operation */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
/* this should not fail the operation */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScheduleRepository.Delete(SelectedSchedule);
|
ScheduleRepository.Delete(SelectedSchedule);
|
||||||
|
|
||||||
SelectedSchedule = null;
|
SelectedSchedule = null;
|
||||||
|
|
||||||
await ToastService.Success("Successfully deleted schedule");
|
await ToastService.Success("Successfully deleted schedule");
|
||||||
await LazyLoader.Reload();
|
await LazyLoader.Reload();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunSelectedSchedule()
|
private async Task RunSelectedSchedule()
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
|
|
||||||
var result = await ScheduleService.Run(Server, SelectedSchedule);
|
var result = await ScheduleService.Run(Server, SelectedSchedule);
|
||||||
|
|
||||||
await ToastService.RemoveProgress("scheduleRun");
|
await ToastService.DeleteProgress("scheduleRun");
|
||||||
|
|
||||||
if (result.Failed)
|
if (result.Failed)
|
||||||
await ToastService.Danger($"Schedule run failed ({result.ExecutionSeconds}s)");
|
await ToastService.Danger($"Schedule run failed ({result.ExecutionSeconds}s)");
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using Moonlight.Features.Servers.UI.Components.VariableViews
|
@using Moonlight.Features.Servers.UI.Components.VariableViews
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Features.Servers.Entities.Enums
|
@using Moonlight.Features.Servers.Entities.Enums
|
||||||
|
|
||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
@inject Repository<ServerVariable> ServerVariableRepository
|
@inject Repository<ServerVariable> ServerVariableRepository
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
|
||||||
<LazyLoader @ref="LazyLoader" Load="Load" ShowAsCard="true">
|
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||||
<div class="row mt-1 g-5">
|
<div class="row mt-1 g-5">
|
||||||
<div class="col-md-6 col-12">
|
<div class="col-md-6 col-12">
|
||||||
<div class="card card-body p-5 h-100">
|
<div class="card card-body p-5 h-100">
|
||||||
<label class="form-label fs-5">Docker image</label>
|
<label class="form-label fs-5">Docker image</label>
|
||||||
@if (Image.AllowDockerImageChange)
|
@if (Image.AllowDockerImageChange)
|
||||||
{
|
{
|
||||||
<SmartSelect @bind-Value="SelectedDockerImage"
|
<MCBSelect @bind-Value="SelectedDockerImage"
|
||||||
Items="Image.DockerImages"
|
Items="Image.DockerImages"
|
||||||
DisplayField="@(x => x.DisplayName)"
|
DisplayField="@(x => x.DisplayName)"
|
||||||
OnChange="OnDockerImageChanged"/>
|
OnChange="OnDockerImageChanged"/>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using Moonlight.Features.Servers.Helpers
|
@using Moonlight.Features.Servers.Helpers
|
||||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
|
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
|
||||||
@@ -17,9 +17,10 @@
|
|||||||
@inject Repository<ServerImage> ImageRepository
|
@inject Repository<ServerImage> ImageRepository
|
||||||
|
|
||||||
@inject ImageConversionHelper ImageConversionHelper
|
@inject ImageConversionHelper ImageConversionHelper
|
||||||
@inject FileDownloadService FileDownloadService
|
@inject DownloadService DownloadService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
|
@inject ILogger<Index> Logger
|
||||||
|
|
||||||
@attribute [RequirePermission(5002)]
|
@attribute [RequirePermission(5002)]
|
||||||
|
|
||||||
@@ -34,14 +35,14 @@
|
|||||||
CustomDelete="CustomDelete"
|
CustomDelete="CustomDelete"
|
||||||
@ref="Crud">
|
@ref="Crud">
|
||||||
<View>
|
<View>
|
||||||
<CrudColumn TItem="ServerImage" Field="@(x => x.Id)" Title="Id" Filterable="true"/>
|
<MCBColumn TItem="ServerImage" Field="@(x => x.Id)" Title="Id" Filterable="true"/>
|
||||||
<CrudColumn TItem="ServerImage" Field="@(x => x.Name)" Title="Name" Filterable="true">
|
<MCBColumn TItem="ServerImage" Field="@(x => x.Name)" Title="Name" Filterable="true">
|
||||||
<Template>
|
<Template>
|
||||||
<a href="/admin/servers/images/view/@context!.Id">@context.Name</a>
|
<a href="/admin/servers/images/view/@context!.Id">@context.Name</a>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerImage" Field="@(x => x.Author)" Title="Author" Filterable="true"/>
|
<MCBColumn TItem="ServerImage" Field="@(x => x.Author)" Title="Author" Filterable="true"/>
|
||||||
<CrudColumn TItem="ServerImage">
|
<MCBColumn TItem="ServerImage">
|
||||||
<Template>
|
<Template>
|
||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
@if (!string.IsNullOrEmpty(context.UpdateUrl))
|
@if (!string.IsNullOrEmpty(context.UpdateUrl))
|
||||||
@@ -66,8 +67,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</View>
|
</View>@*
|
||||||
<NoItemsView>
|
<NoItemsView>
|
||||||
<IconAlert Title="No images found" Color="primary" Icon="bx-search-alt">
|
<IconAlert Title="No images found" Color="primary" Icon="bx-search-alt">
|
||||||
Download and import a image from our <a href="https://github.com/Moonlight-Panel/Images">repository</a> or create a new one. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
Download and import a image from our <a href="https://github.com/Moonlight-Panel/Images">repository</a> or create a new one. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
||||||
@@ -84,14 +85,14 @@
|
|||||||
Import
|
Import
|
||||||
</a>
|
</a>
|
||||||
</SmartCustomFileSelect>
|
</SmartCustomFileSelect>
|
||||||
</OverviewToolbar>
|
</OverviewToolbar>*@
|
||||||
</AutoCrud>
|
</AutoCrud>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private AutoCrud<ServerImage, CreateImageForm, UpdateImageForm> Crud;
|
private AutoCrud<ServerImage, CreateImageForm, UpdateImageForm> Crud;
|
||||||
private SmartCustomFileSelect ImageUpload;
|
private MCBCustomFileSelect ImageUpload;
|
||||||
private SmartCustomFileSelect EggUpload;
|
private MCBCustomFileSelect EggUpload;
|
||||||
|
|
||||||
private IEnumerable<ServerImage> Load(Repository<ServerImage> repository)
|
private IEnumerable<ServerImage> Load(Repository<ServerImage> repository)
|
||||||
{
|
{
|
||||||
@@ -178,7 +179,7 @@
|
|||||||
{
|
{
|
||||||
var json = await ImageConversionHelper.ExportAsJson(image);
|
var json = await ImageConversionHelper.ExportAsJson(image);
|
||||||
var imageName = image.Name.Replace(" ", "");
|
var imageName = image.Name.Replace(" ", "");
|
||||||
await FileDownloadService.DownloadString($"{imageName}.json", json);
|
await DownloadService.DownloadString($"{imageName}.json", json);
|
||||||
|
|
||||||
await ToastService.Success($"Successfully exported '{image.Name}'");
|
await ToastService.Success($"Successfully exported '{image.Name}'");
|
||||||
}
|
}
|
||||||
@@ -198,7 +199,7 @@
|
|||||||
await ToastService.Success($"Successfully imported '{image.Name}'");
|
await ToastService.Success($"Successfully imported '{image.Name}'");
|
||||||
|
|
||||||
await ImageUpload.RemoveSelection();
|
await ImageUpload.RemoveSelection();
|
||||||
await Crud.Reload();
|
//await Crud.Reload();
|
||||||
}
|
}
|
||||||
catch (DisplayException)
|
catch (DisplayException)
|
||||||
{
|
{
|
||||||
@@ -206,8 +207,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn("An error occured while importing a image");
|
Logger.LogWarning("An error occured while importing a image: {e}", e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await ToastService.Danger("Unable to import egg: " + e.Message);
|
await ToastService.Danger("Unable to import egg: " + e.Message);
|
||||||
}
|
}
|
||||||
@@ -219,45 +219,39 @@
|
|||||||
|
|
||||||
private async Task ImportEgg(IBrowserFile file)
|
private async Task ImportEgg(IBrowserFile file)
|
||||||
{
|
{
|
||||||
var confirm = await AlertService.YesNo("Importing pterodactyl eggs is a experimental feature and may result in unusable images. Are you sure you want to proceed?",
|
await AlertService.Confirm("Import a pterodactyl egg", "Importing pterodactyl eggs is a experimental feature and may result in unusable images. Are you sure you want to proceed?",
|
||||||
"Yes, i take the risk",
|
async () =>
|
||||||
"Cancel");
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stream = file.OpenReadStream();
|
||||||
|
|
||||||
if (!confirm)
|
using var sr = new StreamReader(stream);
|
||||||
{
|
var content = await sr.ReadToEndAsync();
|
||||||
await EggUpload.RemoveSelection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
var image = await ImageConversionHelper.ImportFromEggJson(content);
|
||||||
{
|
|
||||||
var stream = file.OpenReadStream();
|
|
||||||
|
|
||||||
using var sr = new StreamReader(stream);
|
ImageRepository.Add(image);
|
||||||
var content = await sr.ReadToEndAsync();
|
await ToastService.Success($"Successfully imported '{image.Name}'");
|
||||||
|
|
||||||
var image = await ImageConversionHelper.ImportFromEggJson(content);
|
await EggUpload.RemoveSelection();
|
||||||
|
//await Crud.Reload();
|
||||||
|
}
|
||||||
|
catch (DisplayException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogWarning("An error occured while importing a pterodactyl egg: {e}", e);
|
||||||
|
|
||||||
ImageRepository.Add(image);
|
await ToastService.Danger("Unable to import egg: " + e.Message);
|
||||||
await ToastService.Success($"Successfully imported '{image.Name}'");
|
}
|
||||||
|
finally
|
||||||
await EggUpload.RemoveSelection();
|
{
|
||||||
await Crud.Reload();
|
await EggUpload.RemoveSelection();
|
||||||
}
|
}
|
||||||
catch (DisplayException)
|
},
|
||||||
{
|
"Yes, i take the risk");
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Warn("An error occured while importing a pterodactyl egg");
|
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await ToastService.Danger("Unable to import egg: " + e.Message);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
await EggUpload.RemoveSelection();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
@page "/admin/servers/images/view/{Id:int}/{Route?}"
|
@page "/admin/servers/images/view/{Id:int}/{Route?}"
|
||||||
|
|
||||||
@using Mappy.Net
|
@using Mappy.Net
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCore.Exceptions
|
@using MoonCore.Exceptions
|
||||||
@using MoonCore.Helpers
|
|
||||||
@using MoonCoreUI.Models
|
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using Moonlight.Features.Servers.Models.Enums
|
@using Moonlight.Features.Servers.Models.Enums
|
||||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Servers
|
@using Moonlight.Features.Servers.Models.Forms.Admin.Servers
|
||||||
@@ -15,11 +13,12 @@
|
|||||||
@inject ServerService ServerService
|
@inject ServerService ServerService
|
||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
|
@inject ILogger<Index> Logger
|
||||||
|
|
||||||
@attribute [RequirePermission(5000)]
|
@attribute [RequirePermission(5000)]
|
||||||
|
|
||||||
<AdminServersNavigation Index="0"/>
|
<AdminServersNavigation Index="0"/>
|
||||||
|
@*
|
||||||
<AutoCrud TItem="Server"
|
<AutoCrud TItem="Server"
|
||||||
TCreateForm="CreateServerForm"
|
TCreateForm="CreateServerForm"
|
||||||
TUpdateForm="CreateServerForm"
|
TUpdateForm="CreateServerForm"
|
||||||
@@ -30,40 +29,41 @@
|
|||||||
CustomDelete="CustomDelete"
|
CustomDelete="CustomDelete"
|
||||||
OnConfigure="OnConfigure">
|
OnConfigure="OnConfigure">
|
||||||
<View>
|
<View>
|
||||||
<CrudColumn TItem="Server" Field="@(x => x.Id)" Title="Id" Filterable="true"/>
|
<MCBColumn TItem="Server" Field="@(x => x.Id)" Title="Id" Filterable="true"/>
|
||||||
<CrudColumn TItem="Server" Field="@(x => x.Name)" Title="Name" Filterable="true"/>
|
<MCBColumn TItem="Server" Field="@(x => x.Name)" Title="Name" Filterable="true"/>
|
||||||
<CrudColumn TItem="Server" Field="@(x => x.Id)" Title="Image">
|
<MCBColumn TItem="Server" Field="@(x => x.Id)" Title="Image">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(context.Image.Name)</span>
|
<span>@(context.Image.Name)</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="Server" Field="@(x => x.Id)" Title="Node">
|
<MCBColumn TItem="Server" Field="@(x => x.Id)" Title="Node">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(context.Node.Name)</span>
|
<span>@(context.Node.Name)</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="Server" Field="@(x => x.Id)" Title="User">
|
<MCBColumn TItem="Server" Field="@(x => x.Id)" Title="User">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(context.Owner.Username)</span>
|
<span>@(context.Owner.Username)</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</View>
|
</View>
|
||||||
<NoItemsView>
|
<NoItemsView>
|
||||||
<IconAlert Title="No servers found" Color="primary" Icon="bx-search-alt">
|
<IconAlert Title="No servers found" Color="primary" Icon="bx-search-alt">
|
||||||
Create a new server in order to manage it using this page. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
Create a new server in order to manage it using this page. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
||||||
</IconAlert>
|
</IconAlert>
|
||||||
</NoItemsView>
|
</NoItemsView>
|
||||||
</AutoCrud>
|
</AutoCrud>*@
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
private void OnConfigure(AutoCrudOptions options)
|
private void OnConfigure(AutoCrudOptions options)
|
||||||
{
|
{
|
||||||
options.AddCustomItemLoader<Server, ServerAllocation>("FreeAllocations", LoadFreeAllocations);
|
options.AddCustomItemLoader<Server, ServerAllocation>("FreeAllocations", LoadFreeAllocations);
|
||||||
|
|
||||||
options.AddCustomDisplayFunction<ServerAllocation>("AllocationWithIp",
|
options.AddCustomDisplayFunction<ServerAllocation>("AllocationWithIp",
|
||||||
allocation => allocation.IpAddress + ":" + allocation.Port);
|
allocation => allocation.IpAddress + ":" + allocation.Port);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private IEnumerable<Server> Load(Repository<Server> repository)
|
private IEnumerable<Server> Load(Repository<Server> repository)
|
||||||
{
|
{
|
||||||
@@ -124,8 +124,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error("Unable to sync server changes due to an error occuring");
|
Logger.LogError("Unable to sync server changes due to an error occuring: {e}", e);
|
||||||
Logger.Error(e);
|
|
||||||
|
|
||||||
await ToastService.Danger("An error occured while sending the changes to the daemon");
|
await ToastService.Danger("An error occured while sending the changes to the daemon");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
@using MoonCore.Abstractions
|
@using MoonCore.Abstractions
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCoreUI.Services
|
|
||||||
@using Moonlight.Features.Servers.Api.Resources
|
@using Moonlight.Features.Servers.Api.Resources
|
||||||
@using Moonlight.Features.Servers.Entities
|
@using Moonlight.Features.Servers.Entities
|
||||||
@using Moonlight.Features.Servers.Services
|
@using Moonlight.Features.Servers.Services
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
@inject ServerService ServerService
|
@inject ServerService ServerService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
|
@inject ILogger<Manager> Logger
|
||||||
|
|
||||||
@attribute [RequirePermission(5000)]
|
@attribute [RequirePermission(5000)]
|
||||||
|
|
||||||
@@ -210,8 +211,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An error occured while fetching server list from node {node.Id}");
|
Logger.LogWarning("An error occured while fetching server list from node {nodeId}: {e}", node.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
OfflineNodes.Add(node);
|
OfflineNodes.Add(node);
|
||||||
|
|
||||||
@@ -248,33 +248,32 @@
|
|||||||
await Table.SetPageSizeAsync(PageSize);
|
await Table.SetPageSizeAsync(PageSize);
|
||||||
|
|
||||||
// Confirm
|
// Confirm
|
||||||
if(!await AlertService.YesNo($"Do you really want to perform the action '{action}' for {items.Length} servers?"))
|
await AlertService.Confirm("Confirm power action", $"Do you really want to perform the action '{action}' for {items.Length} servers?", async () =>
|
||||||
return;
|
|
||||||
|
|
||||||
await ToastService.CreateProgress("multiPowerAction", "Preparing");
|
|
||||||
|
|
||||||
// Perform
|
|
||||||
int i = 0;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
{
|
||||||
try
|
await ToastService.CreateProgress("multiPowerAction", "Preparing");
|
||||||
|
|
||||||
|
// Perform
|
||||||
|
int i = 0;
|
||||||
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
await ToastService.ModifyProgress("multiPowerAction", $"Sending power action [{i + 1} / {items.Length}]");
|
try
|
||||||
await ServerService.Console.SendAction(item.Server, action);
|
{
|
||||||
|
await ToastService.UpdateProgress("multiPowerAction", $"Sending power action [{i + 1} / {items.Length}]");
|
||||||
|
await ServerService.Console.SendAction(item.Server, action);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"An error occured while performing power action on server {item.Server.Id}");
|
Logger.LogWarning("An error occured while performing power action on server {serverId}: {e}", item.Server.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
await ToastService.Danger($"Unable to perform power action for server '{item.Server.Name}'");
|
await ToastService.Danger($"Unable to perform power action for server '{item.Server.Name}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await ToastService.RemoveProgress("multiPowerAction");
|
await ToastService.DeleteProgress("multiPowerAction");
|
||||||
await ToastService.Success($"Successfully performed the action for {i} servers");
|
await ToastService.Success($"Successfully performed the action for {i} servers");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
@inject Repository<ServerNode> NodeRepository
|
@inject Repository<ServerNode> NodeRepository
|
||||||
@inject NodeService NodeService
|
@inject NodeService NodeService
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
|
@inject ILogger<Index> Logger
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
@@ -31,14 +32,14 @@
|
|||||||
ValidateUpdate="ValidateUpdate"
|
ValidateUpdate="ValidateUpdate"
|
||||||
ValidateDelete="ValidateDelete">
|
ValidateDelete="ValidateDelete">
|
||||||
<View>
|
<View>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
|
<MCBColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name">
|
<MCBColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name">
|
||||||
<Template>
|
<Template>
|
||||||
<a href="/admin/servers/nodes/view/@(context!.Id)">@context!.Name</a>
|
<a href="/admin/servers/nodes/view/@(context!.Id)">@context!.Name</a>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
|
<MCBColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
|
||||||
<CrudColumn TItem="ServerNode" Title="Status">
|
<MCBColumn TItem="ServerNode" Title="Status">
|
||||||
<Template>
|
<Template>
|
||||||
@if (NodeStats.ContainsKey(context!.Id))
|
@if (NodeStats.ContainsKey(context!.Id))
|
||||||
{
|
{
|
||||||
@@ -56,8 +57,8 @@
|
|||||||
<span class="text-muted">N/A</span>
|
<span class="text-muted">N/A</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerNode" Title="CPU">
|
<MCBColumn TItem="ServerNode" Title="CPU">
|
||||||
<Template>
|
<Template>
|
||||||
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
||||||
{
|
{
|
||||||
@@ -71,8 +72,8 @@
|
|||||||
<span class="text-muted">N/A</span>
|
<span class="text-muted">N/A</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerNode" Title="Memory">
|
<MCBColumn TItem="ServerNode" Title="Memory">
|
||||||
<Template>
|
<Template>
|
||||||
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
||||||
{
|
{
|
||||||
@@ -90,8 +91,8 @@
|
|||||||
<span class="text-muted">N/A</span>
|
<span class="text-muted">N/A</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerNode" Title="Disk">
|
<MCBColumn TItem="ServerNode" Title="Disk">
|
||||||
<Template>
|
<Template>
|
||||||
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
||||||
{
|
{
|
||||||
@@ -105,13 +106,14 @@
|
|||||||
<span class="text-muted">N/A</span>
|
<span class="text-muted">N/A</span>
|
||||||
}
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</View>
|
</View>
|
||||||
|
@*
|
||||||
<NoItemsView>
|
<NoItemsView>
|
||||||
<IconAlert Title="No nodes found" Color="primary" Icon="bx-search-alt">
|
<IconAlert Title="No nodes found" Color="primary" Icon="bx-search-alt">
|
||||||
Add a new node in order to get started. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
Add a new node in order to get started. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
|
||||||
</IconAlert>
|
</IconAlert>
|
||||||
</NoItemsView>
|
</NoItemsView>*@
|
||||||
</AutoCrud>
|
</AutoCrud>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
|
|
||||||
@@ -140,8 +142,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unable to fetch system status for node '{node.Name}'");
|
Logger.LogWarning("Unable to fetch system status for node '{name}': {e}", node.Name, e);
|
||||||
Logger.Warn(e);
|
|
||||||
|
|
||||||
NodeStats[node.Id] = null;
|
NodeStats[node.Id] = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
@inject Repository<Server> ServerRepository
|
@inject Repository<Server> ServerRepository
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject ServerService ServerService
|
@inject ServerService ServerService
|
||||||
|
@inject ILogger<Index> Logger
|
||||||
|
|
||||||
<ServersNavigation Index="0"/>
|
<ServersNavigation Index="0"/>
|
||||||
|
|
||||||
@@ -163,8 +164,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unable to get server state for server {server.Id}");
|
Logger.LogWarning("Unable to get server state for server {serverId}: {e}", server.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -187,8 +187,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unable to get server stats for server {server.Id}");
|
Logger.LogWarning("Unable to get server stats for server {serverId}: {e}", server.Id, e);
|
||||||
Logger.Warn(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,13 +19,13 @@
|
|||||||
Loader="Load"
|
Loader="Load"
|
||||||
ValidateAdd="ValidateAdd">
|
ValidateAdd="ValidateAdd">
|
||||||
<View>
|
<View>
|
||||||
<CrudColumn TItem="ServerNetwork" Field="@(x => x.Name)" Title="Name"/>
|
<MCBColumn TItem="ServerNetwork" Field="@(x => x.Name)" Title="Name"/>
|
||||||
<CrudColumn TItem="ServerNetwork" Title="Node">
|
<MCBColumn TItem="ServerNetwork" Title="Node">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(context!.Node.Name)</span>
|
<span>@(context!.Node.Name)</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
<CrudColumn TItem="ServerNetwork" Title="Used by">
|
<MCBColumn TItem="ServerNetwork" Title="Used by">
|
||||||
<Template>
|
<Template>
|
||||||
@{
|
@{
|
||||||
var servers = UsedByCache.ContainsKey(context.Id) ? UsedByCache[context.Id] : Array.Empty<Server>();
|
var servers = UsedByCache.ContainsKey(context.Id) ? UsedByCache[context.Id] : Array.Empty<Server>();
|
||||||
@@ -38,13 +38,13 @@
|
|||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
</Template>
|
</Template>
|
||||||
</CrudColumn>
|
</MCBColumn>
|
||||||
</View>
|
</View>@*
|
||||||
<NoItemsView>
|
<NoItemsView>
|
||||||
<IconAlert Icon="bx-search-alt" Color="primary" Title="No private network found">
|
<IconAlert Icon="bx-search-alt" Color="primary" Title="No private network found">
|
||||||
Create a new private network in order to connect multiple servers on the same node
|
Create a new private network in order to connect multiple servers on the same node
|
||||||
</IconAlert>
|
</IconAlert>
|
||||||
</NoItemsView>
|
</NoItemsView>*@
|
||||||
</AutoCrud>
|
</AutoCrud>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
|
|||||||
@@ -93,8 +93,8 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MoonCore" Version="1.3.5" />
|
<PackageReference Include="MoonCore" Version="1.3.8" />
|
||||||
<PackageReference Include="MoonCoreUI" Version="1.2.1" />
|
<PackageReference Include="MoonCore.Blazor" Version="1.0.3" />
|
||||||
<PackageReference Include="Otp.NET" Version="1.3.0" />
|
<PackageReference Include="Otp.NET" Version="1.3.0" />
|
||||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
<!-- TODO: Replace with local version -->
|
<!-- TODO: Replace with local version -->
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,400,500,600,700">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,400,500,600,700">
|
||||||
|
|
||||||
|
<link href="/_content/MoonCore.Blazor/css/mooncore.blazor.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
||||||
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
|
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
|
||||||
</head>
|
</head>
|
||||||
<body data-kt-app-header-fixed="true"
|
<body data-kt-app-header-fixed="true"
|
||||||
@@ -62,6 +64,7 @@
|
|||||||
|
|
||||||
<!-- BlazorTable Interop -->
|
<!-- BlazorTable Interop -->
|
||||||
<script src="/_content/BlazorTable/BlazorTable.min.js"></script>
|
<script src="/_content/BlazorTable/BlazorTable.min.js"></script>
|
||||||
|
<script src="/_content/MoonCore.Blazor/js/mooncore.blazor.js"></script>
|
||||||
|
|
||||||
<!-- Blazor server script -->
|
<!-- Blazor server script -->
|
||||||
<script src="/_framework/blazor.server.js"></script>
|
<script src="/_framework/blazor.server.js"></script>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user