Add dynamic background images for servers
This commit is contained in:
@@ -20,4 +20,5 @@ public class Image
|
|||||||
public List<DockerImage> DockerImages { get; set; } = new();
|
public List<DockerImage> DockerImages { get; set; } = new();
|
||||||
public List<ImageVariable> Variables { get; set; } = new();
|
public List<ImageVariable> Variables { get; set; } = new();
|
||||||
public string TagsJson { get; set; } = "";
|
public string TagsJson { get; set; } = "";
|
||||||
|
public string BackgroundImageUrl { get; set; } = "";
|
||||||
}
|
}
|
||||||
1056
Moonlight/App/Database/Migrations/20230609202138_AddBackgroundImageUrlImage.Designer.cs
generated
Normal file
1056
Moonlight/App/Database/Migrations/20230609202138_AddBackgroundImageUrlImage.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddBackgroundImageUrlImage : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "BackgroundImageUrl",
|
||||||
|
table: "Images",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BackgroundImageUrl",
|
||||||
|
table: "Images");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -132,6 +132,10 @@ namespace Moonlight.App.Database.Migrations
|
|||||||
b.Property<int>("Allocations")
|
b.Property<int>("Allocations")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("BackgroundImageUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("ConfigFiles")
|
b.Property<string>("ConfigFiles")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|||||||
@@ -47,6 +47,29 @@ public class ResourcesController : Controller
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("background/{name}")]
|
||||||
|
public async Task<ActionResult> GetBackground([FromRoute] string name)
|
||||||
|
{
|
||||||
|
if (name.Contains(".."))
|
||||||
|
{
|
||||||
|
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
|
||||||
|
{
|
||||||
|
x.Add<string>(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(PathBuilder.File("storage", "resources", "public", "background", name)))
|
||||||
|
{
|
||||||
|
var fs = new FileStream(PathBuilder.File("storage", "resources", "public", "background", name), FileMode.Open);
|
||||||
|
|
||||||
|
return File(fs, MimeTypes.GetMimeType(name), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("bucket/{bucket}/{name}")]
|
[HttpGet("bucket/{bucket}/{name}")]
|
||||||
public async Task<ActionResult> GetBucket([FromRoute] string bucket, [FromRoute] string name)
|
public async Task<ActionResult> GetBucket([FromRoute] string bucket, [FromRoute] string name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ public class ResourceService
|
|||||||
return $"{AppUrl}/api/moonlight/resources/images/{name}";
|
return $"{AppUrl}/api/moonlight/resources/images/{name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string BackgroundImage(string name)
|
||||||
|
{
|
||||||
|
return $"{AppUrl}/api/moonlight/resources/background/{name}";
|
||||||
|
}
|
||||||
|
|
||||||
public string Avatar(User user)
|
public string Avatar(User user)
|
||||||
{
|
{
|
||||||
return $"{AppUrl}/api/moonlight/avatar/{user.Id}";
|
return $"{AppUrl}/api/moonlight/avatar/{user.Id}";
|
||||||
|
|||||||
33
Moonlight/App/Services/Sessions/DynamicBackgroundService.cs
Normal file
33
Moonlight/App/Services/Sessions/DynamicBackgroundService.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Logging.Net;
|
||||||
|
using Moonlight.App.Services.Files;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services.Sessions;
|
||||||
|
|
||||||
|
public class DynamicBackgroundService
|
||||||
|
{
|
||||||
|
public EventHandler OnBackgroundImageChanged { get; set; }
|
||||||
|
public string BackgroundImageUrl { get; private set; }
|
||||||
|
private string DefaultBackgroundImageUrl;
|
||||||
|
|
||||||
|
public DynamicBackgroundService(ResourceService resourceService)
|
||||||
|
{
|
||||||
|
DefaultBackgroundImageUrl = resourceService.BackgroundImage("main.jpg");
|
||||||
|
BackgroundImageUrl = DefaultBackgroundImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Change(string url)
|
||||||
|
{
|
||||||
|
BackgroundImageUrl = url;
|
||||||
|
OnBackgroundImageChanged?.Invoke(this, null!);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Reset()
|
||||||
|
{
|
||||||
|
BackgroundImageUrl = DefaultBackgroundImageUrl;
|
||||||
|
OnBackgroundImageChanged?.Invoke(this, null!);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,6 +74,7 @@
|
|||||||
<Folder Include="App\ApiClients\CloudPanel\Resources\" />
|
<Folder Include="App\ApiClients\CloudPanel\Resources\" />
|
||||||
<Folder Include="App\Http\Middleware" />
|
<Folder Include="App\Http\Middleware" />
|
||||||
<Folder Include="storage\backups\" />
|
<Folder Include="storage\backups\" />
|
||||||
|
<Folder Include="storage\resources\public\background\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ namespace Moonlight
|
|||||||
builder.Services.AddScoped<ReCaptchaService>();
|
builder.Services.AddScoped<ReCaptchaService>();
|
||||||
builder.Services.AddScoped<IpBanService>();
|
builder.Services.AddScoped<IpBanService>();
|
||||||
builder.Services.AddSingleton<OAuth2Service>();
|
builder.Services.AddSingleton<OAuth2Service>();
|
||||||
|
builder.Services.AddScoped<DynamicBackgroundService>();
|
||||||
|
|
||||||
builder.Services.AddScoped<SubscriptionService>();
|
builder.Services.AddScoped<SubscriptionService>();
|
||||||
builder.Services.AddScoped<SubscriptionAdminService>();
|
builder.Services.AddScoped<SubscriptionAdminService>();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject SmartTranslateService SmartTranslateService
|
@inject SmartTranslateService SmartTranslateService
|
||||||
@inject IpBanService IpBanService
|
@inject IpBanService IpBanService
|
||||||
|
@inject DynamicBackgroundService DynamicBackgroundService
|
||||||
|
|
||||||
<GlobalErrorBoundary>
|
<GlobalErrorBoundary>
|
||||||
@{
|
@{
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
<Sidebar></Sidebar>
|
<Sidebar></Sidebar>
|
||||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||||
<div class="d-flex flex-column flex-column-fluid">
|
<div class="d-flex flex-column flex-column-fluid">
|
||||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
<div id="kt_app_content" class="app-content flex-column-fluid" style="background-position: center; background-size: cover; background-repeat: no-repeat; background-attachment: fixed; background-image: url('@(DynamicBackgroundService.BackgroundImageUrl)')">
|
||||||
<div id="kt_app_content_container" class="app-container container-fluid">
|
<div id="kt_app_content_container" class="app-container container-fluid">
|
||||||
<div class="mt-10">
|
<div class="mt-10">
|
||||||
<SoftErrorBoundary>
|
<SoftErrorBoundary>
|
||||||
@@ -189,6 +190,11 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
DynamicBackgroundService.OnBackgroundImageChanged += async (_, _) =>
|
||||||
|
{
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
};
|
||||||
|
|
||||||
IsIpBanned = await IpBanService.IsBanned();
|
IsIpBanned = await IpBanService.IsBanned();
|
||||||
|
|
||||||
if(IsIpBanned)
|
if(IsIpBanned)
|
||||||
@@ -211,7 +217,13 @@
|
|||||||
|
|
||||||
await SessionService.Register();
|
await SessionService.Register();
|
||||||
|
|
||||||
NavigationManager.LocationChanged += (sender, args) => { SessionService.Refresh(); };
|
NavigationManager.LocationChanged += async (_, _) =>
|
||||||
|
{
|
||||||
|
SessionService.Refresh();
|
||||||
|
|
||||||
|
if (!NavigationManager.Uri.Contains("/server/"))
|
||||||
|
await DynamicBackgroundService.Reset();
|
||||||
|
};
|
||||||
|
|
||||||
if (User != null)
|
if (User != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,16 +13,16 @@
|
|||||||
@inject FileDownloadService FileDownloadService
|
@inject FileDownloadService FileDownloadService
|
||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<LazyLoader @ref="LazyLoader" Load="Load">
|
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||||
@if (Image == null)
|
@if (Image == null)
|
||||||
{
|
{
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<TL>No image with this id found</TL>
|
<TL>No image with this id found</TL>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||||
<div class="card card-body">
|
<div class="card card-body">
|
||||||
@@ -38,6 +38,16 @@
|
|||||||
</label>
|
</label>
|
||||||
<textarea @bind="Image.Description" type="text" class="form-control"></textarea>
|
<textarea @bind="Image.Description" type="text" class="form-control"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-10">
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Background image url</TL>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
@bind="Image.BackgroundImageUrl"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="@(SmartTranslateService.Translate("Leave empty for the default background image"))">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||||
@@ -244,9 +254,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
|
|||||||
@@ -125,8 +125,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--d-flex flex-row mb-5-->
|
<div class="row">
|
||||||
<div class="card mb-5">
|
<div class="col">
|
||||||
|
<div class="card mb-5">
|
||||||
<div class="card-header card-header-stretch">
|
<div class="card-header card-header-stretch">
|
||||||
<div class="card-title d-flex align-items-center">
|
<div class="card-title d-flex align-items-center">
|
||||||
<h3 class="fw-bold m-0 text-gray-800">
|
<h3 class="fw-bold m-0 text-gray-800">
|
||||||
@@ -173,15 +174,16 @@
|
|||||||
<TL>Create a domain</TL>
|
<TL>Create a domain</TL>
|
||||||
</a>
|
</a>
|
||||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||||
<TL>Make your servvices accessible throught your own domain</TL>
|
<TL>Make your services accessible through your own domain</TL>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="card mb-5">
|
<div class="col">
|
||||||
|
<div class="card mb-5">
|
||||||
<div class="card-header card-header-stretch">
|
<div class="card-header card-header-stretch">
|
||||||
<div class="card-title d-flex align-items-center">
|
<div class="card-title d-flex align-items-center">
|
||||||
<h3 class="fw-bold m-0 text-gray-800">
|
<h3 class="fw-bold m-0 text-gray-800">
|
||||||
@@ -234,6 +236,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
@using Moonlight.App.Helpers.Wings.Enums
|
@using Moonlight.App.Helpers.Wings.Enums
|
||||||
@using Moonlight.App.Repositories
|
@using Moonlight.App.Repositories
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.Sessions
|
||||||
@using Moonlight.Shared.Components.Xterm
|
@using Moonlight.Shared.Components.Xterm
|
||||||
@using Moonlight.Shared.Components.ServerControl
|
@using Moonlight.Shared.Components.ServerControl
|
||||||
@using Newtonsoft.Json
|
@using Newtonsoft.Json
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
@inject EventSystem Event
|
@inject EventSystem Event
|
||||||
@inject ServerService ServerService
|
@inject ServerService ServerService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject DynamicBackgroundService DynamicBackgroundService
|
||||||
|
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
@@ -291,6 +293,11 @@
|
|||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Image.BackgroundImageUrl))
|
||||||
|
await DynamicBackgroundService.Reset();
|
||||||
|
else
|
||||||
|
await DynamicBackgroundService.Change(Image.BackgroundImageUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user