Merge pull request #156 from Moonlight-Panel/AddServerBackgroundImage
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<ImageVariable> Variables { get; set; } = new();
|
||||
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")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("BackgroundImageUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ConfigFiles")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
@@ -47,6 +47,29 @@ public class ResourcesController : Controller
|
||||
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}")]
|
||||
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}";
|
||||
}
|
||||
|
||||
public string BackgroundImage(string name)
|
||||
{
|
||||
return $"{AppUrl}/api/moonlight/resources/background/{name}";
|
||||
}
|
||||
|
||||
public string Avatar(User user)
|
||||
{
|
||||
return $"{AppUrl}/api/moonlight/avatar/{user.Id}";
|
||||
|
||||
39
Moonlight/App/Services/Sessions/DynamicBackgroundService.cs
Normal file
39
Moonlight/App/Services/Sessions/DynamicBackgroundService.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
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)
|
||||
{
|
||||
if(BackgroundImageUrl == url) // Prevent unnecessary updates
|
||||
return Task.CompletedTask;
|
||||
|
||||
BackgroundImageUrl = url;
|
||||
OnBackgroundImageChanged?.Invoke(this, null!);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Reset()
|
||||
{
|
||||
if(BackgroundImageUrl == DefaultBackgroundImageUrl) // Prevent unnecessary updates
|
||||
return Task.CompletedTask;
|
||||
|
||||
BackgroundImageUrl = DefaultBackgroundImageUrl;
|
||||
OnBackgroundImageChanged?.Invoke(this, null!);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@
|
||||
<Folder Include="App\ApiClients\CloudPanel\Resources\" />
|
||||
<Folder Include="App\Http\Middleware" />
|
||||
<Folder Include="storage\backups\" />
|
||||
<Folder Include="storage\resources\public\background\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -134,6 +134,7 @@ namespace Moonlight
|
||||
builder.Services.AddScoped<ReCaptchaService>();
|
||||
builder.Services.AddScoped<IpBanService>();
|
||||
builder.Services.AddSingleton<OAuth2Service>();
|
||||
builder.Services.AddScoped<DynamicBackgroundService>();
|
||||
|
||||
builder.Services.AddScoped<SubscriptionService>();
|
||||
builder.Services.AddScoped<SubscriptionAdminService>();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
@inject ToastService ToastService
|
||||
@inject SmartTranslateService SmartTranslateService
|
||||
@inject IpBanService IpBanService
|
||||
@inject DynamicBackgroundService DynamicBackgroundService
|
||||
|
||||
<GlobalErrorBoundary>
|
||||
@{
|
||||
@@ -56,7 +57,7 @@
|
||||
<Sidebar></Sidebar>
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
<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 class="mt-10">
|
||||
<SoftErrorBoundary>
|
||||
@@ -189,6 +190,11 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
DynamicBackgroundService.OnBackgroundImageChanged += async (_, _) =>
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
};
|
||||
|
||||
IsIpBanned = await IpBanService.IsBanned();
|
||||
|
||||
if(IsIpBanned)
|
||||
@@ -211,7 +217,13 @@
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,16 @@
|
||||
</label>
|
||||
<textarea @bind="Image.Description" type="text" class="form-control"></textarea>
|
||||
</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 class="col-xl-6 mb-5 mb-xl-10">
|
||||
|
||||
@@ -125,7 +125,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--d-flex flex-row mb-5-->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card mb-5">
|
||||
<div class="card-header card-header-stretch">
|
||||
<div class="card-title d-flex align-items-center">
|
||||
@@ -173,14 +174,15 @@
|
||||
<TL>Create a domain</TL>
|
||||
</a>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card mb-5">
|
||||
<div class="card-header card-header-stretch">
|
||||
<div class="card-title d-flex align-items-center">
|
||||
@@ -235,6 +237,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LazyLoader>
|
||||
|
||||
@code
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
@using Moonlight.App.Helpers.Wings.Enums
|
||||
@using Moonlight.App.Repositories
|
||||
@using Moonlight.App.Services
|
||||
@using Moonlight.App.Services.Sessions
|
||||
@using Moonlight.Shared.Components.Xterm
|
||||
@using Moonlight.Shared.Components.ServerControl
|
||||
@using Newtonsoft.Json
|
||||
@@ -20,6 +21,7 @@
|
||||
@inject EventSystem Event
|
||||
@inject ServerService ServerService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject DynamicBackgroundService DynamicBackgroundService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
@@ -291,6 +293,11 @@
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(Image.BackgroundImageUrl))
|
||||
await DynamicBackgroundService.Reset();
|
||||
else
|
||||
await DynamicBackgroundService.Change(Image.BackgroundImageUrl);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
BIN
Moonlight/defaultstorage/resources/public/background/main.jpg
Normal file
BIN
Moonlight/defaultstorage/resources/public/background/main.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Reference in New Issue
Block a user