diff --git a/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs b/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs new file mode 100644 index 0000000..43fe3f6 --- /dev/null +++ b/MoonlightServers.ApiServer/Http/Controllers/Users/ServerPowerController.cs @@ -0,0 +1,125 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using MoonCore.Exceptions; +using MoonCore.Extended.Abstractions; +using MoonCore.Extensions; +using MoonlightServers.ApiServer.Database.Entities; +using MoonlightServers.ApiServer.Services; + +namespace MoonlightServers.ApiServer.Http.Controllers.Users; + +[ApiController] +[Authorize] +[Route("api/servers")] +public class ServerPowerController : Controller +{ + private readonly DatabaseRepository ServerRepository; + private readonly NodeService NodeService; + + public ServerPowerController(DatabaseRepository serverRepository, NodeService nodeService) + { + ServerRepository = serverRepository; + NodeService = nodeService; + } + + [HttpPost("{serverId:int}/start")] + [Authorize] + public async Task Start([FromRoute] int serverId) + { + var server = await GetServerWithPermCheck(serverId); + + using var apiClient = await NodeService.CreateApiClient(server.Node); + + try + { + await apiClient.Post($"api/servers/{server.Id}/start"); + } + catch (HttpRequestException e) + { + throw new HttpApiException("Unable to access the node the server is running on", 502); + } + } + + [HttpPost("{serverId:int}/stop")] + [Authorize] + public async Task Stop([FromRoute] int serverId) + { + var server = await GetServerWithPermCheck(serverId); + + using var apiClient = await NodeService.CreateApiClient(server.Node); + + try + { + await apiClient.Post($"api/servers/{server.Id}/stop"); + } + catch (HttpRequestException e) + { + throw new HttpApiException("Unable to access the node the server is running on", 502); + } + } + + [HttpPost("{serverId:int}/kill")] + [Authorize] + public async Task Kill([FromRoute] int serverId) + { + var server = await GetServerWithPermCheck(serverId); + + using var apiClient = await NodeService.CreateApiClient(server.Node); + + try + { + await apiClient.Post($"api/servers/{server.Id}/kill"); + } + catch (HttpRequestException e) + { + throw new HttpApiException("Unable to access the node the server is running on", 502); + } + } + + [HttpPost("{serverId:int}/install")] + [Authorize] + public async Task Install([FromRoute] int serverId) + { + var server = await GetServerWithPermCheck(serverId); + + using var apiClient = await NodeService.CreateApiClient(server.Node); + + try + { + await apiClient.Post($"api/servers/{server.Id}/install"); + } + catch (HttpRequestException e) + { + throw new HttpApiException("Unable to access the node the server is running on", 502); + } + } + + private async Task GetServerWithPermCheck(int serverId, + Func, IQueryable>? queryModifier = null) + { + var userIdClaim = User.Claims.First(x => x.Type == "userId"); + var userId = int.Parse(userIdClaim.Value); + + var query = ServerRepository + .Get() + .Include(x => x.Node) as IQueryable; + + if (queryModifier != null) + query = queryModifier.Invoke(query); + + var server = await query + .FirstOrDefaultAsync(x => x.Id == serverId); + + if (server == null) + throw new HttpApiException("No server with this id found", 404); + + if (server.OwnerId == userId) // The current user is the owner + return server; + + if (User.HasPermission("admin.servers.get")) // The current user is an admin + return server; + + throw new HttpApiException("No server with this id found", 404); + } +} \ No newline at end of file diff --git a/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs b/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs index bfa1b87..539e4a5 100644 --- a/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs +++ b/MoonlightServers.ApiServer/Http/Controllers/Users/ServersController.cs @@ -175,60 +175,6 @@ public class ServersController : Controller throw new HttpApiException("Unable to access the node the server is running on", 502); } } - - [HttpPost("{serverId:int}/start")] - [Authorize] - public async Task Start([FromRoute] int serverId) - { - var server = await GetServerWithPermCheck(serverId); - - using var apiClient = await NodeService.CreateApiClient(server.Node); - - try - { - await apiClient.Post($"api/servers/{server.Id}/start"); - } - catch (HttpRequestException e) - { - throw new HttpApiException("Unable to access the node the server is running on", 502); - } - } - - [HttpPost("{serverId:int}/stop")] - [Authorize] - public async Task Stop([FromRoute] int serverId) - { - var server = await GetServerWithPermCheck(serverId); - - using var apiClient = await NodeService.CreateApiClient(server.Node); - - try - { - await apiClient.Post($"api/servers/{server.Id}/stop"); - } - catch (HttpRequestException e) - { - throw new HttpApiException("Unable to access the node the server is running on", 502); - } - } - - [HttpPost("{serverId:int}/kill")] - [Authorize] - public async Task Kill([FromRoute] int serverId) - { - var server = await GetServerWithPermCheck(serverId); - - using var apiClient = await NodeService.CreateApiClient(server.Node); - - try - { - await apiClient.Post($"api/servers/{server.Id}/kill"); - } - catch (HttpRequestException e) - { - throw new HttpApiException("Unable to access the node the server is running on", 502); - } - } private async Task GetServerWithPermCheck(int serverId, Func, IQueryable>? queryModifier = null) diff --git a/MoonlightServers.Frontend/Implementations/DefaultServerTabProvider.cs b/MoonlightServers.Frontend/Implementations/DefaultServerTabProvider.cs new file mode 100644 index 0000000..623d4e2 --- /dev/null +++ b/MoonlightServers.Frontend/Implementations/DefaultServerTabProvider.cs @@ -0,0 +1,21 @@ +using MoonlightServers.Frontend.Interfaces; +using MoonlightServers.Frontend.Models; +using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs; +using MoonlightServers.Shared.Http.Responses.Users.Servers; + +namespace MoonlightServers.Frontend.Implementations; + +public class DefaultServerTabProvider : IServerTabProvider +{ + public Task GetTabs(ServerDetailResponse server) + { + ServerTab[] tabs = + [ + ServerTab.CreateFromComponent("Console", "console", 0), + ServerTab.CreateFromComponent("Files", "files", 1), + ServerTab.CreateFromComponent("Settings", "settings", 10), + ]; + + return Task.FromResult(tabs); + } +} \ No newline at end of file diff --git a/MoonlightServers.Frontend/Interfaces/IServerTabProvider.cs b/MoonlightServers.Frontend/Interfaces/IServerTabProvider.cs new file mode 100644 index 0000000..6ee8f13 --- /dev/null +++ b/MoonlightServers.Frontend/Interfaces/IServerTabProvider.cs @@ -0,0 +1,9 @@ +using MoonlightServers.Frontend.Models; +using MoonlightServers.Shared.Http.Responses.Users.Servers; + +namespace MoonlightServers.Frontend.Interfaces; + +public interface IServerTabProvider +{ + public Task GetTabs(ServerDetailResponse server); +} \ No newline at end of file diff --git a/MoonlightServers.Frontend/Models/ServerTab.cs b/MoonlightServers.Frontend/Models/ServerTab.cs index 5bd2a0b..9e3126d 100644 --- a/MoonlightServers.Frontend/Models/ServerTab.cs +++ b/MoonlightServers.Frontend/Models/ServerTab.cs @@ -1,7 +1,22 @@ +using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs; + namespace MoonlightServers.Frontend.Models; public class ServerTab { - public string Path { get; set; } - public string Name { get; set; } + public string Name { get; private set; } + public string Path { get; private set; } + public int Priority { get; set; } + public Type ComponentType { get; private set; } + + public static ServerTab CreateFromComponent(string name, string path, int priority) where T : BaseServerTab + { + return new() + { + Name = name, + Path = path, + Priority = priority, + ComponentType = typeof(T) + }; + } } \ No newline at end of file diff --git a/MoonlightServers.Frontend/MoonlightServers.Frontend.csproj b/MoonlightServers.Frontend/MoonlightServers.Frontend.csproj index 57f6888..e6d57b7 100644 --- a/MoonlightServers.Frontend/MoonlightServers.Frontend.csproj +++ b/MoonlightServers.Frontend/MoonlightServers.Frontend.csproj @@ -21,7 +21,6 @@ - diff --git a/MoonlightServers.Frontend/Startup/PluginStartup.cs b/MoonlightServers.Frontend/Startup/PluginStartup.cs index 5db24ce..2bb75f2 100644 --- a/MoonlightServers.Frontend/Startup/PluginStartup.cs +++ b/MoonlightServers.Frontend/Startup/PluginStartup.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MoonCore.Extensions; +using MoonCore.PluginFramework.Extensions; using Moonlight.Client.Interfaces; +using MoonlightServers.Frontend.Interfaces; namespace MoonlightServers.Frontend.Startup; @@ -9,6 +11,13 @@ public class PluginStartup : IAppStartup public Task BuildApp(WebAssemblyHostBuilder builder) { builder.Services.AutoAddServices(); + + builder.Services.AddInterfaces(configuration => + { + configuration.AddAssembly(GetType().Assembly); + + configuration.AddInterface(); + }); return Task.CompletedTask; } diff --git a/MoonlightServers.Frontend/Styles/package-lock.json b/MoonlightServers.Frontend/Styles/package-lock.json index 6a0b8fb..647363b 100644 --- a/MoonlightServers.Frontend/Styles/package-lock.json +++ b/MoonlightServers.Frontend/Styles/package-lock.json @@ -4,7 +4,6 @@ "requires": true, "packages": { "": { - "name": "Styles", "dependencies": { "@tailwindcss/forms": "^0.5.9" }, diff --git a/MoonlightServers.Frontend/UI/Components/Servers/ServerTabs/FilesTab.razor b/MoonlightServers.Frontend/UI/Components/Servers/ServerTabs/FilesTab.razor new file mode 100644 index 0000000..a41ada5 --- /dev/null +++ b/MoonlightServers.Frontend/UI/Components/Servers/ServerTabs/FilesTab.razor @@ -0,0 +1,6 @@ +@inherits BaseServerTab + +@code +{ + +} diff --git a/MoonlightServers.Frontend/UI/Components/Servers/ServerTabs/SettingsTab.razor b/MoonlightServers.Frontend/UI/Components/Servers/ServerTabs/SettingsTab.razor new file mode 100644 index 0000000..5eb405a --- /dev/null +++ b/MoonlightServers.Frontend/UI/Components/Servers/ServerTabs/SettingsTab.razor @@ -0,0 +1,40 @@ +@using MoonCore.Blazor.Tailwind.Alerts +@using MoonCore.Helpers +@using MoonCore.Blazor.Tailwind.Components +@using MoonlightServers.Shared.Enums + +@inherits BaseServerTab + +@inject HttpApiClient HttpApiClient +@inject AlertService AlertService + +
+
+ @if (State != ServerState.Offline) + { + + } + else + { + + + Reinstall + + } +
+
+ +@code +{ + private async Task Reinstall(WButton _) + { + await AlertService.ConfirmDanger( + "Server installation", + "Do you really want to reinstall the server? This can potentially lead to loss of data", + () => HttpApiClient.Post($"api/servers/{Server.Id}/install") + ); + } +} \ No newline at end of file diff --git a/MoonlightServers.Frontend/UI/Views/User/Manage.razor b/MoonlightServers.Frontend/UI/Views/User/Manage.razor index b3a01f9..aa171fe 100644 --- a/MoonlightServers.Frontend/UI/Views/User/Manage.razor +++ b/MoonlightServers.Frontend/UI/Views/User/Manage.razor @@ -5,11 +5,14 @@ @using MoonCore.Blazor.Tailwind.Components @using MoonCore.Exceptions @using MoonCore.Helpers +@using MoonlightServers.Frontend.Interfaces +@using MoonlightServers.Frontend.Models @using MoonlightServers.Shared.Enums @using MoonlightServers.Frontend.UI.Components @using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs @inject HttpApiClient ApiClient +@inject IServerTabProvider[] TabProviders @implements IAsyncDisposable @@ -75,7 +78,7 @@ Start } - + @if (State == ServerState.Online) { } - + @if (State == ServerState.Starting || State == ServerState.Online || State == ServerState.Stopping) { if (State == ServerState.Stopping) @@ -118,16 +121,26 @@ - -
- - - - - - - +
+ + @foreach (var tab in Tabs) + { + + @{ + var rf = ComponentHelper.FromType(tab.ComponentType, parameters => + { + parameters.Add("Server", Server); + parameters.Add("State", State); + parameters.Add("InitialConsoleMessage", InitialConsoleMessage); + parameters.Add("HubConnection", HubConnection); + parameters.Add("Parent", this); + }); + } + + @rf + + }
} @@ -137,6 +150,8 @@ { [Parameter] public int ServerId { get; set; } + private List Tabs = new(); + private ServerDetailResponse Server; private bool NotFound = false; private ServerState State; @@ -153,6 +168,10 @@ $"api/servers/{ServerId}" ); + // Load server tabs + foreach (var serverTabProvider in TabProviders) + Tabs.AddRange(await serverTabProvider.GetTabs(Server)); + // Load initial status for first render var status = await ApiClient.GetJson( $"api/servers/{ServerId}/status" @@ -217,7 +236,7 @@ private async Task Stop() => await ApiClient.Post($"api/servers/{Server.Id}/stop"); - + private async Task Kill() => await ApiClient.Post($"api/servers/{Server.Id}/kill");