Separating runtime from application code to improve building. Upgraded mooncore packages. Started switching to flyonui. Added PluginFramework plugin loading via mooncore
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<NoDefaultLaunchSettingsFile>True</NoDefaultLaunchSettingsFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Moonlight.ApiServer\Moonlight.ApiServer.csproj" />
|
||||||
|
<ProjectReference Include="..\Moonlight.Client.Runtime\Moonlight.Client.Runtime.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
||||||
|
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.7" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
10
Moonlight.ApiServer.Runtime/PluginLoader.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using MoonCore.PluginFramework;
|
||||||
|
using Moonlight.ApiServer.Plugins;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Runtime;
|
||||||
|
|
||||||
|
[PluginLoader]
|
||||||
|
public partial class PluginLoader : IPluginStartup
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
9
Moonlight.ApiServer.Runtime/Program.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Moonlight.ApiServer;
|
||||||
|
using Moonlight.ApiServer.Runtime;
|
||||||
|
|
||||||
|
var startup = new Startup();
|
||||||
|
|
||||||
|
var pluginLoader = new PluginLoader();
|
||||||
|
pluginLoader.Initialize();
|
||||||
|
|
||||||
|
await startup.Run(args, pluginLoader.Instances);
|
||||||
29
Moonlight.ApiServer.Runtime/Properties/launchSettings.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"applicationUrl": "http://localhost:5165",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
"HTTP_PROXY": "",
|
||||||
|
"HTTPS_PROXY": ""
|
||||||
|
},
|
||||||
|
"hotReloadEnabled": true
|
||||||
|
},
|
||||||
|
"WASM Debug": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"applicationUrl": "http://localhost:5165",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
|
"HTTP_PROXY": "",
|
||||||
|
"HTTPS_PROXY": ""
|
||||||
|
},
|
||||||
|
"hotReloadEnabled": true,
|
||||||
|
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,14 +16,14 @@ namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
|
|||||||
[Authorize(Policy = "permissions:admin.system.files")]
|
[Authorize(Policy = "permissions:admin.system.files")]
|
||||||
public class FilesController : Controller
|
public class FilesController : Controller
|
||||||
{
|
{
|
||||||
private readonly string BaseDirectory = PathBuilder.Dir("storage");
|
private readonly string BaseDirectory = "storage";
|
||||||
private readonly long ChunkSize = ByteConverter.FromMegaBytes(20).Bytes;
|
private readonly long ChunkSize = ByteConverter.FromMegaBytes(20).Bytes;
|
||||||
|
|
||||||
[HttpGet("list")]
|
[HttpGet("list")]
|
||||||
public Task<FileSystemEntryResponse[]> List([FromQuery] string path)
|
public Task<FileSystemEntryResponse[]> List([FromQuery] string path)
|
||||||
{
|
{
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var physicalPath = PathBuilder.Dir(BaseDirectory, safePath);
|
var physicalPath = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
var entries = new List<FileSystemEntryResponse>();
|
var entries = new List<FileSystemEntryResponse>();
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ public class FilesController : Controller
|
|||||||
var positionToSkipTo = ChunkSize * chunkId;
|
var positionToSkipTo = ChunkSize * chunkId;
|
||||||
|
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var physicalPath = PathBuilder.File(BaseDirectory, safePath);
|
var physicalPath = Path.Combine(BaseDirectory, safePath);
|
||||||
var baseDir = Path.GetDirectoryName(physicalPath);
|
var baseDir = Path.GetDirectoryName(physicalPath);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(baseDir))
|
if (!string.IsNullOrEmpty(baseDir))
|
||||||
@@ -113,11 +113,11 @@ public class FilesController : Controller
|
|||||||
var oldSafePath = SanitizePath(oldPath);
|
var oldSafePath = SanitizePath(oldPath);
|
||||||
var newSafePath = SanitizePath(newPath);
|
var newSafePath = SanitizePath(newPath);
|
||||||
|
|
||||||
var oldPhysicalDirPath = PathBuilder.Dir(BaseDirectory, oldSafePath);
|
var oldPhysicalDirPath = Path.Combine(BaseDirectory, oldSafePath);
|
||||||
|
|
||||||
if (Directory.Exists(oldPhysicalDirPath))
|
if (Directory.Exists(oldPhysicalDirPath))
|
||||||
{
|
{
|
||||||
var newPhysicalDirPath = PathBuilder.Dir(BaseDirectory, newSafePath);
|
var newPhysicalDirPath = Path.Combine(BaseDirectory, newSafePath);
|
||||||
|
|
||||||
Directory.Move(
|
Directory.Move(
|
||||||
oldPhysicalDirPath,
|
oldPhysicalDirPath,
|
||||||
@@ -126,8 +126,8 @@ public class FilesController : Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var oldPhysicalFilePath = PathBuilder.File(BaseDirectory, oldSafePath);
|
var oldPhysicalFilePath = Path.Combine(BaseDirectory, oldSafePath);
|
||||||
var newPhysicalFilePath = PathBuilder.File(BaseDirectory, newSafePath);
|
var newPhysicalFilePath = Path.Combine(BaseDirectory, newSafePath);
|
||||||
|
|
||||||
System.IO.File.Move(
|
System.IO.File.Move(
|
||||||
oldPhysicalFilePath,
|
oldPhysicalFilePath,
|
||||||
@@ -142,13 +142,13 @@ public class FilesController : Controller
|
|||||||
public Task Delete([FromQuery] string path)
|
public Task Delete([FromQuery] string path)
|
||||||
{
|
{
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var physicalDirPath = PathBuilder.Dir(BaseDirectory, safePath);
|
var physicalDirPath = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
if (Directory.Exists(physicalDirPath))
|
if (Directory.Exists(physicalDirPath))
|
||||||
Directory.Delete(physicalDirPath, true);
|
Directory.Delete(physicalDirPath, true);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var physicalFilePath = PathBuilder.File(BaseDirectory, safePath);
|
var physicalFilePath = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
System.IO.File.Delete(physicalFilePath);
|
System.IO.File.Delete(physicalFilePath);
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ public class FilesController : Controller
|
|||||||
public Task CreateDirectory([FromQuery] string path)
|
public Task CreateDirectory([FromQuery] string path)
|
||||||
{
|
{
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var physicalPath = PathBuilder.Dir(BaseDirectory, safePath);
|
var physicalPath = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
Directory.CreateDirectory(physicalPath);
|
Directory.CreateDirectory(physicalPath);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
@@ -170,7 +170,7 @@ public class FilesController : Controller
|
|||||||
public async Task Download([FromQuery] string path)
|
public async Task Download([FromQuery] string path)
|
||||||
{
|
{
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var physicalPath = PathBuilder.File(BaseDirectory, safePath);
|
var physicalPath = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
await using var fs = System.IO.File.Open(physicalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
await using var fs = System.IO.File.Open(physicalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
await fs.CopyToAsync(Response.Body);
|
await fs.CopyToAsync(Response.Body);
|
||||||
@@ -192,7 +192,7 @@ public class FilesController : Controller
|
|||||||
private async Task CompressTarGz(string path, string[] itemsToCompress)
|
private async Task CompressTarGz(string path, string[] itemsToCompress)
|
||||||
{
|
{
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var destination = PathBuilder.File(BaseDirectory, safePath);
|
var destination = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
await using var outStream = System.IO.File.Create(destination);
|
await using var outStream = System.IO.File.Create(destination);
|
||||||
await using var gzoStream = new GZipOutputStream(outStream);
|
await using var gzoStream = new GZipOutputStream(outStream);
|
||||||
@@ -201,7 +201,7 @@ public class FilesController : Controller
|
|||||||
foreach (var itemName in itemsToCompress)
|
foreach (var itemName in itemsToCompress)
|
||||||
{
|
{
|
||||||
var safeFilePath = SanitizePath(itemName);
|
var safeFilePath = SanitizePath(itemName);
|
||||||
var filePath = PathBuilder.File(BaseDirectory, safeFilePath);
|
var filePath = Path.Combine(BaseDirectory, safeFilePath);
|
||||||
|
|
||||||
var fi = new FileInfo(filePath);
|
var fi = new FileInfo(filePath);
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ public class FilesController : Controller
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var safeDirePath = SanitizePath(itemName);
|
var safeDirePath = SanitizePath(itemName);
|
||||||
var dirPath = PathBuilder.Dir(BaseDirectory, safeDirePath);
|
var dirPath = Path.Combine(BaseDirectory, safeDirePath);
|
||||||
|
|
||||||
await AddDirectoryToTarGz(tarStream, dirPath);
|
await AddDirectoryToTarGz(tarStream, dirPath);
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ public class FilesController : Controller
|
|||||||
private async Task CompressZip(string path, string[] itemsToCompress)
|
private async Task CompressZip(string path, string[] itemsToCompress)
|
||||||
{
|
{
|
||||||
var safePath = SanitizePath(path);
|
var safePath = SanitizePath(path);
|
||||||
var destination = PathBuilder.File(BaseDirectory, safePath);
|
var destination = Path.Combine(BaseDirectory, safePath);
|
||||||
|
|
||||||
await using var outStream = System.IO.File.Create(destination);
|
await using var outStream = System.IO.File.Create(destination);
|
||||||
await using var zipOutputStream = new ZipOutputStream(outStream);
|
await using var zipOutputStream = new ZipOutputStream(outStream);
|
||||||
@@ -275,7 +275,7 @@ public class FilesController : Controller
|
|||||||
foreach (var itemName in itemsToCompress)
|
foreach (var itemName in itemsToCompress)
|
||||||
{
|
{
|
||||||
var safeFilePath = SanitizePath(itemName);
|
var safeFilePath = SanitizePath(itemName);
|
||||||
var filePath = PathBuilder.File(BaseDirectory, safeFilePath);
|
var filePath = Path.Combine(BaseDirectory, safeFilePath);
|
||||||
|
|
||||||
var fi = new FileInfo(filePath);
|
var fi = new FileInfo(filePath);
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ public class FilesController : Controller
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var safeDirePath = SanitizePath(itemName);
|
var safeDirePath = SanitizePath(itemName);
|
||||||
var dirPath = PathBuilder.Dir(BaseDirectory, safeDirePath);
|
var dirPath = Path.Combine(BaseDirectory, safeDirePath);
|
||||||
|
|
||||||
await AddDirectoryToZip(zipOutputStream, dirPath);
|
await AddDirectoryToZip(zipOutputStream, dirPath);
|
||||||
}
|
}
|
||||||
@@ -350,7 +350,7 @@ public class FilesController : Controller
|
|||||||
var safeDestination = SanitizePath(destination);
|
var safeDestination = SanitizePath(destination);
|
||||||
|
|
||||||
var safeArchivePath = SanitizePath(path);
|
var safeArchivePath = SanitizePath(path);
|
||||||
var archivePath = PathBuilder.File(BaseDirectory, safeArchivePath);
|
var archivePath = Path.Combine(BaseDirectory, safeArchivePath);
|
||||||
|
|
||||||
await using var fs = System.IO.File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
await using var fs = System.IO.File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
await using var gzipInputStream = new GZipInputStream(fs);
|
await using var gzipInputStream = new GZipInputStream(fs);
|
||||||
@@ -364,7 +364,7 @@ public class FilesController : Controller
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
var safeFilePath = SanitizePath(entry.Name);
|
var safeFilePath = SanitizePath(entry.Name);
|
||||||
var fileDestination = PathBuilder.File(BaseDirectory, safeDestination, safeFilePath);
|
var fileDestination = Path.Combine(BaseDirectory, safeDestination, safeFilePath);
|
||||||
var parentFolder = Path.GetDirectoryName(fileDestination);
|
var parentFolder = Path.GetDirectoryName(fileDestination);
|
||||||
|
|
||||||
// Ensure parent directory exists, if it's not the base directory
|
// Ensure parent directory exists, if it's not the base directory
|
||||||
@@ -393,7 +393,7 @@ public class FilesController : Controller
|
|||||||
var safeDestination = SanitizePath(destination);
|
var safeDestination = SanitizePath(destination);
|
||||||
|
|
||||||
var safeArchivePath = SanitizePath(path);
|
var safeArchivePath = SanitizePath(path);
|
||||||
var archivePath = PathBuilder.File(BaseDirectory, safeArchivePath);
|
var archivePath = Path.Combine(BaseDirectory, safeArchivePath);
|
||||||
|
|
||||||
await using var fs = System.IO.File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
await using var fs = System.IO.File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
await using var zipInputStream = new ZipInputStream(fs);
|
await using var zipInputStream = new ZipInputStream(fs);
|
||||||
@@ -409,7 +409,7 @@ public class FilesController : Controller
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var safeFilePath = SanitizePath(entry.Name);
|
var safeFilePath = SanitizePath(entry.Name);
|
||||||
var fileDestination = PathBuilder.File(BaseDirectory, safeDestination, safeFilePath);
|
var fileDestination = Path.Combine(BaseDirectory, safeDestination, safeFilePath);
|
||||||
var parentFolder = Path.GetDirectoryName(fileDestination);
|
var parentFolder = Path.GetDirectoryName(fileDestination);
|
||||||
|
|
||||||
// Ensure parent directory exists, if it's not the base directory
|
// Ensure parent directory exists, if it's not the base directory
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class ThemeController : Controller
|
|||||||
[Authorize(Policy = "permissions:admin.system.theme.update")]
|
[Authorize(Policy = "permissions:admin.system.theme.update")]
|
||||||
public async Task Patch([FromBody] UpdateThemeRequest request)
|
public async Task Patch([FromBody] UpdateThemeRequest request)
|
||||||
{
|
{
|
||||||
var themePath = PathBuilder.File("storage", "theme.json");
|
var themePath = Path.Combine("storage", "theme.json");
|
||||||
|
|
||||||
await System.IO.File.WriteAllTextAsync(
|
await System.IO.File.WriteAllTextAsync(
|
||||||
themePath,
|
themePath,
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using System.Text.Json;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MoonCore.Exceptions;
|
|
||||||
using MoonCore.Helpers;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using Moonlight.Shared.Misc;
|
using Moonlight.Shared.Misc;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Controllers;
|
namespace Moonlight.ApiServer.Http.Controllers.Frontend;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
[Route("/")]
|
||||||
public class FrontendController : Controller
|
public class FrontendController : Controller
|
||||||
{
|
{
|
||||||
private readonly FrontendService FrontendService;
|
private readonly FrontendService FrontendService;
|
||||||
@@ -21,4 +19,12 @@ public class FrontendController : Controller
|
|||||||
[HttpGet("frontend.json")]
|
[HttpGet("frontend.json")]
|
||||||
public async Task<FrontendConfiguration> GetConfiguration()
|
public async Task<FrontendConfiguration> GetConfiguration()
|
||||||
=> await FrontendService.GetConfiguration();
|
=> await FrontendService.GetConfiguration();
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IResult> Index()
|
||||||
|
{
|
||||||
|
var content = await FrontendService.GenerateIndexHtml();
|
||||||
|
|
||||||
|
return Results.Text(content, "text/html", Encoding.UTF8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
@using Moonlight.Shared.Misc
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>@Configuration.Title</title>
|
||||||
|
<base href="/" />
|
||||||
|
|
||||||
|
@foreach (var style in Configuration.Styles)
|
||||||
|
{
|
||||||
|
<link rel="stylesheet" href="@style" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<link href="manifest.webmanifest" rel="manifest" />
|
||||||
|
<link rel="apple-touch-icon" sizes="512x512" href="/img/icon-512.png" />
|
||||||
|
<link rel="apple-touch-icon" sizes="192x192" href="/img/icon-192.png" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="bg-gray-950 text-white font-inter h-full">
|
||||||
|
<div id="app">
|
||||||
|
|
||||||
|
<div class="flex h-screen justify-center items-center">
|
||||||
|
<div class="sm:max-w-lg">
|
||||||
|
<div id="blazor-loader-label" class="text-center mb-2 text-lg font-semibold"></div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<div class="progress min-w-sm md:min-w-md" role="progressbar">
|
||||||
|
<div id="blazor-loader-progress" class="progress-bar"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@foreach (var script in Configuration.Scripts)
|
||||||
|
{
|
||||||
|
<script src="@script"></script>
|
||||||
|
}
|
||||||
|
|
||||||
|
<script src="/_framework/blazor.webassembly.js"></script>
|
||||||
|
<script>navigator.serviceWorker.register('service-worker.js');</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter] public FrontendConfiguration Configuration { get; set; }
|
||||||
|
}
|
||||||
@@ -2,13 +2,11 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.Services;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Models;
|
using Moonlight.ApiServer.Models;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Controllers.Swagger;
|
namespace Moonlight.ApiServer.Http.Controllers.Swagger;
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[Route("api/swagger")]
|
[Route("api/swagger")]
|
||||||
public class SwaggerController : Controller
|
public class SwaggerController : Controller
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Moonlight.ApiServer.Database;
|
|||||||
using Moonlight.ApiServer.Implementations.Diagnose;
|
using Moonlight.ApiServer.Implementations.Diagnose;
|
||||||
using Moonlight.ApiServer.Implementations.Metrics;
|
using Moonlight.ApiServer.Implementations.Metrics;
|
||||||
using Moonlight.ApiServer.Interfaces;
|
using Moonlight.ApiServer.Interfaces;
|
||||||
|
using Moonlight.ApiServer.Models;
|
||||||
using Moonlight.ApiServer.Plugins;
|
using Moonlight.ApiServer.Plugins;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using OpenTelemetry.Metrics;
|
using OpenTelemetry.Metrics;
|
||||||
@@ -11,7 +12,6 @@ using OpenTelemetry.Trace;
|
|||||||
|
|
||||||
namespace Moonlight.ApiServer.Implementations.Startup;
|
namespace Moonlight.ApiServer.Implementations.Startup;
|
||||||
|
|
||||||
[PluginStartup]
|
|
||||||
public class CoreStartup : IPluginStartup
|
public class CoreStartup : IPluginStartup
|
||||||
{
|
{
|
||||||
public Task BuildApplication(IServiceProvider serviceProvider, IHostApplicationBuilder builder)
|
public Task BuildApplication(IServiceProvider serviceProvider, IHostApplicationBuilder builder)
|
||||||
@@ -81,20 +81,37 @@ public class CoreStartup : IPluginStartup
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Client / Frontend
|
||||||
|
|
||||||
|
if (configuration.Client.Enable)
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton(new FrontendConfigurationOption()
|
||||||
|
{
|
||||||
|
Scripts =
|
||||||
|
[
|
||||||
|
"/_content/Moonlight.Client/js/moonlight.js", "/_content/Moonlight.Client/js/moonCore.js",
|
||||||
|
"/_content/Moonlight.Client/ace/ace.js"
|
||||||
|
],
|
||||||
|
Styles = ["/css/style.min.css"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task ConfigureApplication(IServiceProvider serviceProvider, IApplicationBuilder app)
|
public Task ConfigureApplication(IServiceProvider serviceProvider, IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
var configuration = serviceProvider.GetRequiredService<AppConfiguration>();
|
var configuration = serviceProvider.GetRequiredService<AppConfiguration>();
|
||||||
|
|
||||||
#region Prometheus
|
#region Prometheus
|
||||||
|
|
||||||
if(configuration.Metrics.Enable)
|
if (configuration.Metrics.Enable)
|
||||||
app.UseOpenTelemetryPrometheusScrapingEndpoint();
|
app.UseOpenTelemetryPrometheusScrapingEndpoint();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
62
Moonlight.ApiServer/Implementations/UserAuthInvalidation.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using MoonCore.Extended.Abstractions;
|
||||||
|
using MoonCore.Extended.JwtInvalidation;
|
||||||
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Implementations;
|
||||||
|
|
||||||
|
public class UserAuthInvalidation : IJwtInvalidateHandler
|
||||||
|
{
|
||||||
|
private readonly DatabaseRepository<User> UserRepository;
|
||||||
|
private readonly DatabaseRepository<ApiKey> ApiKeyRepository;
|
||||||
|
|
||||||
|
public UserAuthInvalidation(
|
||||||
|
DatabaseRepository<User> userRepository,
|
||||||
|
DatabaseRepository<ApiKey> apiKeyRepository
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UserRepository = userRepository;
|
||||||
|
ApiKeyRepository = apiKeyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Handle(ClaimsPrincipal principal)
|
||||||
|
{
|
||||||
|
var userIdClaim = principal.FindFirstValue("userId");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(userIdClaim))
|
||||||
|
{
|
||||||
|
var userId = int.Parse(userIdClaim);
|
||||||
|
|
||||||
|
var user = await UserRepository
|
||||||
|
.Get()
|
||||||
|
.FirstOrDefaultAsync(x => x.Id == userId);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return true; // User is deleted, invalidate session
|
||||||
|
|
||||||
|
var iatStr = principal.FindFirstValue("iat")!;
|
||||||
|
var iat = DateTimeOffset.FromUnixTimeSeconds(long.Parse(iatStr));
|
||||||
|
|
||||||
|
// If the token has been issued before the token valid time, its expired, and we want to invalidate it
|
||||||
|
return user.TokenValidTimestamp > iat;
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiKeyIdClaim = principal.FindFirstValue("apiKeyId");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(apiKeyIdClaim))
|
||||||
|
{
|
||||||
|
var apiKeyId = int.Parse(apiKeyIdClaim);
|
||||||
|
|
||||||
|
var apiKey = await ApiKeyRepository
|
||||||
|
.Get()
|
||||||
|
.FirstOrDefaultAsync(x => x.Id == apiKeyId);
|
||||||
|
|
||||||
|
// If the api key exists, we don't want to invalidate the request.
|
||||||
|
// If it doesn't exist we want to invalidate the request
|
||||||
|
return apiKey == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Moonlight.Client\Moonlight.Client.csproj" />
|
|
||||||
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj" />
|
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -30,13 +29,14 @@
|
|||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.18" />
|
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||||
<PackageReference Include="Hangfire.Core" Version="1.8.18" />
|
<PackageReference Include="Hangfire.Core" Version="1.8.20" />
|
||||||
<PackageReference Include="Hangfire.EntityFrameworkCore" Version="0.7.0" />
|
<PackageReference Include="Hangfire.EntityFrameworkCore" Version="0.7.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
||||||
<PackageReference Include="MoonCore" Version="1.8.8" />
|
<PackageReference Include="MoonCore" Version="1.9.1" />
|
||||||
<PackageReference Include="MoonCore.Extended" Version="1.3.4" />
|
<PackageReference Include="MoonCore.Extended" Version="1.3.5" />
|
||||||
|
<PackageReference Include="MoonCore.PluginFramework.Generator" Version="1.0.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.12.0-beta.1" />
|
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.12.0-beta.1" />
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Moonlight.ApiServer.Plugins;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class PluginStartupAttribute : Attribute
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ using MoonCore.Attributes;
|
|||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
|
using Moonlight.ApiServer.Http.Controllers.Frontend;
|
||||||
using Moonlight.ApiServer.Models;
|
using Moonlight.ApiServer.Models;
|
||||||
using Moonlight.Shared.Misc;
|
using Moonlight.Shared.Misc;
|
||||||
|
|
||||||
@@ -17,23 +18,26 @@ public class FrontendService
|
|||||||
private readonly AppConfiguration Configuration;
|
private readonly AppConfiguration Configuration;
|
||||||
private readonly IWebHostEnvironment WebHostEnvironment;
|
private readonly IWebHostEnvironment WebHostEnvironment;
|
||||||
private readonly IEnumerable<FrontendConfigurationOption> ConfigurationOptions;
|
private readonly IEnumerable<FrontendConfigurationOption> ConfigurationOptions;
|
||||||
|
private readonly IServiceProvider ServiceProvider;
|
||||||
|
|
||||||
public FrontendService(
|
public FrontendService(
|
||||||
AppConfiguration configuration,
|
AppConfiguration configuration,
|
||||||
IWebHostEnvironment webHostEnvironment,
|
IWebHostEnvironment webHostEnvironment,
|
||||||
IEnumerable<FrontendConfigurationOption> configurationOptions
|
IEnumerable<FrontendConfigurationOption> configurationOptions,
|
||||||
|
IServiceProvider serviceProvider
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
WebHostEnvironment = webHostEnvironment;
|
WebHostEnvironment = webHostEnvironment;
|
||||||
ConfigurationOptions = configurationOptions;
|
ConfigurationOptions = configurationOptions;
|
||||||
|
ServiceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<FrontendConfiguration> GetConfiguration()
|
public async Task<FrontendConfiguration> GetConfiguration()
|
||||||
{
|
{
|
||||||
var configuration = new FrontendConfiguration()
|
var configuration = new FrontendConfiguration()
|
||||||
{
|
{
|
||||||
Title = "Moonlight",
|
Title = "Moonlight", // TODO: CONFIG
|
||||||
ApiUrl = Configuration.PublicUrl,
|
ApiUrl = Configuration.PublicUrl,
|
||||||
HostEnvironment = "ApiServer"
|
HostEnvironment = "ApiServer"
|
||||||
};
|
};
|
||||||
@@ -62,7 +66,20 @@ public class FrontendService
|
|||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Stream> GenerateZip()
|
public async Task<string> GenerateIndexHtml() // TODO: Cache
|
||||||
|
{
|
||||||
|
var configuration = await GetConfiguration();
|
||||||
|
|
||||||
|
return await ComponentHelper.RenderComponent<FrontendPage>(
|
||||||
|
ServiceProvider,
|
||||||
|
parameters =>
|
||||||
|
{
|
||||||
|
parameters["Configuration"] = configuration;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> GenerateZip() // TODO: Rework to be able to extract everything successfully
|
||||||
{
|
{
|
||||||
// We only allow the access to this function when we are actually hosting the frontend
|
// We only allow the access to this function when we are actually hosting the frontend
|
||||||
if (!Configuration.Client.Enable)
|
if (!Configuration.Client.Enable)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using MoonCore.Extended.Helpers;
|
|||||||
using MoonCore.Extended.JwtInvalidation;
|
using MoonCore.Extended.JwtInvalidation;
|
||||||
using MoonCore.Extensions;
|
using MoonCore.Extensions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
using MoonCore.Logging;
|
||||||
using MoonCore.Permissions;
|
using MoonCore.Permissions;
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Database;
|
using Moonlight.ApiServer.Database;
|
||||||
@@ -111,8 +112,7 @@ public class Startup
|
|||||||
private Task CreateStorage()
|
private Task CreateStorage()
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory("storage");
|
Directory.CreateDirectory("storage");
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
Directory.CreateDirectory(Path.Combine("storage", "logs"));
|
||||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins"));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ public class Startup
|
|||||||
private Task UseBase()
|
private Task UseBase()
|
||||||
{
|
{
|
||||||
WebApplication.UseRouting();
|
WebApplication.UseRouting();
|
||||||
WebApplication.UseApiExceptionHandler();
|
WebApplication.UseExceptionHandler();
|
||||||
|
|
||||||
if (Configuration.Client.Enable)
|
if (Configuration.Client.Enable)
|
||||||
{
|
{
|
||||||
@@ -161,7 +161,7 @@ public class Startup
|
|||||||
WebApplication.MapControllers();
|
WebApplication.MapControllers();
|
||||||
|
|
||||||
if (Configuration.Client.Enable)
|
if (Configuration.Client.Enable)
|
||||||
WebApplication.MapFallbackToFile("index.html");
|
WebApplication.MapFallbackToController("Index", "Frontend");
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -194,7 +194,7 @@ public class Startup
|
|||||||
serviceCollection.AddLogging(builder =>
|
serviceCollection.AddLogging(builder =>
|
||||||
{
|
{
|
||||||
builder.ClearProviders();
|
builder.ClearProviders();
|
||||||
builder.AddProviders(LoggerProviders);
|
builder.AddAnsiConsole();
|
||||||
});
|
});
|
||||||
|
|
||||||
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
|
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
|
||||||
@@ -202,8 +202,6 @@ public class Startup
|
|||||||
// Collect startups
|
// Collect startups
|
||||||
var pluginStartups = new List<IPluginStartup>();
|
var pluginStartups = new List<IPluginStartup>();
|
||||||
|
|
||||||
pluginStartups.Add(new CoreStartup());
|
|
||||||
|
|
||||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
||||||
|
|
||||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
||||||
@@ -291,7 +289,7 @@ public class Startup
|
|||||||
var configurationBuilder = new ConfigurationBuilder();
|
var configurationBuilder = new ConfigurationBuilder();
|
||||||
|
|
||||||
// Ensure configuration file exists
|
// Ensure configuration file exists
|
||||||
var jsonFilePath = PathBuilder.File(Directory.GetCurrentDirectory(), "storage", "app.json");
|
var jsonFilePath = Path.Combine(Directory.GetCurrentDirectory(), "storage", "app.json");
|
||||||
|
|
||||||
if (!File.Exists(jsonFilePath))
|
if (!File.Exists(jsonFilePath))
|
||||||
await File.WriteAllTextAsync(jsonFilePath, JsonSerializer.Serialize(new AppConfiguration()));
|
await File.WriteAllTextAsync(jsonFilePath, JsonSerializer.Serialize(new AppConfiguration()));
|
||||||
@@ -336,18 +334,8 @@ public class Startup
|
|||||||
|
|
||||||
private Task SetupLogging()
|
private Task SetupLogging()
|
||||||
{
|
{
|
||||||
LoggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
|
||||||
{
|
|
||||||
configuration.Console.Enable = true;
|
|
||||||
configuration.Console.EnableAnsiMode = true;
|
|
||||||
configuration.FileLogging.Enable = true;
|
|
||||||
configuration.FileLogging.Path = PathBuilder.File("storage", "logs", "latest.log");
|
|
||||||
configuration.FileLogging.EnableLogRotation = true;
|
|
||||||
configuration.FileLogging.RotateLogNameTemplate = PathBuilder.File("storage", "logs", "apiserver.{0}.log");
|
|
||||||
});
|
|
||||||
|
|
||||||
LoggerFactory = new LoggerFactory();
|
LoggerFactory = new LoggerFactory();
|
||||||
LoggerFactory.AddProviders(LoggerProviders);
|
LoggerFactory.AddAnsiConsole();
|
||||||
|
|
||||||
Logger = LoggerFactory.CreateLogger<Startup>();
|
Logger = LoggerFactory.CreateLogger<Startup>();
|
||||||
|
|
||||||
@@ -358,30 +346,33 @@ public class Startup
|
|||||||
{
|
{
|
||||||
// Configure application logging
|
// Configure application logging
|
||||||
WebApplicationBuilder.Logging.ClearProviders();
|
WebApplicationBuilder.Logging.ClearProviders();
|
||||||
WebApplicationBuilder.Logging.AddProviders(LoggerProviders);
|
WebApplicationBuilder.Logging.AddAnsiConsole();
|
||||||
|
WebApplicationBuilder.Logging.AddFile(Path.Combine("storage", "logs", "moonlight.log"));
|
||||||
|
|
||||||
// Logging levels
|
// Logging levels
|
||||||
var logConfigPath = PathBuilder.File("storage", "logConfig.json");
|
var logConfigPath = Path.Combine("storage", "logConfig.json");
|
||||||
|
|
||||||
// Ensure logging config, add a default one is missing
|
// Ensure logging config, add a default one is missing
|
||||||
if (!File.Exists(logConfigPath))
|
if (!File.Exists(logConfigPath))
|
||||||
{
|
{
|
||||||
var logLevels = new Dictionary<string, string>
|
var defaultLogLevels = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "Default", "Information" },
|
{ "Default", "Information" },
|
||||||
{ "Microsoft.AspNetCore", "Warning" },
|
{ "Microsoft.AspNetCore", "Warning" },
|
||||||
{ "System.Net.Http.HttpClient", "Warning" }
|
{ "System.Net.Http.HttpClient", "Warning" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var logLevelsJson = JsonSerializer.Serialize(logLevels);
|
var logLevelsJson = JsonSerializer.Serialize(defaultLogLevels);
|
||||||
var logConfig = "{\"LogLevel\":" + logLevelsJson + "}";
|
await File.WriteAllTextAsync(logConfigPath, logLevelsJson);
|
||||||
await File.WriteAllTextAsync(logConfigPath, logConfig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add logging configuration
|
// Add logging configuration
|
||||||
WebApplicationBuilder.Logging.AddConfiguration(
|
var logLevels = JsonSerializer.Deserialize<Dictionary<string, string>>(
|
||||||
await File.ReadAllTextAsync(logConfigPath)
|
await File.ReadAllTextAsync(logConfigPath)
|
||||||
);
|
)!;
|
||||||
|
|
||||||
|
foreach (var level in logLevels)
|
||||||
|
WebApplicationBuilder.Logging.AddFilter(level.Key, Enum.Parse<LogLevel>(level.Value));
|
||||||
|
|
||||||
// Mute exception handler middleware
|
// Mute exception handler middleware
|
||||||
// https://github.com/dotnet/aspnetcore/issues/19740
|
// https://github.com/dotnet/aspnetcore/issues/19740
|
||||||
@@ -406,7 +397,6 @@ public class Startup
|
|||||||
WebApplicationBuilder.Services.AddServiceCollectionAccessor();
|
WebApplicationBuilder.Services.AddServiceCollectionAccessor();
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddScoped(typeof(DatabaseRepository<>));
|
WebApplicationBuilder.Services.AddScoped(typeof(DatabaseRepository<>));
|
||||||
WebApplicationBuilder.Services.AddScoped(typeof(CrudHelper<,>));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -442,43 +432,9 @@ public class Startup
|
|||||||
ValidIssuer = Configuration.PublicUrl
|
ValidIssuer = Configuration.PublicUrl
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddJwtInvalidation("coreAuthentication", options =>
|
WebApplicationBuilder.Services.AddJwtBearerInvalidation("coreAuthentication");
|
||||||
{
|
WebApplicationBuilder.Services.AddScoped<IJwtInvalidateHandler, UserAuthInvalidation>();
|
||||||
options.InvalidateTimeProvider = async (provider, principal) =>
|
|
||||||
{
|
|
||||||
var userIdClaim = principal.Claims.FirstOrDefault(x => x.Type == "userId");
|
|
||||||
|
|
||||||
if (userIdClaim != null)
|
|
||||||
{
|
|
||||||
var userId = int.Parse(userIdClaim.Value);
|
|
||||||
|
|
||||||
var userRepository = provider.GetRequiredService<DatabaseRepository<User>>();
|
|
||||||
var user = await userRepository.Get().FirstOrDefaultAsync(x => x.Id == userId);
|
|
||||||
|
|
||||||
if (user == null)
|
|
||||||
return DateTime.MaxValue;
|
|
||||||
|
|
||||||
return user.TokenValidTimestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiKeyIdClaim = principal.Claims.FirstOrDefault(x => x.Type == "apiKeyId");
|
|
||||||
|
|
||||||
if (apiKeyIdClaim != null)
|
|
||||||
{
|
|
||||||
var apiKeyId = int.Parse(apiKeyIdClaim.Value);
|
|
||||||
|
|
||||||
var apiKeyRepository = provider.GetRequiredService<DatabaseRepository<ApiKey>>();
|
|
||||||
var apiKey = await apiKeyRepository.Get().FirstOrDefaultAsync(x => x.Id == apiKeyId);
|
|
||||||
|
|
||||||
// If the api key exists, we don't want to invalidate the request.
|
|
||||||
// If it doesn't exist we want to invalidate the request
|
|
||||||
return apiKey == null ? DateTime.MaxValue : DateTime.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DateTime.MaxValue;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddAuthorization();
|
WebApplicationBuilder.Services.AddAuthorization();
|
||||||
|
|
||||||
@@ -499,8 +455,6 @@ public class Startup
|
|||||||
{
|
{
|
||||||
WebApplication.UseAuthentication();
|
WebApplication.UseAuthentication();
|
||||||
|
|
||||||
WebApplication.UseJwtInvalidation();
|
|
||||||
|
|
||||||
WebApplication.UseAuthorization();
|
WebApplication.UseAuthorization();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|||||||
64
Moonlight.Client.Runtime/Moonlight.Client.Runtime.csproj
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<NoDefaultLaunchSettingsFile>True</NoDefaultLaunchSettingsFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Moonlight.Client\Moonlight.Client.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.7"/>
|
||||||
|
<PackageReference Include="MoonCore.PluginFramework.Generator" Version="1.0.1"/>
|
||||||
|
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5"/>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Styles\exports.css">
|
||||||
|
<Pack>true</Pack>
|
||||||
|
<PackagePath>styles</PackagePath>
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="Styles\package-lock.json">
|
||||||
|
<Pack>true</Pack>
|
||||||
|
<PackagePath>styles</PackagePath>
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="Styles\package.json">
|
||||||
|
<Pack>true</Pack>
|
||||||
|
<PackagePath>styles</PackagePath>
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Styles\preTailwind.css">
|
||||||
|
<Pack>true</Pack>
|
||||||
|
<PackagePath>styles</PackagePath>
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Styles\resolveNuget.js">
|
||||||
|
<Pack>true</Pack>
|
||||||
|
<PackagePath>styles</PackagePath>
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Styles\style.css">
|
||||||
|
<Pack>true</Pack>
|
||||||
|
<PackagePath>styles</PackagePath>
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="wwwroot\css\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ContentIncludedByDefault Remove="wwwroot\js\moonCore.js" />
|
||||||
|
<_ContentIncludedByDefault Remove="wwwroot\js\moonlight.js" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
10
Moonlight.Client.Runtime/PluginLoader.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using MoonCore.PluginFramework;
|
||||||
|
using Moonlight.Client.Plugins;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Runtime;
|
||||||
|
|
||||||
|
[PluginLoader]
|
||||||
|
public partial class PluginLoader : IPluginStartup
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
9
Moonlight.Client.Runtime/Program.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using Moonlight.Client;
|
||||||
|
using Moonlight.Client.Runtime;
|
||||||
|
|
||||||
|
var startup = new Startup();
|
||||||
|
|
||||||
|
var pluginLoader = new PluginLoader();
|
||||||
|
pluginLoader.Initialize();
|
||||||
|
|
||||||
|
await startup.Run(args, pluginLoader.Instances);
|
||||||
14
Moonlight.Client.Runtime/Properties/launchSettings.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": false,
|
||||||
|
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||||
|
"applicationUrl": "http://localhost:5165",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=fallback') layer;
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=fallback') layer(base);
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap') layer;
|
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap') layer(base);
|
||||||
@import url("https://cdn.jsdelivr.net/npm/lucide-static/font/lucide.css") layer;
|
@import url("https://cdn.jsdelivr.net/npm/lucide-static/font/lucide.css") layer(base);
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--font-inter: "Inter", var(--font-sans);
|
--font-inter: "Inter", var(--font-sans);
|
||||||
0
Moonlight.Client/Styles/mappings/mooncore.map → Moonlight.Client.Runtime/Styles/mappings/mooncore.map
Executable file → Normal file
@@ -6,9 +6,9 @@
|
|||||||
"xml2js": "^0.6.2"
|
"xml2js": "^0.6.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pretailwind-build": "node resolveNuget.js ../Moonlight.Client.csproj",
|
"pretailwind-build": "node resolveNuget.js ../Moonlight.Client.Runtime.csproj",
|
||||||
"tailwind-build": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css",
|
"tailwind-build": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css",
|
||||||
"pretailwind": "node resolveNuget.js ../Moonlight.Client.csproj",
|
"pretailwind": "node resolveNuget.js ../Moonlight.Client.Runtime.csproj",
|
||||||
"tailwind": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css --watch"
|
"tailwind": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css --watch"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,4 +13,9 @@
|
|||||||
@source "../**/*.razor";
|
@source "../**/*.razor";
|
||||||
@source "../**/*.cs";
|
@source "../**/*.cs";
|
||||||
@source "../**/*.html";
|
@source "../**/*.html";
|
||||||
|
|
||||||
|
@source "../../Moonlight.Client/**/*.razor";
|
||||||
|
@source "../../Moonlight.Client/**/*.cs";
|
||||||
|
@source "../../Moonlight.Client/**/*.html";
|
||||||
|
|
||||||
@source "./mappings/*.map";
|
@source "./mappings/*.map";
|
||||||
BIN
Moonlight.Client.Runtime/wwwroot/img/icon-192.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
Moonlight.Client.Runtime/wwwroot/img/icon-512.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
Moonlight.Client.Runtime/wwwroot/img/pfp_placeholder.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
6
Moonlight.Client/GlobalUsings.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Global using directives
|
||||||
|
|
||||||
|
global using Microsoft.AspNetCore.Components.Web;
|
||||||
|
global using Microsoft.JSInterop;
|
||||||
|
global using Microsoft.Extensions.Logging;
|
||||||
|
global using MoonCore.Blazor.FlyonUi.Components;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moonlight.Client.Interfaces;
|
using Moonlight.Client.Interfaces;
|
||||||
using Moonlight.Client.Plugins;
|
using Moonlight.Client.Plugins;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using MoonCore.Blazor.Services;
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Blazor.Tailwind.Fm;
|
using MoonCore.Blazor.Tailwind.Fm;
|
||||||
using MoonCore.Blazor.Tailwind.Fm.Models;
|
using MoonCore.Blazor.Tailwind.Fm.Models;
|
||||||
using MoonCore.Blazor.Tailwind.Services;
|
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using Moonlight.Shared.Http.Requests.Admin.Sys.Files;
|
using Moonlight.Shared.Http.Requests.Admin.Sys.Files;
|
||||||
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
@@ -22,11 +22,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Blazor-ApexCharts" Version="6.0.0" />
|
<PackageReference Include="Blazor-ApexCharts" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
<PackageReference Include="MoonCore" Version="1.9.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all" />
|
<PackageReference Include="MoonCore.Blazor" Version="1.3.1" />
|
||||||
<PackageReference Include="MoonCore" Version="1.8.8" />
|
<PackageReference Include="MoonCore.Blazor.FlyonUi" Version="1.0.4" />
|
||||||
<PackageReference Include="MoonCore.Blazor" Version="1.3.0" />
|
|
||||||
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.4.7" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="**\*.cs" Exclude="storage\**\*;bin\**\*;obj\**\*">
|
<None Include="**\*.cs" Exclude="storage\**\*;bin\**\*;obj\**\*">
|
||||||
@@ -56,4 +54,10 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj" />
|
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Styles\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<_ContentIncludedByDefault Remove="wwwroot\css\style.min.css" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Moonlight.Client.Plugins;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class PluginStartupAttribute : Attribute
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Moonlight.Client;
|
|
||||||
|
|
||||||
var startup = new Startup();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await startup.Run(args);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
using System.Web;
|
using System.Web;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
using MoonCore.Blazor.FlyonUi.Auth;
|
||||||
using MoonCore.Blazor.Services;
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Blazor.Tailwind.Auth;
|
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using Moonlight.Shared.Http.Requests.Auth;
|
using Moonlight.Shared.Http.Requests.Auth;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Microsoft.JSInterop;
|
|
||||||
|
|
||||||
namespace Moonlight.Client.Services;
|
namespace Moonlight.Client.Services;
|
||||||
|
|
||||||
public class WindowService
|
public class WindowService
|
||||||
|
|||||||
@@ -1,21 +1,18 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.Blazor.FlyonUi;
|
||||||
|
using MoonCore.Blazor.FlyonUi.Auth;
|
||||||
using MoonCore.Blazor.Services;
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Blazor.Tailwind.Extensions;
|
|
||||||
using MoonCore.Blazor.Tailwind.Auth;
|
|
||||||
using MoonCore.Extensions;
|
using MoonCore.Extensions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
using MoonCore.Logging;
|
||||||
using MoonCore.Permissions;
|
using MoonCore.Permissions;
|
||||||
using Moonlight.Client.Implementations;
|
|
||||||
using Moonlight.Client.Interfaces;
|
|
||||||
using Moonlight.Client.Plugins;
|
using Moonlight.Client.Plugins;
|
||||||
using Moonlight.Client.Services;
|
using Moonlight.Client.Services;
|
||||||
using Moonlight.Shared.Misc;
|
using Moonlight.Shared.Misc;
|
||||||
using Moonlight.Client.UI;
|
using Moonlight.Client.UI;
|
||||||
|
using WindowService = Moonlight.Client.Services.WindowService;
|
||||||
|
|
||||||
namespace Moonlight.Client;
|
namespace Moonlight.Client;
|
||||||
|
|
||||||
@@ -27,7 +24,6 @@ public class Startup
|
|||||||
private FrontendConfiguration Configuration;
|
private FrontendConfiguration Configuration;
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
private ILoggerProvider[] LoggerProviders;
|
|
||||||
private ILoggerFactory LoggerFactory;
|
private ILoggerFactory LoggerFactory;
|
||||||
private ILogger<Startup> Logger;
|
private ILogger<Startup> Logger;
|
||||||
|
|
||||||
@@ -143,12 +139,13 @@ public class Startup
|
|||||||
});
|
});
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<WindowService>();
|
WebAssemblyHostBuilder.Services.AddScoped<WindowService>();
|
||||||
WebAssemblyHostBuilder.Services.AddMoonCoreBlazorTailwind();
|
WebAssemblyHostBuilder.Services.AddFileManagerOperations();
|
||||||
|
WebAssemblyHostBuilder.Services.AddFlyonUiServices();
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<ThemeService>();
|
WebAssemblyHostBuilder.Services.AddScoped<ThemeService>();
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AutoAddServices<Program>();
|
WebAssemblyHostBuilder.Services.AutoAddServices<Startup>();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -179,7 +176,7 @@ public class Startup
|
|||||||
startupSc.AddLogging(builder =>
|
startupSc.AddLogging(builder =>
|
||||||
{
|
{
|
||||||
builder.ClearProviders();
|
builder.ClearProviders();
|
||||||
builder.AddProviders(LoggerProviders);
|
builder.AddAnsiConsole();
|
||||||
});
|
});
|
||||||
|
|
||||||
PluginLoadServiceProvider = startupSc.BuildServiceProvider();
|
PluginLoadServiceProvider = startupSc.BuildServiceProvider();
|
||||||
@@ -187,8 +184,6 @@ public class Startup
|
|||||||
// Collect startups
|
// Collect startups
|
||||||
var pluginStartups = new List<IPluginStartup>();
|
var pluginStartups = new List<IPluginStartup>();
|
||||||
|
|
||||||
pluginStartups.Add(new CoreStartup());
|
|
||||||
|
|
||||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
||||||
|
|
||||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
||||||
@@ -259,15 +254,8 @@ public class Startup
|
|||||||
|
|
||||||
private Task SetupLogging()
|
private Task SetupLogging()
|
||||||
{
|
{
|
||||||
LoggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
|
||||||
{
|
|
||||||
configuration.Console.Enable = true;
|
|
||||||
configuration.Console.EnableAnsiMode = true;
|
|
||||||
configuration.FileLogging.Enable = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
LoggerFactory = new LoggerFactory();
|
LoggerFactory = new LoggerFactory();
|
||||||
LoggerFactory.AddProviders(LoggerProviders);
|
LoggerFactory.AddAnsiConsole();
|
||||||
|
|
||||||
Logger = LoggerFactory.CreateLogger<Startup>();
|
Logger = LoggerFactory.CreateLogger<Startup>();
|
||||||
|
|
||||||
@@ -277,7 +265,7 @@ public class Startup
|
|||||||
private Task RegisterLogging()
|
private Task RegisterLogging()
|
||||||
{
|
{
|
||||||
WebAssemblyHostBuilder.Logging.ClearProviders();
|
WebAssemblyHostBuilder.Logging.ClearProviders();
|
||||||
WebAssemblyHostBuilder.Logging.AddProviders(LoggerProviders);
|
WebAssemblyHostBuilder.Logging.AddAnsiConsole();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<ModalLauncher/>
|
<ModalLauncher/>
|
||||||
|
|
||||||
<div id="blazor-error-ui" class="fixed bottom-0 left-0 w-full z-50">
|
<div id="blazor-error-ui" class="fixed bottom-0 left-0 w-full z-50">
|
||||||
<div class="bg-danger-600 text-white p-4 flex flex-row justify-between items-center">
|
<div class="bg-error text-white p-4 flex flex-row justify-between items-center">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<i class="icon-bomb text-lg text-white me-2"></i>
|
<i class="icon-bomb text-lg text-white me-2"></i>
|
||||||
<span>An unhandled error has occurred.</span>
|
<span>An unhandled error has occurred.</span>
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
@using System.Security.Claims
|
@using System.Security.Claims
|
||||||
@using Microsoft.AspNetCore.Authorization
|
@using Microsoft.AspNetCore.Authorization
|
||||||
@using Microsoft.AspNetCore.Components.Authorization
|
@using Microsoft.AspNetCore.Components.Authorization
|
||||||
@using MoonCore.Blazor.Tailwind.Auth
|
@using MoonCore.Blazor.FlyonUi.Auth
|
||||||
@using Moonlight.Client.Interfaces
|
@using Moonlight.Client.Interfaces
|
||||||
@using Moonlight.Client.Models
|
@using Moonlight.Client.Models
|
||||||
@using Moonlight.Client.UI.Layouts
|
@using Moonlight.Client.UI.Layouts
|
||||||
|
|
||||||
@inject ToastService ToastService
|
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
@inject AuthenticationStateManager AuthStateManager
|
@inject AuthenticationStateManager AuthStateManager
|
||||||
@inject IEnumerable<ISidebarItemProvider> SidebarItemProviders
|
@inject IEnumerable<ISidebarItemProvider> SidebarItemProviders
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
@inject FrontendConfiguration FrontendConfiguration
|
@inject FrontendConfiguration FrontendConfiguration
|
||||||
@inject ThemeService ThemeService
|
@inject ThemeService ThemeService
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject DownloadService DownloadService
|
|
||||||
|
@* @inject DownloadService DownloadService *@
|
||||||
|
|
||||||
<div class="card card-body p-2">
|
<div class="card card-body p-2">
|
||||||
<div class="flex flex-row items-center justify-end gap-x-2">
|
<div class="flex flex-row items-center justify-end gap-x-2">
|
||||||
@@ -108,7 +109,7 @@
|
|||||||
AddSetting("danger", "danger-300", 252, 165, 165);
|
AddSetting("danger", "danger-300", 252, 165, 165);
|
||||||
AddSetting("danger", "danger-400", 248, 113, 113);
|
AddSetting("danger", "danger-400", 248, 113, 113);
|
||||||
AddSetting("danger", "danger", 239, 68, 68);
|
AddSetting("danger", "danger", 239, 68, 68);
|
||||||
AddSetting("danger", "danger-600", 220, 38, 38);
|
AddSetting("danger", "error", 220, 38, 38);
|
||||||
AddSetting("danger", "danger-700", 185, 28, 28);
|
AddSetting("danger", "danger-700", 185, 28, 28);
|
||||||
AddSetting("danger", "danger-800", 153, 27, 27);
|
AddSetting("danger", "danger-800", 153, 27, 27);
|
||||||
AddSetting("danger", "danger-900", 127, 29, 29);
|
AddSetting("danger", "danger-900", 127, 29, 29);
|
||||||
@@ -192,7 +193,7 @@
|
|||||||
{
|
{
|
||||||
if (FrontendConfiguration.HostEnvironment != "ApiServer")
|
if (FrontendConfiguration.HostEnvironment != "ApiServer")
|
||||||
{
|
{
|
||||||
await ToastService.Danger(
|
await ToastService.Error(
|
||||||
"Theme Settings",
|
"Theme Settings",
|
||||||
"Unable to save the theme settings. If you are using a static host, you need to configure the colors in the frontend.json file"
|
"Unable to save the theme settings. If you are using a static host, you need to configure the colors in the frontend.json file"
|
||||||
);
|
);
|
||||||
@@ -215,7 +216,7 @@
|
|||||||
var json = JsonSerializer.Serialize(ThemeService.Variables);
|
var json = JsonSerializer.Serialize(ThemeService.Variables);
|
||||||
|
|
||||||
// Download the theme configuration
|
// Download the theme configuration
|
||||||
await DownloadService.DownloadString("theme.json", json);
|
//await DownloadService.DownloadString("theme.json", json);
|
||||||
|
|
||||||
await ToastService.Success("Successfully exported theme configuration");
|
await ToastService.Success("Successfully exported theme configuration");
|
||||||
}
|
}
|
||||||
@@ -224,7 +225,7 @@
|
|||||||
{
|
{
|
||||||
if (!eventArgs.File.Name.EndsWith(".json"))
|
if (!eventArgs.File.Name.EndsWith(".json"))
|
||||||
{
|
{
|
||||||
await ToastService.Danger("Only .json files are allowed");
|
await ToastService.Error("Only .json files are allowed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
@inject ToastService ToastService
|
@inject ToastService ToastService
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
@inject DownloadService DownloadService
|
|
||||||
|
@* @inject DownloadService DownloadService *@
|
||||||
|
|
||||||
<PageHeader Title="Create API Key">
|
<PageHeader Title="Create API Key">
|
||||||
<a href="/admin/api" class="btn btn-secondary">
|
<a href="/admin/api" class="btn btn-secondary">
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCore.Models
|
@using MoonCore.Models
|
||||||
@using MoonCore.Blazor.Tailwind.Dt
|
|
||||||
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
||||||
|
@using MoonCore.Blazor.FlyonUi.DataTables
|
||||||
|
|
||||||
@inject HttpApiClient ApiClient
|
@inject HttpApiClient ApiClient
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
@using System.Text.Json
|
@using System.Text.Json
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||||
@using MoonCore.Blazor.Tailwind.Input2
|
|
||||||
|
|
||||||
@inject HttpApiClient ApiClient
|
@inject HttpApiClient ApiClient
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using MoonCore.Models
|
@using MoonCore.Models
|
||||||
@using MoonCore.Blazor.Tailwind.Dt
|
|
||||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||||
|
@using MoonCore.Blazor.FlyonUi.DataTables
|
||||||
|
|
||||||
@inject HttpApiClient ApiClient
|
@inject HttpApiClient ApiClient
|
||||||
@inject AlertService AlertService
|
@inject AlertService AlertService
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||||
@using MoonCore.Blazor.Tailwind.Input2
|
|
||||||
|
|
||||||
@inject HttpApiClient ApiClient
|
@inject HttpApiClient ApiClient
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
|||||||
@@ -8,9 +8,7 @@
|
|||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using Moonlight.Client
|
@using Moonlight.Client
|
||||||
|
|
||||||
@using MoonCore.Blazor.Tailwind.Components
|
@using MoonCore.Blazor.FlyonUi.Components
|
||||||
@using MoonCore.Blazor.Tailwind.Alerts
|
@using MoonCore.Blazor.FlyonUi.Modals
|
||||||
@using MoonCore.Blazor.Tailwind.Helpers
|
@using MoonCore.Blazor.FlyonUi.Toasts
|
||||||
@using MoonCore.Blazor.Tailwind.Modals
|
@using MoonCore.Blazor.FlyonUi.Alerts
|
||||||
@using MoonCore.Blazor.Tailwind.Services
|
|
||||||
@using MoonCore.Blazor.Tailwind.Toasts
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Moonlight.Client</title>
|
|
||||||
<base href="/" />
|
|
||||||
<link rel="stylesheet" href="/css/style.min.css" />
|
|
||||||
<link href="manifest.webmanifest" rel="manifest" />
|
|
||||||
<link rel="apple-touch-icon" sizes="512x512" href="/img/icon-512.png" />
|
|
||||||
<link rel="apple-touch-icon" sizes="192x192" href="/img/icon-192.png" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-gray-950 text-white font-inter h-full">
|
|
||||||
<div id="app">
|
|
||||||
|
|
||||||
<div class="flex h-screen justify-center items-center">
|
|
||||||
<div class="sm:max-w-lg">
|
|
||||||
<div id="blazor-loader-label" class="text-center mb-2 text-lg font-semibold"></div>
|
|
||||||
<div class="flex flex-col gap-1">
|
|
||||||
<div class="progress min-w-sm md:min-w-md" role="progressbar">
|
|
||||||
<div id="blazor-loader-progress" class="progress-bar"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/js/moonlight.js"></script>
|
|
||||||
<script src="/js/moonCore.js"></script>
|
|
||||||
<script src="/ace/ace.js"></script>
|
|
||||||
<script src="/_framework/blazor.webassembly.js"></script>
|
|
||||||
<script>navigator.serviceWorker.register('service-worker.js');</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -6,6 +6,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Client", "Moonlig
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Shared", "Moonlight.Shared\Moonlight.Shared.csproj", "{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Shared", "Moonlight.Shared\Moonlight.Shared.csproj", "{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.ApiServer.Runtime", "Moonlight.ApiServer.Runtime\Moonlight.ApiServer.Runtime.csproj", "{97FC686D-BC8A-4145-90C7-CA86B598441E}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Client.Runtime", "Moonlight.Client.Runtime\Moonlight.Client.Runtime.csproj", "{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -24,6 +28,14 @@ Global
|
|||||||
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
|||||||