diff --git a/Hosts/Moonlight.Api.Host/Moonlight.Api.Host.csproj b/Hosts/Moonlight.Api.Host/Moonlight.Api.Host.csproj index 51cc3168..50e051ed 100644 --- a/Hosts/Moonlight.Api.Host/Moonlight.Api.Host.csproj +++ b/Hosts/Moonlight.Api.Host/Moonlight.Api.Host.csproj @@ -7,18 +7,18 @@ - + all runtime; build; native; analyzers; buildtransitive - - + + - + diff --git a/Hosts/Moonlight.Frontend.Host/Moonlight.Frontend.Host.csproj b/Hosts/Moonlight.Frontend.Host/Moonlight.Frontend.Host.csproj index c8751280..92e3ba2a 100644 --- a/Hosts/Moonlight.Frontend.Host/Moonlight.Frontend.Host.csproj +++ b/Hosts/Moonlight.Frontend.Host/Moonlight.Frontend.Host.csproj @@ -12,14 +12,16 @@ - - - - + + + + + + - + diff --git a/Hosts/Moonlight.Frontend.Host/Styles/extract-classes.mjs b/Hosts/Moonlight.Frontend.Host/Styles/extract-classes.mjs index 8fba7344..236c95d8 100644 --- a/Hosts/Moonlight.Frontend.Host/Styles/extract-classes.mjs +++ b/Hosts/Moonlight.Frontend.Host/Styles/extract-classes.mjs @@ -15,7 +15,7 @@ export default function extractTailwindClasses(opts = {}) { }, OnceExit() { const classArray = Array.from(classSet).sort(); - fs.mkdirSync('../../../Moonlight.Frontend/Styles', { recursive: true }); + fs.mkdirSync('../../../Moonlight.Frontend/Styles', {recursive: true}); fs.writeFileSync('../../../Moonlight.Frontend/Styles/Moonlight.Frontend.map', classArray.join('\n')); console.log(`Extracted classes ${classArray.length}`); } diff --git a/Hosts/Moonlight.Frontend.Host/Styles/styles.css b/Hosts/Moonlight.Frontend.Host/Styles/styles.css index 98cc703e..802a0928 100644 --- a/Hosts/Moonlight.Frontend.Host/Styles/styles.css +++ b/Hosts/Moonlight.Frontend.Host/Styles/styles.css @@ -25,6 +25,7 @@ * { @apply border-border outline-ring/50; } + body { @apply bg-background text-foreground; } diff --git a/Hosts/Moonlight.Frontend.Host/wwwroot/index.html b/Hosts/Moonlight.Frontend.Host/wwwroot/index.html index 053a3377..a64b4e45 100644 --- a/Hosts/Moonlight.Frontend.Host/wwwroot/index.html +++ b/Hosts/Moonlight.Frontend.Host/wwwroot/index.html @@ -1,22 +1,22 @@ - + - - + + Moonlight - - - - + + + + - + - - - +
+ An unhandled error has occurred. + Reload + 🗙 +
+ + + + + diff --git a/Moonlight.Api/Http/Controllers/Admin/SetupController.cs b/Moonlight.Api/Admin/Setup/SetupController.cs similarity index 84% rename from Moonlight.Api/Http/Controllers/Admin/SetupController.cs rename to Moonlight.Api/Admin/Setup/SetupController.cs index b68f350b..e1866d75 100644 --- a/Moonlight.Api/Http/Controllers/Admin/SetupController.cs +++ b/Moonlight.Api/Admin/Setup/SetupController.cs @@ -1,23 +1,22 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Services; +using Moonlight.Api.Admin.Sys.Settings; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests.Seup; +using Moonlight.Shared.Admin.Setup; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Setup; [ApiController] [Route("api/admin/setup")] public class SetupController : Controller { + private const string StateSettingsKey = "Moonlight.Api.Setup.State"; + private readonly DatabaseRepository RolesRepository; private readonly SettingsService SettingsService; private readonly DatabaseRepository UsersRepository; - private readonly DatabaseRepository RolesRepository; - - private const string StateSettingsKey = "Moonlight.Api.Setup.State"; public SetupController( SettingsService settingsService, @@ -51,41 +50,40 @@ public class SetupController : Controller .FirstOrDefaultAsync(x => x.Name == "Administrators"); if (adminRole == null) - { - adminRole = await RolesRepository.AddAsync(new Role() + adminRole = await RolesRepository.AddAsync(new Role { Name = "Administrators", Description = "Automatically generated group for full administrator permissions", - Permissions = [ + Permissions = + [ Permissions.ApiKeys.View, Permissions.ApiKeys.Create, Permissions.ApiKeys.Edit, Permissions.ApiKeys.Delete, - + Permissions.Roles.View, Permissions.Roles.Create, Permissions.Roles.Edit, Permissions.Roles.Delete, Permissions.Roles.Members, - + Permissions.Users.View, Permissions.Users.Create, Permissions.Users.Edit, Permissions.Users.Delete, Permissions.Users.Logout, - + Permissions.Themes.View, Permissions.Themes.Create, Permissions.Themes.Edit, Permissions.Themes.Delete, - + Permissions.System.Info, Permissions.System.Diagnose, Permissions.System.Versions, - Permissions.System.Instance, + Permissions.System.Instance ] }); - } var user = await UsersRepository @@ -94,12 +92,13 @@ public class SetupController : Controller if (user == null) { - await UsersRepository.AddAsync(new User() + await UsersRepository.AddAsync(new User { Email = dto.AdminEmail, Username = dto.AdminUsername, - RoleMemberships = [ - new RoleMember() + RoleMemberships = + [ + new RoleMember { Role = adminRole, CreatedAt = DateTimeOffset.UtcNow, @@ -112,16 +111,16 @@ public class SetupController : Controller } else { - user.RoleMemberships.Add(new RoleMember() + user.RoleMemberships.Add(new RoleMember { Role = adminRole, CreatedAt = DateTimeOffset.UtcNow, UpdatedAt = DateTimeOffset.UtcNow }); - + await UsersRepository.UpdateAsync(user); } - + await SettingsService.SetValueAsync(StateSettingsKey, true); return NoContent(); diff --git a/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs b/Moonlight.Api/Admin/Sys/ApiKeys/ApiKeyController.cs similarity index 89% rename from Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs rename to Moonlight.Api/Admin/Sys/ApiKeys/ApiKeyController.cs index 2ff16560..5763b6c5 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs +++ b/Moonlight.Api/Admin/Sys/ApiKeys/ApiKeyController.cs @@ -2,25 +2,22 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Hybrid; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Implementations.ApiKeyScheme; -using Moonlight.Api.Mappers; +using Moonlight.Api.Admin.Sys.ApiKeys.Scheme; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Admin.ApiKeys; -using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Admin.ApiKeys; +using Moonlight.Shared.Admin.Sys.ApiKeys; +using Moonlight.Shared.Shared; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Sys.ApiKeys; [Authorize] [ApiController] [Route("api/admin/apiKeys")] public class ApiKeyController : Controller { - private readonly DatabaseRepository KeyRepository; private readonly HybridCache HybridCache; + private readonly DatabaseRepository KeyRepository; public ApiKeyController(DatabaseRepository keyRepository, HybridCache hybridCache) { @@ -48,9 +45,7 @@ public class ApiKeyController : Controller // Filters if (filterOptions != null) - { foreach (var filterOption in filterOptions.Filters) - { query = filterOption.Key switch { nameof(ApiKey.Name) => @@ -61,8 +56,6 @@ public class ApiKeyController : Controller _ => query }; - } - } // Pagination var data = await query @@ -96,7 +89,7 @@ public class ApiKeyController : Controller public async Task> CreateAsync([FromBody] CreateApiKeyDto request) { var apiKey = ApiKeyMapper.ToEntity(request); - + apiKey.Key = Guid.NewGuid().ToString("N").Substring(0, 32); var finalKey = await KeyRepository.AddAsync(apiKey); @@ -135,9 +128,9 @@ public class ApiKeyController : Controller return Problem("No API key with this id found", statusCode: 404); await KeyRepository.RemoveAsync(apiKey); - + await HybridCache.RemoveAsync(string.Format(ApiKeySchemeHandler.CacheKeyFormat, apiKey.Key)); - + return NoContent(); } } \ No newline at end of file diff --git a/Moonlight.Api/Mappers/ApiKeyMapper.cs b/Moonlight.Api/Admin/Sys/ApiKeys/ApiKeyMapper.cs similarity index 77% rename from Moonlight.Api/Mappers/ApiKeyMapper.cs rename to Moonlight.Api/Admin/Sys/ApiKeys/ApiKeyMapper.cs index 55dd62e1..487d82d3 100644 --- a/Moonlight.Api/Mappers/ApiKeyMapper.cs +++ b/Moonlight.Api/Admin/Sys/ApiKeys/ApiKeyMapper.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.Admin.ApiKeys; -using Moonlight.Shared.Http.Responses.Admin.ApiKeys; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Shared.Admin.Sys.ApiKeys; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Sys.ApiKeys; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Api/Configuration/ApiOptions.cs b/Moonlight.Api/Admin/Sys/ApiKeys/ApiOptions.cs similarity index 81% rename from Moonlight.Api/Configuration/ApiOptions.cs rename to Moonlight.Api/Admin/Sys/ApiKeys/ApiOptions.cs index 87959c7e..bba19781 100644 --- a/Moonlight.Api/Configuration/ApiOptions.cs +++ b/Moonlight.Api/Admin/Sys/ApiKeys/ApiOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Admin.Sys.ApiKeys; public class ApiOptions { diff --git a/Moonlight.Api/Implementations/ApiKeyScheme/ApiKeySchemeHandler.cs b/Moonlight.Api/Admin/Sys/ApiKeys/Scheme/ApiKeySchemeHandler.cs similarity index 91% rename from Moonlight.Api/Implementations/ApiKeyScheme/ApiKeySchemeHandler.cs rename to Moonlight.Api/Admin/Sys/ApiKeys/Scheme/ApiKeySchemeHandler.cs index 4f37e81d..33f4b586 100644 --- a/Moonlight.Api/Implementations/ApiKeyScheme/ApiKeySchemeHandler.cs +++ b/Moonlight.Api/Admin/Sys/ApiKeys/Scheme/ApiKeySchemeHandler.cs @@ -5,19 +5,18 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Hybrid; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -namespace Moonlight.Api.Implementations.ApiKeyScheme; +namespace Moonlight.Api.Admin.Sys.ApiKeys.Scheme; public class ApiKeySchemeHandler : AuthenticationHandler { + public const string CacheKeyFormat = $"Moonlight.Api.{nameof(ApiKeySchemeHandler)}.{{0}}"; private readonly DatabaseRepository ApiKeyRepository; private readonly HybridCache HybridCache; - public const string CacheKeyFormat = $"Moonlight.Api.{nameof(ApiKeySchemeHandler)}.{{0}}"; - public ApiKeySchemeHandler( IOptionsMonitor options, ILoggerFactory logger, @@ -50,9 +49,9 @@ public class ApiKeySchemeHandler : AuthenticationHandler .Query() .Where(x => x.Key == authHeaderValue) .Select(x => new ApiKeySession(x.Permissions, x.ValidUntil)) - .FirstOrDefaultAsync(cancellationToken: ct); + .FirstOrDefaultAsync(ct); }, - new HybridCacheEntryOptions() + new HybridCacheEntryOptions { LocalCacheExpiration = Options.LookupL1CacheTime, Expiration = Options.LookupL2CacheTime diff --git a/Moonlight.Api/Implementations/ApiKeyScheme/ApiKeySchemeOptions.cs b/Moonlight.Api/Admin/Sys/ApiKeys/Scheme/ApiKeySchemeOptions.cs similarity index 79% rename from Moonlight.Api/Implementations/ApiKeyScheme/ApiKeySchemeOptions.cs rename to Moonlight.Api/Admin/Sys/ApiKeys/Scheme/ApiKeySchemeOptions.cs index 0057f976..548bdff9 100644 --- a/Moonlight.Api/Implementations/ApiKeyScheme/ApiKeySchemeOptions.cs +++ b/Moonlight.Api/Admin/Sys/ApiKeys/Scheme/ApiKeySchemeOptions.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Authentication; -namespace Moonlight.Api.Implementations.ApiKeyScheme; +namespace Moonlight.Api.Admin.Sys.ApiKeys.Scheme; public class ApiKeySchemeOptions : AuthenticationSchemeOptions { diff --git a/Moonlight.Api/Services/ApplicationService.cs b/Moonlight.Api/Admin/Sys/ApplicationService.cs similarity index 87% rename from Moonlight.Api/Services/ApplicationService.cs rename to Moonlight.Api/Admin/Sys/ApplicationService.cs index ce99cbdc..cef2606f 100644 --- a/Moonlight.Api/Services/ApplicationService.cs +++ b/Moonlight.Api/Admin/Sys/ApplicationService.cs @@ -1,24 +1,61 @@ using System.Diagnostics; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Moonlight.Api.Helpers; +using VersionService = Moonlight.Api.Admin.Sys.Versions.VersionService; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Sys; public class ApplicationService : IHostedService { - private readonly VersionService VersionService; private readonly ILogger Logger; + private readonly VersionService VersionService; + + public ApplicationService(VersionService versionService, ILogger logger) + { + VersionService = versionService; + Logger = logger; + } public DateTimeOffset StartedAt { get; private set; } public string VersionName { get; private set; } = "N/A"; public bool IsUpToDate { get; set; } = true; public string OperatingSystem { get; private set; } = "N/A"; - public ApplicationService(VersionService versionService, ILogger logger) + public async Task StartAsync(CancellationToken cancellationToken) { - VersionService = versionService; - Logger = logger; + StartedAt = DateTimeOffset.UtcNow; + + OperatingSystem = OsHelper.GetName(); + + try + { + var currentVersion = await VersionService.GetInstanceVersionAsync(); + var latestVersion = await VersionService.GetLatestVersionAsync(); + + VersionName = currentVersion.Identifier; + IsUpToDate = latestVersion == null || currentVersion.Identifier == latestVersion.Identifier; + + Logger.LogInformation("Running Moonlight Panel {version} on {operatingSystem}", VersionName, + OperatingSystem); + + if (!IsUpToDate) + Logger.LogWarning("Your instance is not up-to-date"); + + if (currentVersion.IsDevelopment) + Logger.LogWarning("Your instance is running a development version"); + + if (currentVersion.IsPreRelease) + Logger.LogWarning("Your instance is running a pre-release version"); + } + catch (Exception e) + { + Logger.LogError(e, "An unhandled exception occurred while fetching version details"); + } + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; } public Task GetMemoryUsageAsync() @@ -45,41 +82,8 @@ public class ApplicationService : IHostedService // Calculate CPU usage var cpuUsedMs = (endCpuTime - startCpuTime).TotalMilliseconds; var totalMsPassed = (endTime - startTime).TotalMilliseconds; - var cpuUsagePercent = (cpuUsedMs / (Environment.ProcessorCount * totalMsPassed)) * 100; + var cpuUsagePercent = cpuUsedMs / (Environment.ProcessorCount * totalMsPassed) * 100; return Math.Round(cpuUsagePercent, 2); } - - public async Task StartAsync(CancellationToken cancellationToken) - { - StartedAt = DateTimeOffset.UtcNow; - - OperatingSystem = OsHelper.GetName(); - - try - { - var currentVersion = await VersionService.GetInstanceVersionAsync(); - var latestVersion = await VersionService.GetLatestVersionAsync(); - - VersionName = currentVersion.Identifier; - IsUpToDate = latestVersion == null || currentVersion.Identifier == latestVersion.Identifier; - - Logger.LogInformation("Running Moonlight Panel {version} on {operatingSystem}", VersionName, OperatingSystem); - - if (!IsUpToDate) - Logger.LogWarning("Your instance is not up-to-date"); - - if (currentVersion.IsDevelopment) - Logger.LogWarning("Your instance is running a development version"); - - if (currentVersion.IsPreRelease) - Logger.LogWarning("Your instance is running a pre-release version"); - } - catch (Exception e) - { - Logger.LogError(e, "An unhandled exception occurred while fetching version details"); - } - } - - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } \ No newline at end of file diff --git a/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperController.cs similarity index 83% rename from Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs rename to Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperController.cs index fa61a329..23a7d72c 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperController.cs @@ -2,14 +2,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Api.Mappers; -using Moonlight.Api.Services; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Sys.ContainerHelper; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Sys.ContainerHelper; [ApiController] [Route("api/admin/ch")] @@ -19,7 +15,8 @@ public class ContainerHelperController : Controller private readonly ContainerHelperService ContainerHelperService; private readonly IOptions Options; - public ContainerHelperController(ContainerHelperService containerHelperService, IOptions options) + public ContainerHelperController(ContainerHelperService containerHelperService, + IOptions options) { ContainerHelperService = containerHelperService; Options = options; diff --git a/Moonlight.Api/Mappers/ContainerHelperMapper.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperMapper.cs similarity index 60% rename from Moonlight.Api/Mappers/ContainerHelperMapper.cs rename to Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperMapper.cs index 26cc39b4..b293871f 100644 --- a/Moonlight.Api/Mappers/ContainerHelperMapper.cs +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperMapper.cs @@ -1,13 +1,13 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Events; +using Moonlight.Shared.Admin.Sys.ContainerHelper; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Sys.ContainerHelper; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] [SuppressMessage("Mapper", "RMG012:No members are mapped in an object mapping")] public static partial class ContainerHelperMapper { - public static partial RebuildEventDto ToDto(Http.Services.ContainerHelper.Events.RebuildEventDto rebuildEventDto); + public static partial RebuildEventDto ToDto(Models.Events.RebuildEventDto rebuildEventDto); } \ No newline at end of file diff --git a/Moonlight.Api/Configuration/ContainerHelperOptions.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperOptions.cs similarity index 72% rename from Moonlight.Api/Configuration/ContainerHelperOptions.cs rename to Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperOptions.cs index 42f89bd7..f2685952 100644 --- a/Moonlight.Api/Configuration/ContainerHelperOptions.cs +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Admin.Sys.ContainerHelper; public class ContainerHelperOptions { diff --git a/Moonlight.Api/Services/ContainerHelperService.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperService.cs similarity index 86% rename from Moonlight.Api/Services/ContainerHelperService.cs rename to Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperService.cs index 2ce921a7..1c04a077 100644 --- a/Moonlight.Api/Services/ContainerHelperService.cs +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/ContainerHelperService.cs @@ -1,10 +1,10 @@ using System.Net.Http.Json; using System.Text.Json; -using Moonlight.Api.Http.Services.ContainerHelper; -using Moonlight.Api.Http.Services.ContainerHelper.Requests; -using Moonlight.Api.Http.Services.ContainerHelper.Events; +using Moonlight.Api.Admin.Sys.ContainerHelper.Models; +using Moonlight.Api.Admin.Sys.ContainerHelper.Models.Events; +using Moonlight.Api.Admin.Sys.ContainerHelper.Models.Requests; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Sys.ContainerHelper; public class ContainerHelperService { @@ -53,7 +53,7 @@ public class ContainerHelperService { var responseText = await response.Content.ReadAsStringAsync(); - yield return new RebuildEventDto() + yield return new RebuildEventDto { Type = RebuildEventType.Failed, Data = responseText @@ -76,7 +76,8 @@ public class ContainerHelperService continue; var data = line.Trim("data: "); - var deserializedData = JsonSerializer.Deserialize(data, SerializationContext.Default.Options); + var deserializedData = + JsonSerializer.Deserialize(data, SerializationContext.Default.Options); yield return deserializedData; @@ -85,7 +86,7 @@ public class ContainerHelperService yield break; } while (true); - yield return new RebuildEventDto() + yield return new RebuildEventDto { Type = RebuildEventType.Succeeded, Data = string.Empty diff --git a/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Events/RebuildEventDto.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Events/RebuildEventDto.cs new file mode 100644 index 00000000..1d544723 --- /dev/null +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Events/RebuildEventDto.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace Moonlight.Api.Admin.Sys.ContainerHelper.Models.Events; + +public struct RebuildEventDto +{ + [JsonPropertyName("type")] public RebuildEventType Type { get; set; } + + [JsonPropertyName("data")] public string Data { get; set; } +} + +public enum RebuildEventType +{ + Log = 0, + Failed = 1, + Succeeded = 2, + Step = 3 +} \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/ProblemDetails.cs similarity index 80% rename from Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs rename to Moonlight.Api/Admin/Sys/ContainerHelper/Models/ProblemDetails.cs index 925672c6..ea59d88d 100644 --- a/Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/ProblemDetails.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Http.Services.ContainerHelper; +namespace Moonlight.Api.Admin.Sys.ContainerHelper.Models; public class ProblemDetails { diff --git a/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Requests/RequestRebuildDto.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Requests/RequestRebuildDto.cs new file mode 100644 index 00000000..22d0b37f --- /dev/null +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Requests/RequestRebuildDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Api.Admin.Sys.ContainerHelper.Models.Requests; + +public record RequestRebuildDto(bool NoBuildCache); \ No newline at end of file diff --git a/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Requests/SetVersionDto.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Requests/SetVersionDto.cs new file mode 100644 index 00000000..acec1902 --- /dev/null +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/Requests/SetVersionDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Api.Admin.Sys.ContainerHelper.Models.Requests; + +public record SetVersionDto(string Version); \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/SerializationContext.cs similarity index 66% rename from Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs rename to Moonlight.Api/Admin/Sys/ContainerHelper/Models/SerializationContext.cs index d7674b6c..df7c3a71 100644 --- a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs +++ b/Moonlight.Api/Admin/Sys/ContainerHelper/Models/SerializationContext.cs @@ -1,17 +1,15 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Moonlight.Api.Http.Services.ContainerHelper.Events; -using Moonlight.Api.Http.Services.ContainerHelper.Requests; +using Moonlight.Api.Admin.Sys.ContainerHelper.Models.Events; +using Moonlight.Api.Admin.Sys.ContainerHelper.Models.Requests; -namespace Moonlight.Api.Http.Services.ContainerHelper; +namespace Moonlight.Api.Admin.Sys.ContainerHelper.Models; [JsonSerializable(typeof(SetVersionDto))] [JsonSerializable(typeof(ProblemDetails))] [JsonSerializable(typeof(RebuildEventDto))] [JsonSerializable(typeof(RequestRebuildDto))] - [JsonSourceGenerationOptions(JsonSerializerDefaults.Web)] public partial class SerializationContext : JsonSerializerContext { - } \ No newline at end of file diff --git a/Moonlight.Api/Http/Controllers/Admin/DiagnoseController.cs b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseController.cs similarity index 81% rename from Moonlight.Api/Http/Controllers/Admin/DiagnoseController.cs rename to Moonlight.Api/Admin/Sys/Diagnose/DiagnoseController.cs index 598f6368..8a4e4fec 100644 --- a/Moonlight.Api/Http/Controllers/Admin/DiagnoseController.cs +++ b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseController.cs @@ -1,11 +1,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Moonlight.Api.Mappers; -using Moonlight.Api.Services; using Moonlight.Shared; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Sys.Diagnose; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Sys.Diagnose; [ApiController] [Authorize(Policy = Permissions.System.Diagnose)] diff --git a/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseResult.cs b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseResult.cs new file mode 100644 index 00000000..53482fec --- /dev/null +++ b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseResult.cs @@ -0,0 +1,17 @@ +namespace Moonlight.Api.Admin.Sys.Diagnose; + +public record DiagnoseResult( + DiagnoseLevel Level, + string Title, + string[] Tags, + string? Message, + string? StackStrace, + string? SolutionUrl, + string? ReportUrl); + +public enum DiagnoseLevel +{ + Error = 0, + Warning = 1, + Healthy = 2 +} \ No newline at end of file diff --git a/Moonlight.Api/Mappers/DiagnoseResultMapper.cs b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseResultMapper.cs similarity index 79% rename from Moonlight.Api/Mappers/DiagnoseResultMapper.cs rename to Moonlight.Api/Admin/Sys/Diagnose/DiagnoseResultMapper.cs index ffa91e04..9320f825 100644 --- a/Moonlight.Api/Mappers/DiagnoseResultMapper.cs +++ b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseResultMapper.cs @@ -1,9 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Api.Models; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Sys.Diagnose; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Sys.Diagnose; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Api/Services/DiagnoseService.cs b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseService.cs similarity index 88% rename from Moonlight.Api/Services/DiagnoseService.cs rename to Moonlight.Api/Admin/Sys/Diagnose/DiagnoseService.cs index 0cfdf77b..02026fc4 100644 --- a/Moonlight.Api/Services/DiagnoseService.cs +++ b/Moonlight.Api/Admin/Sys/Diagnose/DiagnoseService.cs @@ -1,13 +1,12 @@ using Microsoft.Extensions.Logging; -using Moonlight.Api.Interfaces; -using Moonlight.Api.Models; +using Moonlight.Api.Infrastructure.Hooks; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Sys.Diagnose; public class DiagnoseService { - private readonly IEnumerable Providers; private readonly ILogger Logger; + private readonly IEnumerable Providers; public DiagnoseService(IEnumerable providers, ILogger logger) { @@ -20,7 +19,6 @@ public class DiagnoseService var results = new List(); foreach (var provider in Providers) - { try { results.AddRange( @@ -31,7 +29,6 @@ public class DiagnoseService { Logger.LogError(e, "An unhandled error occured while processing provider"); } - } return results.ToArray(); } diff --git a/Moonlight.Api/Helpers/OsHelper.cs b/Moonlight.Api/Admin/Sys/OsHelper.cs similarity index 84% rename from Moonlight.Api/Helpers/OsHelper.cs rename to Moonlight.Api/Admin/Sys/OsHelper.cs index c53c37bf..c8aed9a2 100644 --- a/Moonlight.Api/Helpers/OsHelper.cs +++ b/Moonlight.Api/Admin/Sys/OsHelper.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace Moonlight.Api.Helpers; +namespace Moonlight.Api.Admin.Sys; public class OsHelper { @@ -53,17 +53,12 @@ public class OsHelper string? version = null; foreach (var line in lines) - { if (line.StartsWith("NAME=")) name = line.Substring(5).Trim('"'); else if (line.StartsWith("VERSION_ID=")) version = line.Substring(11).Trim('"'); - } - if (!string.IsNullOrEmpty(name)) - { - return string.IsNullOrEmpty(version) ? name : $"{name} {version}"; - } + if (!string.IsNullOrEmpty(name)) return string.IsNullOrEmpty(version) ? name : $"{name} {version}"; } //If for some weird reason it still uses lsb release @@ -74,17 +69,12 @@ public class OsHelper string? version = null; foreach (var line in lines) - { if (line.StartsWith("DISTRIB_ID=")) name = line.Substring(11); else if (line.StartsWith("DISTRIB_RELEASE=")) version = line.Substring(16); - } - if (!string.IsNullOrEmpty(name)) - { - return string.IsNullOrEmpty(version) ? name : $"{name} {version}"; - } + if (!string.IsNullOrEmpty(name)) return string.IsNullOrEmpty(version) ? name : $"{name} {version}"; } } catch diff --git a/Moonlight.Api/Configuration/SettingsOptions.cs b/Moonlight.Api/Admin/Sys/Settings/SettingsOptions.cs similarity index 80% rename from Moonlight.Api/Configuration/SettingsOptions.cs rename to Moonlight.Api/Admin/Sys/Settings/SettingsOptions.cs index 758e0374..2538a6d6 100644 --- a/Moonlight.Api/Configuration/SettingsOptions.cs +++ b/Moonlight.Api/Admin/Sys/Settings/SettingsOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Admin.Sys.Settings; public class SettingsOptions { diff --git a/Moonlight.Api/Services/SettingsService.cs b/Moonlight.Api/Admin/Sys/Settings/SettingsService.cs similarity index 86% rename from Moonlight.Api/Services/SettingsService.cs rename to Moonlight.Api/Admin/Sys/Settings/SettingsService.cs index c30cce2b..3e095cba 100644 --- a/Moonlight.Api/Services/SettingsService.cs +++ b/Moonlight.Api/Admin/Sys/Settings/SettingsService.cs @@ -2,25 +2,23 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Hybrid; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Sys.Settings; public class SettingsService { - private readonly DatabaseRepository Repository; - private readonly IOptions Options; - private readonly HybridCache HybridCache; - private const string CacheKey = "Moonlight.Api.SettingsService.{0}"; + private readonly HybridCache HybridCache; + private readonly IOptions Options; + private readonly DatabaseRepository Repository; public SettingsService( DatabaseRepository repository, IOptions options, HybridCache hybridCache - ) + ) { Repository = repository; HybridCache = hybridCache; @@ -39,9 +37,9 @@ public class SettingsService .Query() .Where(x => x.Key == key) .Select(o => o.ValueJson) - .FirstOrDefaultAsync(cancellationToken: ct); + .FirstOrDefaultAsync(ct); }, - new HybridCacheEntryOptions() + new HybridCacheEntryOptions { LocalCacheExpiration = Options.Value.LookupL1CacheTime, Expiration = Options.Value.LookupL2CacheTime @@ -57,13 +55,13 @@ public class SettingsService public async Task SetValueAsync(string key, T value) { var cacheKey = string.Format(CacheKey, key); - + var option = await Repository .Query() .FirstOrDefaultAsync(x => x.Key == key); var json = JsonSerializer.Serialize(value); - + if (option != null) { option.ValueJson = json; @@ -71,12 +69,12 @@ public class SettingsService } else { - option = new SettingsOption() + option = new SettingsOption { Key = key, ValueJson = json }; - + await Repository.AddAsync(option); } diff --git a/Moonlight.Api/Http/Controllers/Admin/Settings/WhiteLabelingController.cs b/Moonlight.Api/Admin/Sys/Settings/WhiteLabelingController.cs similarity index 84% rename from Moonlight.Api/Http/Controllers/Admin/Settings/WhiteLabelingController.cs rename to Moonlight.Api/Admin/Sys/Settings/WhiteLabelingController.cs index 1fee7384..2261e68a 100644 --- a/Moonlight.Api/Http/Controllers/Admin/Settings/WhiteLabelingController.cs +++ b/Moonlight.Api/Admin/Sys/Settings/WhiteLabelingController.cs @@ -1,20 +1,18 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Moonlight.Api.Constants; -using Moonlight.Api.Services; +using Moonlight.Api.Shared.Frontend; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests.Admin.Settings; -using Moonlight.Shared.Http.Responses.Admin.Settings; +using Moonlight.Shared.Admin.Sys.Settings; -namespace Moonlight.Api.Http.Controllers.Admin.Settings; +namespace Moonlight.Api.Admin.Sys.Settings; [ApiController] [Authorize(Policy = Permissions.System.Settings)] [Route("api/admin/system/settings/whiteLabeling")] public class WhiteLabelingController : Controller { - private readonly SettingsService SettingsService; private readonly FrontendService FrontendService; + private readonly SettingsService SettingsService; public WhiteLabelingController(SettingsService settingsService, FrontendService frontendService) { @@ -38,7 +36,7 @@ public class WhiteLabelingController : Controller { await SettingsService.SetValueAsync(FrontendSettingConstants.Name, request.Name); await FrontendService.ResetCacheAsync(); - + var dto = new WhiteLabelingDto { Name = await SettingsService.GetValueAsync(FrontendSettingConstants.Name) ?? "Moonlight" diff --git a/Moonlight.Api/Http/Controllers/Admin/SystemController.cs b/Moonlight.Api/Admin/Sys/SystemController.cs similarity index 88% rename from Moonlight.Api/Http/Controllers/Admin/SystemController.cs rename to Moonlight.Api/Admin/Sys/SystemController.cs index 50d74229..9a24a1d4 100644 --- a/Moonlight.Api/Http/Controllers/Admin/SystemController.cs +++ b/Moonlight.Api/Admin/Sys/SystemController.cs @@ -1,10 +1,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Moonlight.Api.Services; using Moonlight.Shared; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Sys; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Sys; [ApiController] [Route("api/admin/system")] diff --git a/Moonlight.Api/Mappers/ThemeMapper.cs b/Moonlight.Api/Admin/Sys/Themes/ThemeMapper.cs similarity index 77% rename from Moonlight.Api/Mappers/ThemeMapper.cs rename to Moonlight.Api/Admin/Sys/Themes/ThemeMapper.cs index 4496a329..7eb29e1f 100644 --- a/Moonlight.Api/Mappers/ThemeMapper.cs +++ b/Moonlight.Api/Admin/Sys/Themes/ThemeMapper.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.Admin.Themes; -using Moonlight.Shared.Http.Responses.Admin.Themes; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Shared.Admin.Sys.Themes; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Sys.Themes; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Api/Models/ThemeTransferModel.cs b/Moonlight.Api/Admin/Sys/Themes/ThemeTransferModel.cs similarity index 85% rename from Moonlight.Api/Models/ThemeTransferModel.cs rename to Moonlight.Api/Admin/Sys/Themes/ThemeTransferModel.cs index af816550..7fe3d836 100644 --- a/Moonlight.Api/Models/ThemeTransferModel.cs +++ b/Moonlight.Api/Admin/Sys/Themes/ThemeTransferModel.cs @@ -1,6 +1,6 @@ using VYaml.Annotations; -namespace Moonlight.Api.Models; +namespace Moonlight.Api.Admin.Sys.Themes; [YamlObject] public partial class ThemeTransferModel diff --git a/Moonlight.Api/Http/Controllers/Admin/Themes/ThemesController.cs b/Moonlight.Api/Admin/Sys/Themes/ThemesController.cs similarity index 90% rename from Moonlight.Api/Http/Controllers/Admin/Themes/ThemesController.cs rename to Moonlight.Api/Admin/Sys/Themes/ThemesController.cs index ef8bac6a..0a9d4e6c 100644 --- a/Moonlight.Api/Http/Controllers/Admin/Themes/ThemesController.cs +++ b/Moonlight.Api/Admin/Sys/Themes/ThemesController.cs @@ -1,24 +1,21 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Mappers; -using Moonlight.Api.Services; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Api.Shared.Frontend; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Admin.Themes; -using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Admin.Themes; +using Moonlight.Shared.Admin.Sys.Themes; +using Moonlight.Shared.Shared; -namespace Moonlight.Api.Http.Controllers.Admin.Themes; +namespace Moonlight.Api.Admin.Sys.Themes; [ApiController] [Route("api/admin/themes")] public class ThemesController : Controller { - private readonly DatabaseRepository ThemeRepository; private readonly FrontendService FrontendService; + private readonly DatabaseRepository ThemeRepository; public ThemesController(DatabaseRepository themeRepository, FrontendService frontendService) { @@ -48,9 +45,7 @@ public class ThemesController : Controller // Filters if (filterOptions != null) - { foreach (var filterOption in filterOptions.Filters) - { query = filterOption.Key switch { nameof(Theme.Name) => @@ -64,8 +59,6 @@ public class ThemesController : Controller _ => query }; - } - } // Pagination var data = await query @@ -116,7 +109,7 @@ public class ThemesController : Controller if (theme == null) return Problem("No theme with this id found", statusCode: 404); - + ThemeMapper.Merge(theme, request); await ThemeRepository.UpdateAsync(theme); @@ -137,9 +130,9 @@ public class ThemesController : Controller return Problem("No theme with this id found", statusCode: 404); await ThemeRepository.RemoveAsync(theme); - + await FrontendService.ResetCacheAsync(); - + return NoContent(); } } \ No newline at end of file diff --git a/Moonlight.Api/Http/Controllers/Admin/Themes/TransferController.cs b/Moonlight.Api/Admin/Sys/Themes/TransferController.cs similarity index 89% rename from Moonlight.Api/Http/Controllers/Admin/Themes/TransferController.cs rename to Moonlight.Api/Admin/Sys/Themes/TransferController.cs index 448aba94..7566eed4 100644 --- a/Moonlight.Api/Http/Controllers/Admin/Themes/TransferController.cs +++ b/Moonlight.Api/Admin/Sys/Themes/TransferController.cs @@ -1,15 +1,13 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Mappers; -using Moonlight.Api.Models; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -using Moonlight.Shared.Http.Responses.Admin.Themes; +using Moonlight.Shared.Admin.Sys.Themes; using VYaml.Serialization; -namespace Moonlight.Api.Http.Controllers.Admin.Themes; +namespace Moonlight.Api.Admin.Sys.Themes; [ApiController] [Route("api/admin/themes")] @@ -33,7 +31,7 @@ public class TransferController : Controller if (theme == null) return Problem("No theme with that id found", statusCode: 404); - var yml = YamlSerializer.Serialize(new ThemeTransferModel() + var yml = YamlSerializer.Serialize(new ThemeTransferModel { Name = theme.Name, Author = theme.Author, @@ -55,7 +53,7 @@ public class TransferController : Controller if (existingTheme == null) { - var finalTheme = await ThemeRepository.AddAsync(new Theme() + var finalTheme = await ThemeRepository.AddAsync(new Theme { Name = themeToImport.Name, Author = themeToImport.Author, diff --git a/Moonlight.Api/Configuration/FrontendOptions.cs b/Moonlight.Api/Admin/Sys/Versions/FrontendOptions.cs similarity index 74% rename from Moonlight.Api/Configuration/FrontendOptions.cs rename to Moonlight.Api/Admin/Sys/Versions/FrontendOptions.cs index 7f417f0c..353366c3 100644 --- a/Moonlight.Api/Configuration/FrontendOptions.cs +++ b/Moonlight.Api/Admin/Sys/Versions/FrontendOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Admin.Sys.Versions; public class FrontendOptions { diff --git a/Moonlight.Api/Models/MoonlightVersion.cs b/Moonlight.Api/Admin/Sys/Versions/MoonlightVersion.cs similarity index 85% rename from Moonlight.Api/Models/MoonlightVersion.cs rename to Moonlight.Api/Admin/Sys/Versions/MoonlightVersion.cs index 3d76c95f..4c9b9636 100644 --- a/Moonlight.Api/Models/MoonlightVersion.cs +++ b/Moonlight.Api/Admin/Sys/Versions/MoonlightVersion.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Models; +namespace Moonlight.Api.Admin.Sys.Versions; // Notes: // Identifier - This needs to be the branch to clone to build this version if diff --git a/Moonlight.Api/Mappers/VersionMapper.cs b/Moonlight.Api/Admin/Sys/Versions/VersionMapper.cs similarity index 81% rename from Moonlight.Api/Mappers/VersionMapper.cs rename to Moonlight.Api/Admin/Sys/Versions/VersionMapper.cs index 1477b1c3..749f9114 100644 --- a/Moonlight.Api/Mappers/VersionMapper.cs +++ b/Moonlight.Api/Admin/Sys/Versions/VersionMapper.cs @@ -1,9 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Api.Models; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Sys.Versions; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Sys.Versions; [Mapper] [SuppressMessage("Mapper", "RMG020:Source member is not mapped to any target member")] diff --git a/Moonlight.Api/Configuration/VersionOptions.cs b/Moonlight.Api/Admin/Sys/Versions/VersionOptions.cs similarity index 73% rename from Moonlight.Api/Configuration/VersionOptions.cs rename to Moonlight.Api/Admin/Sys/Versions/VersionOptions.cs index 341e2e85..9ba8901c 100644 --- a/Moonlight.Api/Configuration/VersionOptions.cs +++ b/Moonlight.Api/Admin/Sys/Versions/VersionOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Admin.Sys.Versions; public class VersionOptions { diff --git a/Moonlight.Api/Services/VersionService.cs b/Moonlight.Api/Admin/Sys/Versions/VersionService.cs similarity index 93% rename from Moonlight.Api/Services/VersionService.cs rename to Moonlight.Api/Admin/Sys/Versions/VersionService.cs index fd5b6d2e..5f53cfe0 100644 --- a/Moonlight.Api/Services/VersionService.cs +++ b/Moonlight.Api/Admin/Sys/Versions/VersionService.cs @@ -1,22 +1,16 @@ using System.Text.Json.Nodes; using System.Text.RegularExpressions; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Api.Models; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Sys.Versions; public partial class VersionService { - private readonly IOptions Options; - private readonly IHttpClientFactory HttpClientFactory; - private const string VersionPath = "/app/version"; private const string GiteaServer = "https://git.battlestati.one"; private const string GiteaRepository = "Moonlight-Panel/Moonlight"; - - [GeneratedRegex(@"^v(?!1(\.|$))\d+\.[A-Za-z0-9]+(\.[A-Za-z0-9]+)*$")] - private static partial Regex RegexFilter(); + private readonly IHttpClientFactory HttpClientFactory; + private readonly IOptions Options; public VersionService( IOptions options, @@ -27,11 +21,14 @@ public partial class VersionService HttpClientFactory = httpClientFactory; } + [GeneratedRegex(@"^v(?!1(\.|$))\d+\.[A-Za-z0-9]+(\.[A-Za-z0-9]+)*$")] + private static partial Regex RegexFilter(); + public async Task GetVersionsAsync() { if (Options.Value.OfflineMode) return []; - + var versions = new List(); var httpClient = HttpClientFactory.CreateClient(); @@ -42,7 +39,6 @@ public partial class VersionService var tagsJson = await JsonNode.ParseAsync(tagsJsonStream); if (tagsJson != null) - { foreach (var node in tagsJson.AsArray()) { if (node == null) @@ -50,8 +46,8 @@ public partial class VersionService var name = node["name"]?.GetValue() ?? "N/A"; var createdAt = node["createdAt"]?.GetValue() ?? DateTimeOffset.MinValue; - - if(!RegexFilter().IsMatch(name)) + + if (!RegexFilter().IsMatch(name)) continue; versions.Add(new MoonlightVersion( @@ -61,8 +57,7 @@ public partial class VersionService createdAt )); } - } - + // Branches const string branchesPath = $"{GiteaServer}/api/v1/repos/{GiteaRepository}/branches"; @@ -70,7 +65,6 @@ public partial class VersionService var branchesJson = await JsonNode.ParseAsync(branchesJsonStream); if (branchesJson != null) - { foreach (var node in branchesJson.AsArray()) { if (node == null) @@ -83,8 +77,8 @@ public partial class VersionService continue; var createdAt = commit["timestamp"]?.GetValue() ?? DateTimeOffset.MinValue; - - if(!RegexFilter().IsMatch(name)) + + if (!RegexFilter().IsMatch(name)) continue; versions.Add(new MoonlightVersion( @@ -94,7 +88,6 @@ public partial class VersionService createdAt )); } - } return versions.ToArray(); } @@ -106,7 +99,9 @@ public partial class VersionService string versionIdentifier; if (!string.IsNullOrWhiteSpace(Options.Value.CurrentOverride)) + { versionIdentifier = Options.Value.CurrentOverride; + } else { if (File.Exists(VersionPath)) diff --git a/Moonlight.Api/Http/Controllers/Admin/VersionsController.cs b/Moonlight.Api/Admin/Sys/Versions/VersionsController.cs similarity index 85% rename from Moonlight.Api/Http/Controllers/Admin/VersionsController.cs rename to Moonlight.Api/Admin/Sys/Versions/VersionsController.cs index bfa2f488..61bea381 100644 --- a/Moonlight.Api/Http/Controllers/Admin/VersionsController.cs +++ b/Moonlight.Api/Admin/Sys/Versions/VersionsController.cs @@ -1,11 +1,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Moonlight.Api.Mappers; -using Moonlight.Api.Services; using Moonlight.Shared; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Sys.Versions; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Sys.Versions; [ApiController] [Route("api/admin/versions")] @@ -37,8 +35,8 @@ public class VersionsController : Controller public async Task> GetLatestAsync() { var version = await VersionService.GetLatestVersionAsync(); - - if(version == null) + + if (version == null) return Problem("Unable to retrieve latest version", statusCode: 404); return VersionMapper.ToDto(version); diff --git a/Moonlight.Api/Mappers/RoleMapper.cs b/Moonlight.Api/Admin/Users/Roles/RoleMapper.cs similarity index 80% rename from Moonlight.Api/Mappers/RoleMapper.cs rename to Moonlight.Api/Admin/Users/Roles/RoleMapper.cs index b4a4e0ad..88fd1233 100644 --- a/Moonlight.Api/Mappers/RoleMapper.cs +++ b/Moonlight.Api/Admin/Users/Roles/RoleMapper.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.Admin.Roles; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Shared.Admin.Users.Roles; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Users.Roles; [Mapper] [SuppressMessage("Mapper", "RMG020:Source member is not mapped to any target member")] @@ -13,6 +12,7 @@ public static partial class RoleMapper { [MapProperty([nameof(Role.Members), nameof(Role.Members.Count)], nameof(RoleDto.MemberCount))] public static partial RoleDto ToDto(Role role); + public static partial Role ToEntity(CreateRoleDto request); public static partial void Merge([MappingTarget] Role role, UpdateRoleDto request); diff --git a/Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs b/Moonlight.Api/Admin/Users/Roles/RoleMembersController.cs similarity index 89% rename from Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs rename to Moonlight.Api/Admin/Users/Roles/RoleMembersController.cs index ea2619c0..c42ac238 100644 --- a/Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs +++ b/Moonlight.Api/Admin/Users/Roles/RoleMembersController.cs @@ -1,23 +1,23 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Mappers; +using Moonlight.Api.Admin.Users.Users; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Admin.Users; +using Moonlight.Shared.Admin.Users.Users; +using Moonlight.Shared.Shared; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Users.Roles; [ApiController] [Authorize(Policy = Permissions.Roles.Members)] [Route("api/admin/roles/{roleId:int}/members")] public class RoleMembersController : Controller { - private readonly DatabaseRepository UsersRepository; - private readonly DatabaseRepository RolesRepository; private readonly DatabaseRepository RoleMembersRepository; + private readonly DatabaseRepository RolesRepository; + private readonly DatabaseRepository UsersRepository; public RoleMembersController( DatabaseRepository usersRepository, @@ -53,19 +53,16 @@ public class RoleMembersController : Controller // Filtering if (!string.IsNullOrWhiteSpace(searchTerm)) - { query = query.Where(x => EF.Functions.ILike(x.Username, $"%{searchTerm}%") || EF.Functions.ILike(x.Email, $"%{searchTerm}%") ); - } // Pagination - var items = query - .OrderBy(x => x.Id) - .Skip(startIndex) - .Take(length) - .ProjectToDto() + var items = UserMapper.ProjectToDto(query + .OrderBy(x => x.Id) + .Skip(startIndex) + .Take(length)) .ToArray(); var totalCount = await query.CountAsync(); @@ -95,19 +92,16 @@ public class RoleMembersController : Controller // Filtering if (!string.IsNullOrWhiteSpace(searchTerm)) - { query = query.Where(x => EF.Functions.ILike(x.Username, $"%{searchTerm}%") || EF.Functions.ILike(x.Email, $"%{searchTerm}%") ); - } // Pagination - var items = query - .OrderBy(x => x.Id) - .Skip(startIndex) - .Take(length) - .ProjectToDto() + var items = UserMapper.ProjectToDto(query + .OrderBy(x => x.Id) + .Skip(startIndex) + .Take(length)) .ToArray(); var totalCount = await query.CountAsync(); diff --git a/Moonlight.Api/Http/Controllers/Admin/RolesController.cs b/Moonlight.Api/Admin/Users/Roles/RolesController.cs similarity index 89% rename from Moonlight.Api/Http/Controllers/Admin/RolesController.cs rename to Moonlight.Api/Admin/Users/Roles/RolesController.cs index af1bdbff..595b4b9d 100644 --- a/Moonlight.Api/Http/Controllers/Admin/RolesController.cs +++ b/Moonlight.Api/Admin/Users/Roles/RolesController.cs @@ -1,16 +1,13 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Mappers; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Admin.Roles; -using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Users.Roles; +using Moonlight.Shared.Shared; -namespace Moonlight.Api.Http.Controllers.Admin; +namespace Moonlight.Api.Admin.Users.Roles; [ApiController] [Route("api/admin/roles")] @@ -39,15 +36,13 @@ public class RolesController : Controller return Problem("Invalid length specified"); // Query building - + var query = RoleRepository .Query(); // Filters if (filterOptions != null) - { foreach (var filterOption in filterOptions.Filters) - { query = filterOption.Key switch { nameof(Role.Name) => @@ -55,8 +50,6 @@ public class RolesController : Controller _ => query }; - } - } // Pagination var data = await query @@ -106,7 +99,7 @@ public class RolesController : Controller if (role == null) return Problem("No role with this id found", statusCode: 404); - + RoleMapper.Merge(role, request); await RoleRepository.UpdateAsync(role); diff --git a/Moonlight.Api/Services/UserAuthService.cs b/Moonlight.Api/Admin/Users/Users/UserAuthService.cs similarity index 93% rename from Moonlight.Api/Services/UserAuthService.cs rename to Moonlight.Api/Admin/Users/Users/UserAuthService.cs index 9a9a27c2..97151bd5 100644 --- a/Moonlight.Api/Services/UserAuthService.cs +++ b/Moonlight.Api/Admin/Users/Users/UserAuthService.cs @@ -3,26 +3,25 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Hybrid; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Interfaces; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Api.Infrastructure.Hooks; using Moonlight.Shared; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Users.Users; public class UserAuthService { - private readonly DatabaseRepository UserRepository; - private readonly ILogger Logger; - private readonly IOptions Options; - private readonly IEnumerable Hooks; - private readonly HybridCache HybridCache; + public const string CacheKeyPattern = $"Moonlight.{nameof(UserAuthService)}.{nameof(ValidateAsync)}-{{0}}"; private const string UserIdClaim = "UserId"; private const string IssuedAtClaim = "IssuedAt"; - - public const string CacheKeyPattern = $"Moonlight.{nameof(UserAuthService)}.{nameof(ValidateAsync)}-{{0}}"; + + private readonly IEnumerable Hooks; + private readonly HybridCache HybridCache; + private readonly ILogger Logger; + private readonly IOptions Options; + private readonly DatabaseRepository UserRepository; public UserAuthService( DatabaseRepository userRepository, @@ -60,7 +59,7 @@ public class UserAuthService if (user == null) // Sync user if not already existing in the database { - user = await UserRepository.AddAsync(new User() + user = await UserRepository.AddAsync(new User { Username = username, Email = email, @@ -80,11 +79,9 @@ public class UserAuthService ]); foreach (var hook in Hooks) - { // Run every hook, and if any returns false, we return false as well if (!await hook.SyncAsync(principal, user)) return false; - } return true; } @@ -114,9 +111,9 @@ public class UserAuthService u.InvalidateTimestamp, u.RoleMemberships.SelectMany(x => x.Role.Permissions).ToArray()) ) - .FirstOrDefaultAsync(cancellationToken: ct); + .FirstOrDefaultAsync(ct); }, - new HybridCacheEntryOptions() + new HybridCacheEntryOptions { LocalCacheExpiration = Options.Value.ValidationCacheL1Expiry, Expiration = Options.Value.ValidationCacheL2Expiry @@ -146,11 +143,9 @@ public class UserAuthService ); foreach (var hook in Hooks) - { // Run every hook, and if any returns false we return false as well if (!await hook.ValidateAsync(principal, userId)) return false; - } return true; } diff --git a/Moonlight.Api/Http/Controllers/Admin/Users/UserDeletionController.cs b/Moonlight.Api/Admin/Users/Users/UserDeletionController.cs similarity index 85% rename from Moonlight.Api/Http/Controllers/Admin/Users/UserDeletionController.cs rename to Moonlight.Api/Admin/Users/Users/UserDeletionController.cs index 48a5080f..d4b73ee5 100644 --- a/Moonlight.Api/Http/Controllers/Admin/Users/UserDeletionController.cs +++ b/Moonlight.Api/Admin/Users/Users/UserDeletionController.cs @@ -1,21 +1,19 @@ -using System.Collections.Frozen; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Services; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -namespace Moonlight.Api.Http.Controllers.Admin.Users; +namespace Moonlight.Api.Admin.Users.Users; [ApiController] [Route("api/admin/users")] [Authorize(Policy = Permissions.Users.Delete)] public class UserDeletionController : Controller { - private readonly UserDeletionService UserDeletionService; private readonly DatabaseRepository Repository; + private readonly UserDeletionService UserDeletionService; public UserDeletionController(UserDeletionService userDeletionService, DatabaseRepository repository) { @@ -39,7 +37,7 @@ public class UserDeletionController : Controller { return ValidationProblem( new ValidationProblemDetails( - new Dictionary() + new Dictionary { { string.Empty, @@ -49,7 +47,7 @@ public class UserDeletionController : Controller ) ); } - + await UserDeletionService.DeleteAsync(id); return NoContent(); } diff --git a/Moonlight.Api/Services/UserDeletionService.cs b/Moonlight.Api/Admin/Users/Users/UserDeletionService.cs similarity index 86% rename from Moonlight.Api/Services/UserDeletionService.cs rename to Moonlight.Api/Admin/Users/Users/UserDeletionService.cs index 6253bbab..1bb13e89 100644 --- a/Moonlight.Api/Services/UserDeletionService.cs +++ b/Moonlight.Api/Admin/Users/Users/UserDeletionService.cs @@ -1,22 +1,22 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Hybrid; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Interfaces; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Api.Infrastructure.Hooks; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Users.Users; public class UserDeletionService { - private readonly DatabaseRepository Repository; private readonly IEnumerable Hooks; private readonly HybridCache HybridCache; + private readonly DatabaseRepository Repository; public UserDeletionService( DatabaseRepository repository, IEnumerable hooks, HybridCache hybridCache - ) + ) { Repository = repository; Hooks = hooks; @@ -28,20 +28,20 @@ public class UserDeletionService var user = await Repository .Query() .FirstOrDefaultAsync(x => x.Id == userId); - - if(user == null) + + if (user == null) throw new AggregateException($"User with id {userId} not found"); - + var errorMessages = new List(); foreach (var hook in Hooks) { if (await hook.ValidateAsync(user, errorMessages)) continue; - + return new UserDeletionValidationResult(false, errorMessages); } - + return new UserDeletionValidationResult(true, []); } @@ -50,13 +50,13 @@ public class UserDeletionService var user = await Repository .Query() .FirstOrDefaultAsync(x => x.Id == userId); - - if(user == null) + + if (user == null) throw new AggregateException($"User with id {userId} not found"); - + foreach (var hook in Hooks) await hook.ExecuteAsync(user); - + await Repository.RemoveAsync(user); await HybridCache.RemoveAsync(string.Format(UserAuthService.CacheKeyPattern, user.Id)); diff --git a/Moonlight.Api/Http/Controllers/Admin/Users/UserLogoutController.cs b/Moonlight.Api/Admin/Users/Users/UserLogoutController.cs similarity index 86% rename from Moonlight.Api/Http/Controllers/Admin/Users/UserLogoutController.cs rename to Moonlight.Api/Admin/Users/Users/UserLogoutController.cs index 20046ba8..69205060 100644 --- a/Moonlight.Api/Http/Controllers/Admin/Users/UserLogoutController.cs +++ b/Moonlight.Api/Admin/Users/Users/UserLogoutController.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Services; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -namespace Moonlight.Api.Http.Controllers.Admin.Users; +namespace Moonlight.Api.Admin.Users.Users; [ApiController] [Route("api/admin/users/{id:int}/logout")] diff --git a/Moonlight.Api/Services/UserLogoutService.cs b/Moonlight.Api/Admin/Users/Users/UserLogoutService.cs similarity index 85% rename from Moonlight.Api/Services/UserLogoutService.cs rename to Moonlight.Api/Admin/Users/Users/UserLogoutService.cs index 59b87257..20b79b57 100644 --- a/Moonlight.Api/Services/UserLogoutService.cs +++ b/Moonlight.Api/Admin/Users/Users/UserLogoutService.cs @@ -1,16 +1,16 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Hybrid; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Interfaces; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Api.Infrastructure.Hooks; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Admin.Users.Users; public class UserLogoutService { - private readonly DatabaseRepository Repository; private readonly IEnumerable Hooks; private readonly HybridCache HybridCache; + private readonly DatabaseRepository Repository; public UserLogoutService( DatabaseRepository repository, diff --git a/Moonlight.Api/Mappers/UserMapper.cs b/Moonlight.Api/Admin/Users/Users/UserMapper.cs similarity index 77% rename from Moonlight.Api/Mappers/UserMapper.cs rename to Moonlight.Api/Admin/Users/Users/UserMapper.cs index ef9673d3..5a312cad 100644 --- a/Moonlight.Api/Mappers/UserMapper.cs +++ b/Moonlight.Api/Admin/Users/Users/UserMapper.cs @@ -1,10 +1,9 @@ using System.Diagnostics.CodeAnalysis; +using Moonlight.Api.Infrastructure.Database.Entities; +using Moonlight.Shared.Admin.Users.Users; using Riok.Mapperly.Abstractions; -using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.Admin.Users; -using Moonlight.Shared.Http.Responses.Admin.Users; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Admin.Users.Users; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Api/Configuration/UserOptions.cs b/Moonlight.Api/Admin/Users/Users/UserOptions.cs similarity index 81% rename from Moonlight.Api/Configuration/UserOptions.cs rename to Moonlight.Api/Admin/Users/Users/UserOptions.cs index 84e8aac3..fefc937e 100644 --- a/Moonlight.Api/Configuration/UserOptions.cs +++ b/Moonlight.Api/Admin/Users/Users/UserOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Admin.Users.Users; public class UserOptions { diff --git a/Moonlight.Api/Http/Controllers/Admin/Users/UsersController.cs b/Moonlight.Api/Admin/Users/Users/UsersController.cs similarity index 87% rename from Moonlight.Api/Http/Controllers/Admin/Users/UsersController.cs rename to Moonlight.Api/Admin/Users/Users/UsersController.cs index e90ea5ed..03ecd63e 100644 --- a/Moonlight.Api/Http/Controllers/Admin/Users/UsersController.cs +++ b/Moonlight.Api/Admin/Users/Users/UsersController.cs @@ -1,16 +1,13 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Mappers; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; using Moonlight.Shared; -using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Admin.Users; -using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Admin.Users; +using Moonlight.Shared.Admin.Users.Users; +using Moonlight.Shared.Shared; -namespace Moonlight.Api.Http.Controllers.Admin.Users; +namespace Moonlight.Api.Admin.Users.Users; [Authorize] [ApiController] @@ -40,7 +37,7 @@ public class UsersController : Controller return Problem("Invalid length specified"); // Query building - + var query = UserRepository .Query(); @@ -51,10 +48,10 @@ public class UsersController : Controller { query = filterOption.Key switch { - nameof(Database.Entities.User.Email) => + nameof(Infrastructure.Database.Entities.User.Email) => query.Where(user => EF.Functions.ILike(user.Email, $"%{filterOption.Value}%")), - nameof(Database.Entities.User.Username) => + nameof(Infrastructure.Database.Entities.User.Username) => query.Where(user => EF.Functions.ILike(user.Username, $"%{filterOption.Value}%")), _ => query diff --git a/Moonlight.Api/Database/Entities/Theme.cs b/Moonlight.Api/Database/Entities/Theme.cs deleted file mode 100644 index bbaf6e32..00000000 --- a/Moonlight.Api/Database/Entities/Theme.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Moonlight.Api.Database.Entities; - -public class Theme -{ - public int Id { get; set; } - - [MaxLength(30)] - public required string Name { get; set; } - - [MaxLength(30)] - public required string Version { get; set; } - - [MaxLength(30)] - public required string Author { get; set; } - public bool IsEnabled { get; set; } - - [MaxLength(20_000)] - public required string CssContent { get; set; } -} \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs deleted file mode 100644 index 1742b643..00000000 --- a/Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Moonlight.Api.Http.Services.ContainerHelper.Events; - -public struct RebuildEventDto -{ - [JsonPropertyName("type")] - public RebuildEventType Type { get; set; } - - [JsonPropertyName("data")] - public string Data { get; set; } -} - -public enum RebuildEventType -{ - Log = 0, - Failed = 1, - Succeeded = 2, - Step = 3 -} \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs deleted file mode 100644 index c7dda283..00000000 --- a/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Api.Http.Services.ContainerHelper.Requests; - -public record RequestRebuildDto(bool NoBuildCache); \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs deleted file mode 100644 index 4c462fbc..00000000 --- a/Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Api.Http.Services.ContainerHelper.Requests; - -public record SetVersionDto(string Version); \ No newline at end of file diff --git a/Moonlight.Api/Configuration/CacheOptions.cs b/Moonlight.Api/Infrastructure/Configuration/CacheOptions.cs similarity index 56% rename from Moonlight.Api/Configuration/CacheOptions.cs rename to Moonlight.Api/Infrastructure/Configuration/CacheOptions.cs index 1d166b4f..72b8ed32 100644 --- a/Moonlight.Api/Configuration/CacheOptions.cs +++ b/Moonlight.Api/Infrastructure/Configuration/CacheOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Infrastructure.Configuration; public class CacheOptions { diff --git a/Moonlight.Api/Configuration/OidcOptions.cs b/Moonlight.Api/Infrastructure/Configuration/OidcOptions.cs similarity index 86% rename from Moonlight.Api/Configuration/OidcOptions.cs rename to Moonlight.Api/Infrastructure/Configuration/OidcOptions.cs index bf7c0625..145f1572 100644 --- a/Moonlight.Api/Configuration/OidcOptions.cs +++ b/Moonlight.Api/Infrastructure/Configuration/OidcOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Infrastructure.Configuration; public class OidcOptions { diff --git a/Moonlight.Api/Configuration/RedisOptions.cs b/Moonlight.Api/Infrastructure/Configuration/RedisOptions.cs similarity index 67% rename from Moonlight.Api/Configuration/RedisOptions.cs rename to Moonlight.Api/Infrastructure/Configuration/RedisOptions.cs index 37935ff7..9b51810a 100644 --- a/Moonlight.Api/Configuration/RedisOptions.cs +++ b/Moonlight.Api/Infrastructure/Configuration/RedisOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Infrastructure.Configuration; public class RedisOptions { diff --git a/Moonlight.Api/Database/DataContext.cs b/Moonlight.Api/Infrastructure/Database/DataContext.cs similarity index 76% rename from Moonlight.Api/Database/DataContext.cs rename to Moonlight.Api/Infrastructure/Database/DataContext.cs index 36c7d758..f71a4444 100644 --- a/Moonlight.Api/Database/DataContext.cs +++ b/Moonlight.Api/Infrastructure/Database/DataContext.cs @@ -1,19 +1,11 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Api.Database.Entities; +using Moonlight.Api.Infrastructure.Database.Entities; -namespace Moonlight.Api.Database; +namespace Moonlight.Api.Infrastructure.Database; public class DataContext : DbContext { - public DbSet Users { get; set; } - public DbSet SettingsOptions { get; set; } - public DbSet Roles { get; set; } - public DbSet RoleMembers { get; set; } - public DbSet ApiKeys { get; set; } - public DbSet Themes { get; set; } - private readonly IOptions Options; public DataContext(IOptions options) @@ -21,24 +13,36 @@ public class DataContext : DbContext Options = options; } + public DbSet Users { get; set; } + public DbSet SettingsOptions { get; set; } + public DbSet Roles { get; set; } + public DbSet RoleMembers { get; set; } + public DbSet ApiKeys { get; set; } + public DbSet Themes { get; set; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (optionsBuilder.IsConfigured) return; - + optionsBuilder.UseNpgsql( $"Host={Options.Value.Host};" + $"Port={Options.Value.Port};" + $"Username={Options.Value.Username};" + $"Password={Options.Value.Password};" + - $"Database={Options.Value.Database}" + $"Database={Options.Value.Database}", + builder => + { + builder.MigrationsAssembly(typeof(DataContext).Assembly); + builder.MigrationsHistoryTable("MigrationsHistory", "core"); + } ); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("core"); - + base.OnModelCreating(modelBuilder); } } \ No newline at end of file diff --git a/Moonlight.Api/Configuration/DatabaseOptions.cs b/Moonlight.Api/Infrastructure/Database/DatabaseOptions.cs similarity index 81% rename from Moonlight.Api/Configuration/DatabaseOptions.cs rename to Moonlight.Api/Infrastructure/Database/DatabaseOptions.cs index 4685d628..22074dde 100644 --- a/Moonlight.Api/Configuration/DatabaseOptions.cs +++ b/Moonlight.Api/Infrastructure/Database/DatabaseOptions.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Configuration; +namespace Moonlight.Api.Infrastructure.Database; public class DatabaseOptions { diff --git a/Moonlight.Api/Database/DatabaseRepository.cs b/Moonlight.Api/Infrastructure/Database/DatabaseRepository.cs similarity index 86% rename from Moonlight.Api/Database/DatabaseRepository.cs rename to Moonlight.Api/Infrastructure/Database/DatabaseRepository.cs index 4dcdcc8f..709e31d4 100644 --- a/Moonlight.Api/Database/DatabaseRepository.cs +++ b/Moonlight.Api/Infrastructure/Database/DatabaseRepository.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; -using Moonlight.Api.Database.Interfaces; +using Moonlight.Api.Infrastructure.Database.Interfaces; -namespace Moonlight.Api.Database; +namespace Moonlight.Api.Infrastructure.Database; public class DatabaseRepository where T : class { @@ -14,7 +14,10 @@ public class DatabaseRepository where T : class Set = DataContext.Set(); } - public IQueryable Query() => Set; + public IQueryable Query() + { + return Set; + } public async Task AddAsync(T entity) { @@ -23,7 +26,7 @@ public class DatabaseRepository where T : class actionTimestamps.CreatedAt = DateTimeOffset.UtcNow; actionTimestamps.UpdatedAt = DateTimeOffset.UtcNow; } - + var final = Set.Add(entity); await DataContext.SaveChangesAsync(); return final.Entity; @@ -33,7 +36,7 @@ public class DatabaseRepository where T : class { if (entity is IActionTimestamps actionTimestamps) actionTimestamps.UpdatedAt = DateTimeOffset.UtcNow; - + Set.Update(entity); await DataContext.SaveChangesAsync(); } diff --git a/Moonlight.Api/Services/DbMigrationService.cs b/Moonlight.Api/Infrastructure/Database/DbMigrationService.cs similarity index 75% rename from Moonlight.Api/Services/DbMigrationService.cs rename to Moonlight.Api/Infrastructure/Database/DbMigrationService.cs index 4d300a47..801b8b4c 100644 --- a/Moonlight.Api/Services/DbMigrationService.cs +++ b/Moonlight.Api/Infrastructure/Database/DbMigrationService.cs @@ -2,9 +2,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Moonlight.Api.Database; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Infrastructure.Database; public class DbMigrationService : IHostedLifecycleService { @@ -29,7 +28,7 @@ public class DbMigrationService : IHostedLifecycleService if (migrationNames.Length == 0) { - Logger.LogDebug("No pending migrations found"); + Logger.LogTrace("No pending migrations found"); return; } @@ -41,9 +40,28 @@ public class DbMigrationService : IHostedLifecycleService Logger.LogInformation("Migration complete"); } - public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public Task StartedAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public Task StoppingAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StartAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task StartedAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task StoppedAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task StoppingAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } } \ No newline at end of file diff --git a/Moonlight.Api/Database/Entities/ApiKey.cs b/Moonlight.Api/Infrastructure/Database/Entities/ApiKey.cs similarity index 53% rename from Moonlight.Api/Database/Entities/ApiKey.cs rename to Moonlight.Api/Infrastructure/Database/Entities/ApiKey.cs index 3073f0c6..ea0a2c39 100644 --- a/Moonlight.Api/Database/Entities/ApiKey.cs +++ b/Moonlight.Api/Infrastructure/Database/Entities/ApiKey.cs @@ -1,24 +1,21 @@ using System.ComponentModel.DataAnnotations; -using Moonlight.Api.Database.Interfaces; +using Moonlight.Api.Infrastructure.Database.Interfaces; -namespace Moonlight.Api.Database.Entities; +namespace Moonlight.Api.Infrastructure.Database.Entities; public class ApiKey : IActionTimestamps { public int Id { get; set; } - [MaxLength(30)] - public required string Name { get; set; } - - [MaxLength(300)] - public required string Description { get; set; } - + [MaxLength(30)] public required string Name { get; set; } + + [MaxLength(300)] public required string Description { get; set; } + public string[] Permissions { get; set; } = []; public DateTimeOffset ValidUntil { get; set; } - - [MaxLength(32)] - public string Key { get; set; } - + + [MaxLength(32)] public string Key { get; set; } + // Action timestamps public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset UpdatedAt { get; set; } diff --git a/Moonlight.Api/Database/Entities/Role.cs b/Moonlight.Api/Infrastructure/Database/Entities/Role.cs similarity index 59% rename from Moonlight.Api/Database/Entities/Role.cs rename to Moonlight.Api/Infrastructure/Database/Entities/Role.cs index a38ccd13..e19a629c 100644 --- a/Moonlight.Api/Database/Entities/Role.cs +++ b/Moonlight.Api/Infrastructure/Database/Entities/Role.cs @@ -1,23 +1,21 @@ using System.ComponentModel.DataAnnotations; -using Moonlight.Api.Database.Interfaces; +using Moonlight.Api.Infrastructure.Database.Interfaces; -namespace Moonlight.Api.Database.Entities; +namespace Moonlight.Api.Infrastructure.Database.Entities; public class Role : IActionTimestamps { public int Id { get; set; } - [MaxLength(30)] - public required string Name { get; set; } - - [MaxLength(300)] - public required string Description { get; set; } + [MaxLength(30)] public required string Name { get; set; } + + [MaxLength(300)] public required string Description { get; set; } public string[] Permissions { get; set; } = []; - + // Relations public List Members { get; set; } = []; - + // Action timestamps public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset UpdatedAt { get; set; } diff --git a/Moonlight.Api/Database/Entities/RoleMember.cs b/Moonlight.Api/Infrastructure/Database/Entities/RoleMember.cs similarity index 70% rename from Moonlight.Api/Database/Entities/RoleMember.cs rename to Moonlight.Api/Infrastructure/Database/Entities/RoleMember.cs index 5363689a..4315e1fd 100644 --- a/Moonlight.Api/Database/Entities/RoleMember.cs +++ b/Moonlight.Api/Infrastructure/Database/Entities/RoleMember.cs @@ -1,6 +1,6 @@ -using Moonlight.Api.Database.Interfaces; +using Moonlight.Api.Infrastructure.Database.Interfaces; -namespace Moonlight.Api.Database.Entities; +namespace Moonlight.Api.Infrastructure.Database.Entities; public class RoleMember : IActionTimestamps { @@ -8,7 +8,7 @@ public class RoleMember : IActionTimestamps public Role Role { get; set; } public User User { get; set; } - + // Action timestamps public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset UpdatedAt { get; set; } diff --git a/Moonlight.Api/Database/Entities/SettingsOption.cs b/Moonlight.Api/Infrastructure/Database/Entities/SettingsOption.cs similarity index 68% rename from Moonlight.Api/Database/Entities/SettingsOption.cs rename to Moonlight.Api/Infrastructure/Database/Entities/SettingsOption.cs index 74cf210a..d23d22e9 100644 --- a/Moonlight.Api/Database/Entities/SettingsOption.cs +++ b/Moonlight.Api/Infrastructure/Database/Entities/SettingsOption.cs @@ -1,15 +1,14 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Moonlight.Api.Database.Entities; +namespace Moonlight.Api.Infrastructure.Database.Entities; public class SettingsOption { public int Id { get; set; } - [MaxLength(256)] - public required string Key { get; set; } - + [MaxLength(256)] public required string Key { get; set; } + [MaxLength(4096)] [Column(TypeName = "jsonb")] public required string ValueJson { get; set; } diff --git a/Moonlight.Api/Infrastructure/Database/Entities/Theme.cs b/Moonlight.Api/Infrastructure/Database/Entities/Theme.cs new file mode 100644 index 00000000..e054a1cd --- /dev/null +++ b/Moonlight.Api/Infrastructure/Database/Entities/Theme.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Api.Infrastructure.Database.Entities; + +public class Theme +{ + public int Id { get; set; } + + [MaxLength(30)] public required string Name { get; set; } + + [MaxLength(30)] public required string Version { get; set; } + + [MaxLength(30)] public required string Author { get; set; } + + public bool IsEnabled { get; set; } + + [MaxLength(20_000)] public required string CssContent { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Api/Database/Entities/User.cs b/Moonlight.Api/Infrastructure/Database/Entities/User.cs similarity index 64% rename from Moonlight.Api/Database/Entities/User.cs rename to Moonlight.Api/Infrastructure/Database/Entities/User.cs index 54d04f2d..fefb10e0 100644 --- a/Moonlight.Api/Database/Entities/User.cs +++ b/Moonlight.Api/Infrastructure/Database/Entities/User.cs @@ -1,25 +1,23 @@ using System.ComponentModel.DataAnnotations; -using Moonlight.Api.Database.Interfaces; +using Moonlight.Api.Infrastructure.Database.Interfaces; -namespace Moonlight.Api.Database.Entities; +namespace Moonlight.Api.Infrastructure.Database.Entities; public class User : IActionTimestamps { public int Id { get; set; } // Base information - [MaxLength(50)] - public required string Username { get; set; } - - [MaxLength(254)] - public required string Email { get; set; } + [MaxLength(50)] public required string Username { get; set; } + + [MaxLength(254)] public required string Email { get; set; } // Authentication public DateTimeOffset InvalidateTimestamp { get; set; } // Relations public List RoleMemberships { get; set; } = []; - + // Action timestamps public DateTimeOffset CreatedAt { get; set; } public DateTimeOffset UpdatedAt { get; set; } diff --git a/Moonlight.Api/Database/Interfaces/IActionTimestamps.cs b/Moonlight.Api/Infrastructure/Database/Interfaces/IActionTimestamps.cs similarity index 70% rename from Moonlight.Api/Database/Interfaces/IActionTimestamps.cs rename to Moonlight.Api/Infrastructure/Database/Interfaces/IActionTimestamps.cs index 616383e1..764ed307 100644 --- a/Moonlight.Api/Database/Interfaces/IActionTimestamps.cs +++ b/Moonlight.Api/Infrastructure/Database/Interfaces/IActionTimestamps.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Database.Interfaces; +namespace Moonlight.Api.Infrastructure.Database.Interfaces; internal interface IActionTimestamps { diff --git a/Moonlight.Api/Database/Migrations/20251225202335_AddedUsersAndSettings.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20251225202335_AddedUsersAndSettings.Designer.cs similarity index 98% rename from Moonlight.Api/Database/Migrations/20251225202335_AddedUsersAndSettings.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20251225202335_AddedUsersAndSettings.Designer.cs index 0c7f92c8..59fb569b 100644 --- a/Moonlight.Api/Database/Migrations/20251225202335_AddedUsersAndSettings.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20251225202335_AddedUsersAndSettings.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20251225202335_AddedUsersAndSettings.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20251225202335_AddedUsersAndSettings.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20251225202335_AddedUsersAndSettings.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20251225202335_AddedUsersAndSettings.cs diff --git a/Moonlight.Api/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.Designer.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.Designer.cs index 4421d15c..c886ca64 100644 --- a/Moonlight.Api/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20251230200748_AddedRolesAndActionTimestamps.cs diff --git a/Moonlight.Api/Database/Migrations/20260116133404_AddedApiKeys.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260116133404_AddedApiKeys.Designer.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/20260116133404_AddedApiKeys.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260116133404_AddedApiKeys.Designer.cs index 5a99596d..d3caa5e0 100644 --- a/Moonlight.Api/Database/Migrations/20260116133404_AddedApiKeys.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20260116133404_AddedApiKeys.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20260116133404_AddedApiKeys.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260116133404_AddedApiKeys.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20260116133404_AddedApiKeys.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260116133404_AddedApiKeys.cs diff --git a/Moonlight.Api/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.Designer.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.Designer.cs index 11979c0b..4f190d81 100644 --- a/Moonlight.Api/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260116134322_AdjustedLenghtsOfRoleAndApiKeyStrings.cs diff --git a/Moonlight.Api/Database/Migrations/20260118005634_AddedThemes.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260118005634_AddedThemes.Designer.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/20260118005634_AddedThemes.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260118005634_AddedThemes.Designer.cs index 6b189b36..ccf5ce7f 100644 --- a/Moonlight.Api/Database/Migrations/20260118005634_AddedThemes.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20260118005634_AddedThemes.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20260118005634_AddedThemes.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260118005634_AddedThemes.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20260118005634_AddedThemes.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260118005634_AddedThemes.cs diff --git a/Moonlight.Api/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.Designer.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.Designer.cs index 97ae800d..295be88b 100644 --- a/Moonlight.Api/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260129134620_SwitchedToJsonForSettingsOption.cs diff --git a/Moonlight.Api/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.Designer.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.Designer.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.Designer.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.Designer.cs index 03bdc39f..205335a6 100644 --- a/Moonlight.Api/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.Designer.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.Designer.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.cs b/Moonlight.Api/Infrastructure/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.cs similarity index 100% rename from Moonlight.Api/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/20260209114238_AddedValidUntilToApiKeys.cs diff --git a/Moonlight.Api/Database/Migrations/DataContextModelSnapshot.cs b/Moonlight.Api/Infrastructure/Database/Migrations/DataContextModelSnapshot.cs similarity index 99% rename from Moonlight.Api/Database/Migrations/DataContextModelSnapshot.cs rename to Moonlight.Api/Infrastructure/Database/Migrations/DataContextModelSnapshot.cs index 2945a90c..94786c5b 100644 --- a/Moonlight.Api/Database/Migrations/DataContextModelSnapshot.cs +++ b/Moonlight.Api/Infrastructure/Database/Migrations/DataContextModelSnapshot.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Moonlight.Api.Database; +using Moonlight.Api.Infrastructure.Database; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable diff --git a/Moonlight.Api/Helpers/AppConsoleFormatter.cs b/Moonlight.Api/Infrastructure/Helpers/AppConsoleFormatter.cs similarity index 97% rename from Moonlight.Api/Helpers/AppConsoleFormatter.cs rename to Moonlight.Api/Infrastructure/Helpers/AppConsoleFormatter.cs index d5b7136a..b384e92a 100644 --- a/Moonlight.Api/Helpers/AppConsoleFormatter.cs +++ b/Moonlight.Api/Infrastructure/Helpers/AppConsoleFormatter.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Console; -namespace Moonlight.Api.Helpers; +namespace Moonlight.Api.Infrastructure.Helpers; public class AppConsoleFormatter : ConsoleFormatter { @@ -58,7 +58,9 @@ public class AppConsoleFormatter : ConsoleFormatter textWriter.WriteLine(logEntry.Exception.ToString()); } else + { textWriter.WriteLine(); + } } private static (string text, string color) GetLevelInfo(LogLevel logLevel) diff --git a/Moonlight.Api/Interfaces/IDiagnoseProvider.cs b/Moonlight.Api/Infrastructure/Hooks/IDiagnoseProvider.cs similarity index 51% rename from Moonlight.Api/Interfaces/IDiagnoseProvider.cs rename to Moonlight.Api/Infrastructure/Hooks/IDiagnoseProvider.cs index e5d0a4a6..726e4397 100644 --- a/Moonlight.Api/Interfaces/IDiagnoseProvider.cs +++ b/Moonlight.Api/Infrastructure/Hooks/IDiagnoseProvider.cs @@ -1,6 +1,6 @@ -using Moonlight.Api.Models; +using Moonlight.Api.Admin.Sys.Diagnose; -namespace Moonlight.Api.Interfaces; +namespace Moonlight.Api.Infrastructure.Hooks; public interface IDiagnoseProvider { diff --git a/Moonlight.Api/Interfaces/IUserAuthHook.cs b/Moonlight.Api/Infrastructure/Hooks/IUserAuthHook.cs similarity index 77% rename from Moonlight.Api/Interfaces/IUserAuthHook.cs rename to Moonlight.Api/Infrastructure/Hooks/IUserAuthHook.cs index d434e16c..a71db3f8 100644 --- a/Moonlight.Api/Interfaces/IUserAuthHook.cs +++ b/Moonlight.Api/Infrastructure/Hooks/IUserAuthHook.cs @@ -1,12 +1,12 @@ using System.Security.Claims; -using Moonlight.Api.Database.Entities; +using Moonlight.Api.Infrastructure.Database.Entities; -namespace Moonlight.Api.Interfaces; +namespace Moonlight.Api.Infrastructure.Hooks; public interface IUserAuthHook { public Task SyncAsync(ClaimsPrincipal principal, User trackedUser); - + // Every implementation of this function should execute as fast as possible // as this directly impacts every api call public Task ValidateAsync(ClaimsPrincipal principal, int userId); diff --git a/Moonlight.Api/Interfaces/IUserDeletionHook.cs b/Moonlight.Api/Infrastructure/Hooks/IUserDeletionHook.cs similarity index 60% rename from Moonlight.Api/Interfaces/IUserDeletionHook.cs rename to Moonlight.Api/Infrastructure/Hooks/IUserDeletionHook.cs index 15710996..842668bd 100644 --- a/Moonlight.Api/Interfaces/IUserDeletionHook.cs +++ b/Moonlight.Api/Infrastructure/Hooks/IUserDeletionHook.cs @@ -1,6 +1,6 @@ -using Moonlight.Api.Database.Entities; +using Moonlight.Api.Infrastructure.Database.Entities; -namespace Moonlight.Api.Interfaces; +namespace Moonlight.Api.Infrastructure.Hooks; public interface IUserDeletionHook { diff --git a/Moonlight.Api/Infrastructure/Hooks/IUserLogoutHook.cs b/Moonlight.Api/Infrastructure/Hooks/IUserLogoutHook.cs new file mode 100644 index 00000000..a26ebce6 --- /dev/null +++ b/Moonlight.Api/Infrastructure/Hooks/IUserLogoutHook.cs @@ -0,0 +1,8 @@ +using Moonlight.Api.Infrastructure.Database.Entities; + +namespace Moonlight.Api.Infrastructure.Hooks; + +public interface IUserLogoutHook +{ + public Task ExecuteAsync(User user); +} \ No newline at end of file diff --git a/Moonlight.Api/Implementations/PermissionAuthorizationHandler.cs b/Moonlight.Api/Infrastructure/Implementations/PermissionAuthorizationHandler.cs similarity index 94% rename from Moonlight.Api/Implementations/PermissionAuthorizationHandler.cs rename to Moonlight.Api/Infrastructure/Implementations/PermissionAuthorizationHandler.cs index dd378d57..11e98a2d 100644 --- a/Moonlight.Api/Implementations/PermissionAuthorizationHandler.cs +++ b/Moonlight.Api/Infrastructure/Implementations/PermissionAuthorizationHandler.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Moonlight.Shared; -namespace Moonlight.Api.Implementations; +namespace Moonlight.Api.Infrastructure.Implementations; public class PermissionAuthorizationHandler : AuthorizationHandler { diff --git a/Moonlight.Api/Implementations/PermissionPolicyProvider.cs b/Moonlight.Api/Infrastructure/Implementations/PermissionPolicyProvider.cs similarity index 85% rename from Moonlight.Api/Implementations/PermissionPolicyProvider.cs rename to Moonlight.Api/Infrastructure/Implementations/PermissionPolicyProvider.cs index 217c868e..127afba3 100644 --- a/Moonlight.Api/Implementations/PermissionPolicyProvider.cs +++ b/Moonlight.Api/Infrastructure/Implementations/PermissionPolicyProvider.cs @@ -2,22 +2,22 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Moonlight.Shared; -namespace Moonlight.Api.Implementations; +namespace Moonlight.Api.Infrastructure.Implementations; public class PermissionPolicyProvider : IAuthorizationPolicyProvider { private readonly DefaultAuthorizationPolicyProvider FallbackProvider; - + public PermissionPolicyProvider(IOptions options) { FallbackProvider = new DefaultAuthorizationPolicyProvider(options); } - + public async Task GetPolicyAsync(string policyName) { if (!policyName.StartsWith(Permissions.Prefix, StringComparison.OrdinalIgnoreCase)) return await FallbackProvider.GetPolicyAsync(policyName); - + var policy = new AuthorizationPolicyBuilder(); policy.AddRequirements(new PermissionRequirement(policyName)); @@ -25,18 +25,22 @@ public class PermissionPolicyProvider : IAuthorizationPolicyProvider } public Task GetDefaultPolicyAsync() - => FallbackProvider.GetDefaultPolicyAsync(); + { + return FallbackProvider.GetDefaultPolicyAsync(); + } public Task GetFallbackPolicyAsync() - => FallbackProvider.GetFallbackPolicyAsync(); + { + return FallbackProvider.GetFallbackPolicyAsync(); + } } public class PermissionRequirement : IAuthorizationRequirement { - public string Identifier { get; } - public PermissionRequirement(string identifier) { Identifier = identifier; } + + public string Identifier { get; } } \ No newline at end of file diff --git a/Moonlight.Api/Implementations/UpdateDiagnoseProvider.cs b/Moonlight.Api/Infrastructure/Implementations/UpdateDiagnoseProvider.cs similarity index 84% rename from Moonlight.Api/Implementations/UpdateDiagnoseProvider.cs rename to Moonlight.Api/Infrastructure/Implementations/UpdateDiagnoseProvider.cs index cf1b99e8..43d77632 100644 --- a/Moonlight.Api/Implementations/UpdateDiagnoseProvider.cs +++ b/Moonlight.Api/Infrastructure/Implementations/UpdateDiagnoseProvider.cs @@ -1,8 +1,8 @@ -using Moonlight.Api.Interfaces; -using Moonlight.Api.Models; -using Moonlight.Api.Services; +using Moonlight.Api.Admin.Sys; +using Moonlight.Api.Admin.Sys.Diagnose; +using Moonlight.Api.Infrastructure.Hooks; -namespace Moonlight.Api.Implementations; +namespace Moonlight.Api.Infrastructure.Implementations; public sealed class UpdateDiagnoseProvider : IDiagnoseProvider { diff --git a/Moonlight.Api/Interfaces/IUserLogoutHook.cs b/Moonlight.Api/Interfaces/IUserLogoutHook.cs deleted file mode 100644 index 4516af69..00000000 --- a/Moonlight.Api/Interfaces/IUserLogoutHook.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Moonlight.Api.Database.Entities; - -namespace Moonlight.Api.Interfaces; - -public interface IUserLogoutHook -{ - public Task ExecuteAsync(User user); -} \ No newline at end of file diff --git a/Moonlight.Api/Models/DiagnoseResult.cs b/Moonlight.Api/Models/DiagnoseResult.cs deleted file mode 100644 index c968ab92..00000000 --- a/Moonlight.Api/Models/DiagnoseResult.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Moonlight.Api.Models; - -public record DiagnoseResult(DiagnoseLevel Level, string Title, string[] Tags, string? Message, string? StackStrace, string? SolutionUrl, string? ReportUrl); - -public enum DiagnoseLevel -{ - Error = 0, - Warning = 1, - Healthy = 2 -} \ No newline at end of file diff --git a/Moonlight.Api/Moonlight.Api.csproj b/Moonlight.Api/Moonlight.Api.csproj index eae99e8c..4494d354 100644 --- a/Moonlight.Api/Moonlight.Api.csproj +++ b/Moonlight.Api/Moonlight.Api.csproj @@ -6,7 +6,7 @@ enable Linux - + 2.1.0 Moonlight.Api @@ -24,15 +24,15 @@
- - - - - - - - - + + + + + + + + + @@ -42,6 +42,6 @@ - + \ No newline at end of file diff --git a/Moonlight.Api/MoonlightPlugin.cs b/Moonlight.Api/MoonlightPlugin.cs index 2b5441fd..570f5146 100644 --- a/Moonlight.Api/MoonlightPlugin.cs +++ b/Moonlight.Api/MoonlightPlugin.cs @@ -1,6 +1,4 @@ -using System.Reflection; -using System.Text.Json.Serialization; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using SimplePlugin.Abstractions; namespace Moonlight.Api; @@ -13,7 +11,7 @@ public abstract class MoonlightPlugin : IPluginModule { Plugins = plugins; } - + public virtual void PreBuild(WebApplicationBuilder builder) { } diff --git a/Moonlight.Api/Http/Controllers/AuthController.cs b/Moonlight.Api/Shared/Auth/AuthController.cs similarity index 89% rename from Moonlight.Api/Http/Controllers/AuthController.cs rename to Moonlight.Api/Shared/Auth/AuthController.cs index 34dc18e7..931394b4 100644 --- a/Moonlight.Api/Http/Controllers/AuthController.cs +++ b/Moonlight.Api/Shared/Auth/AuthController.cs @@ -1,9 +1,9 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Moonlight.Shared.Http.Responses.Admin.Auth; +using Moonlight.Shared.Shared.Auth; -namespace Moonlight.Api.Http.Controllers; +namespace Moonlight.Api.Shared.Auth; [ApiController] [Route("api/auth")] @@ -35,7 +35,7 @@ public class AuthController : Controller if (scheme == null || string.IsNullOrWhiteSpace(scheme.DisplayName)) return Problem("Invalid authentication scheme name", statusCode: 400); - return Challenge(new AuthenticationProperties() + return Challenge(new AuthenticationProperties { RedirectUri = "/" }, scheme.Name); @@ -56,7 +56,7 @@ public class AuthController : Controller public Task LogoutAsync() { return Task.FromResult( - SignOut(new AuthenticationProperties() + SignOut(new AuthenticationProperties { RedirectUri = "/" }) diff --git a/Moonlight.Api/Mappers/FrontendConfigMapper.cs b/Moonlight.Api/Shared/Frontend/FrontendConfigMapper.cs similarity index 77% rename from Moonlight.Api/Mappers/FrontendConfigMapper.cs rename to Moonlight.Api/Shared/Frontend/FrontendConfigMapper.cs index e731d714..b9945b8b 100644 --- a/Moonlight.Api/Mappers/FrontendConfigMapper.cs +++ b/Moonlight.Api/Shared/Frontend/FrontendConfigMapper.cs @@ -1,9 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Api.Models; -using Moonlight.Shared.Http.Responses.Admin.Frontend; +using Moonlight.Shared.Shared.Frontend; using Riok.Mapperly.Abstractions; -namespace Moonlight.Api.Mappers; +namespace Moonlight.Api.Shared.Frontend; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Api/Models/FrontendConfiguration.cs b/Moonlight.Api/Shared/Frontend/FrontendConfiguration.cs similarity index 62% rename from Moonlight.Api/Models/FrontendConfiguration.cs rename to Moonlight.Api/Shared/Frontend/FrontendConfiguration.cs index 853bf545..9300bbba 100644 --- a/Moonlight.Api/Models/FrontendConfiguration.cs +++ b/Moonlight.Api/Shared/Frontend/FrontendConfiguration.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Api.Models; +namespace Moonlight.Api.Shared.Frontend; public record FrontendConfiguration(string Name, string? ThemeCss); \ No newline at end of file diff --git a/Moonlight.Api/Http/Controllers/FrontendController.cs b/Moonlight.Api/Shared/Frontend/FrontendController.cs similarity index 77% rename from Moonlight.Api/Http/Controllers/FrontendController.cs rename to Moonlight.Api/Shared/Frontend/FrontendController.cs index 6fffb0aa..4f4b982a 100644 --- a/Moonlight.Api/Http/Controllers/FrontendController.cs +++ b/Moonlight.Api/Shared/Frontend/FrontendController.cs @@ -1,9 +1,7 @@ using Microsoft.AspNetCore.Mvc; -using Moonlight.Api.Mappers; -using Moonlight.Api.Services; -using Moonlight.Shared.Http.Responses.Admin.Frontend; +using Moonlight.Shared.Shared.Frontend; -namespace Moonlight.Api.Http.Controllers; +namespace Moonlight.Api.Shared.Frontend; [ApiController] [Route("api/frontend")] diff --git a/Moonlight.Api/Services/FrontendService.cs b/Moonlight.Api/Shared/Frontend/FrontendService.cs similarity index 81% rename from Moonlight.Api/Services/FrontendService.cs rename to Moonlight.Api/Shared/Frontend/FrontendService.cs index f3fa3eb4..e44eeae6 100644 --- a/Moonlight.Api/Services/FrontendService.cs +++ b/Moonlight.Api/Shared/Frontend/FrontendService.cs @@ -1,24 +1,23 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Api.Constants; -using Moonlight.Api.Database; -using Moonlight.Api.Database.Entities; -using Moonlight.Api.Models; +using Moonlight.Api.Admin.Sys.Settings; +using Moonlight.Api.Admin.Sys.Versions; +using Moonlight.Api.Infrastructure.Database; +using Moonlight.Api.Infrastructure.Database.Entities; -namespace Moonlight.Api.Services; +namespace Moonlight.Api.Shared.Frontend; public class FrontendService { + private const string CacheKey = $"Moonlight.{nameof(FrontendService)}.{nameof(GetConfigurationAsync)}"; private readonly IMemoryCache Cache; - private readonly DatabaseRepository ThemeRepository; private readonly IOptions Options; private readonly SettingsService SettingsService; - - private const string CacheKey = $"Moonlight.{nameof(FrontendService)}.{nameof(GetConfigurationAsync)}"; + private readonly DatabaseRepository ThemeRepository; - public FrontendService(IMemoryCache cache, DatabaseRepository themeRepository, IOptions options, SettingsService settingsService) + public FrontendService(IMemoryCache cache, DatabaseRepository themeRepository, + IOptions options, SettingsService settingsService) { Cache = cache; ThemeRepository = themeRepository; @@ -29,17 +28,15 @@ public class FrontendService public async Task GetConfigurationAsync() { if (Cache.TryGetValue(CacheKey, out FrontendConfiguration? value)) - { if (value != null) return value; - } var theme = await ThemeRepository .Query() .FirstOrDefaultAsync(x => x.IsEnabled); var name = await SettingsService.GetValueAsync(FrontendSettingConstants.Name); - + var config = new FrontendConfiguration(name ?? "Moonlight", theme?.CssContent); Cache.Set(CacheKey, config, TimeSpan.FromMinutes(Options.Value.CacheMinutes)); diff --git a/Moonlight.Api/Constants/FrontendSettingConstants.cs b/Moonlight.Api/Shared/Frontend/FrontendSettingConstants.cs similarity index 70% rename from Moonlight.Api/Constants/FrontendSettingConstants.cs rename to Moonlight.Api/Shared/Frontend/FrontendSettingConstants.cs index 1c4e81aa..1b463306 100644 --- a/Moonlight.Api/Constants/FrontendSettingConstants.cs +++ b/Moonlight.Api/Shared/Frontend/FrontendSettingConstants.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Api.Constants; +namespace Moonlight.Api.Shared.Frontend; public class FrontendSettingConstants { diff --git a/Moonlight.Api/Http/Controllers/PingController.cs b/Moonlight.Api/Shared/PingController.cs similarity index 65% rename from Moonlight.Api/Http/Controllers/PingController.cs rename to Moonlight.Api/Shared/PingController.cs index 8de46960..934da371 100644 --- a/Moonlight.Api/Http/Controllers/PingController.cs +++ b/Moonlight.Api/Shared/PingController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace Moonlight.Api.Http.Controllers; +namespace Moonlight.Api.Shared; [ApiController] [Route("api/ping")] @@ -9,5 +9,8 @@ public class PingController : Controller { [HttpGet] [AllowAnonymous] - public IActionResult Get() => Ok("Pong"); + public IActionResult Get() + { + return Ok("Pong"); + } } \ No newline at end of file diff --git a/Moonlight.Api/Startup/Startup.Auth.cs b/Moonlight.Api/Startup/Startup.Auth.cs index 7d404c56..14c724b4 100644 --- a/Moonlight.Api/Startup/Startup.Auth.cs +++ b/Moonlight.Api/Startup/Startup.Auth.cs @@ -6,10 +6,11 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Moonlight.Api.Configuration; -using Moonlight.Api.Implementations; -using Moonlight.Api.Implementations.ApiKeyScheme; -using Moonlight.Api.Services; +using Moonlight.Api.Admin.Sys.ApiKeys; +using Moonlight.Api.Admin.Sys.ApiKeys.Scheme; +using Moonlight.Api.Admin.Users.Users; +using Moonlight.Api.Infrastructure.Configuration; +using Moonlight.Api.Infrastructure.Implementations; namespace Moonlight.Api.Startup; @@ -25,7 +26,7 @@ public partial class Startup var apiKeyOptions = new ApiOptions(); builder.Configuration.GetSection("Moonlight:Api").Bind(apiKeyOptions); builder.Services.AddOptions().BindConfiguration("Moonlight:Api"); - + // Session builder.Services.AddOptions().BindConfiguration("Moonlight:User"); @@ -67,7 +68,7 @@ public partial class Startup context.RejectPrincipal(); }; - options.Cookie = new CookieBuilder() + options.Cookie = new CookieBuilder { Name = "token", Path = "/", @@ -109,7 +110,7 @@ public partial class Startup options.LookupL1CacheTime = apiKeyOptions.LookupCacheL1Expiry; options.LookupL2CacheTime = apiKeyOptions.LookupCacheL2Expiry; }); - + // Authorization builder.Services.AddAuthorization(); @@ -119,7 +120,7 @@ public partial class Startup // Custom permission handling using named policies builder.Services.AddSingleton(); builder.Services.AddSingleton(); - + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Moonlight.Api/Startup/Startup.Base.cs b/Moonlight.Api/Startup/Startup.Base.cs index daa0c912..3d9e77ea 100644 --- a/Moonlight.Api/Startup/Startup.Base.cs +++ b/Moonlight.Api/Startup/Startup.Base.cs @@ -5,12 +5,18 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Console; using Microsoft.Extensions.Options; -using Moonlight.Api.Configuration; -using Moonlight.Shared.Http; -using Moonlight.Api.Helpers; -using Moonlight.Api.Implementations; -using Moonlight.Api.Interfaces; -using Moonlight.Api.Services; +using Moonlight.Api.Admin.Sys; +using Moonlight.Api.Admin.Sys.ContainerHelper; +using Moonlight.Api.Admin.Sys.Diagnose; +using Moonlight.Api.Admin.Sys.Settings; +using Moonlight.Api.Admin.Sys.Versions; +using Moonlight.Api.Admin.Users.Users; +using Moonlight.Api.Infrastructure.Helpers; +using Moonlight.Api.Infrastructure.Hooks; +using Moonlight.Api.Infrastructure.Implementations; +using Moonlight.Api.Shared.Frontend; +using Moonlight.Shared; +using VersionService = Moonlight.Api.Admin.Sys.Versions.VersionService; namespace Moonlight.Api.Startup; diff --git a/Moonlight.Api/Startup/Startup.Cache.cs b/Moonlight.Api/Startup/Startup.Cache.cs index 9d642ff5..90a3ab4e 100644 --- a/Moonlight.Api/Startup/Startup.Cache.cs +++ b/Moonlight.Api/Startup/Startup.Cache.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Moonlight.Api.Configuration; +using Moonlight.Api.Infrastructure.Configuration; namespace Moonlight.Api.Startup; @@ -22,9 +22,9 @@ public partial class Startup var redisOptions = new RedisOptions(); builder.Configuration.GetSection("Moonlight:Redis").Bind(redisOptions); - if(!redisOptions.Enable) + if (!redisOptions.Enable) return; - + builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = redisOptions.ConnectionString; diff --git a/Moonlight.Api/Startup/Startup.Database.cs b/Moonlight.Api/Startup/Startup.Database.cs index 04a9c3bc..c022a4b0 100644 --- a/Moonlight.Api/Startup/Startup.Database.cs +++ b/Moonlight.Api/Startup/Startup.Database.cs @@ -1,8 +1,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using Moonlight.Api.Configuration; -using Moonlight.Api.Database; -using Moonlight.Api.Services; +using Moonlight.Api.Infrastructure.Database; namespace Moonlight.Api.Startup; diff --git a/Moonlight.Api/Startup/Startup.cs b/Moonlight.Api/Startup/Startup.cs index 6844ebcb..a396f9db 100644 --- a/Moonlight.Api/Startup/Startup.cs +++ b/Moonlight.Api/Startup/Startup.cs @@ -1,7 +1,4 @@ -using System.Reflection; -using System.Text.Json.Serialization; -using Microsoft.AspNetCore.Builder; -using Moonlight.Shared.Http; +using Microsoft.AspNetCore.Builder; using SimplePlugin.Abstractions; namespace Moonlight.Api.Startup; diff --git a/Moonlight.Api/StartupHandler.cs b/Moonlight.Api/StartupHandler.cs index 3495e373..d49886f0 100644 --- a/Moonlight.Api/StartupHandler.cs +++ b/Moonlight.Api/StartupHandler.cs @@ -8,7 +8,7 @@ public static class StartupHandler public static async Task RunAsync(string[] args, MoonlightPlugin[] plugins) { Console.WriteLine($"Starting with: {string.Join(", ", plugins.Select(x => x.GetType().FullName))}"); - + var builder = WebApplication.CreateBuilder(args); // Setting up context diff --git a/Moonlight.Frontend/Admin/Setup/Index.razor b/Moonlight.Frontend/Admin/Setup/Index.razor new file mode 100644 index 00000000..99e1703e --- /dev/null +++ b/Moonlight.Frontend/Admin/Setup/Index.razor @@ -0,0 +1,181 @@ +@using LucideBlazor +@using Moonlight.Shared.Admin.Setup +@using ShadcnBlazor.Buttons +@using ShadcnBlazor.Cards +@using ShadcnBlazor.Inputs +@using ShadcnBlazor.Labels +@using ShadcnBlazor.Spinners + +@inject HttpClient HttpClient +@inject NavigationManager Navigation + +
+ + @if (IsLoaded) + { +
+ @switch (CurrentStep) + { + case 0: +
+ Moonlight Logo +
+ +
+

Welcome to Moonlight Panel

+

+ You successfully installed moonlight. Now you are ready to perform some initial steps to + complete your installation +

+
+ break; + + case 1: +
+ +
+ +
+

Admin Account Creation

+

+ To continue please fill in the account details of the user you want to use as the initial + administrator account. + If you use an external OIDC provider, these details need to match with your desired OIDC + account +

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ break; + + case 2: +
+ +
+ +
+

You are all set!

+

+ You are now ready to finish the initial setup. + The configured options will be applied to the instance. + You will be redirected to the login after changes have been applied successfully +

+
+ break; + } + +
+
+ @for (var step = 0; step < StepCount; step++) + { + if (step == CurrentStep) + { +
+
+ } + else + { +
+
+ } + } +
+
+ @if (CurrentStep > 0) + { + + } + else if (CurrentStep != StepCount - 1) + { + + } + else + { + + } +
+
+
+ } + else + { +
+ +
+ } +
+
+ +@code +{ + private bool IsLoaded; + + private int CurrentStep; + private readonly int StepCount = 3; + + private readonly ApplySetupDto SetupDto = new(); + + private void Navigate(int diff) + { + CurrentStep += diff; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (!firstRender) + return; + + var response = await HttpClient.GetAsync("api/admin/setup"); + + if (!response.IsSuccessStatusCode) + { + Navigation.NavigateTo("/", true); + return; + } + + IsLoaded = true; + await InvokeAsync(StateHasChanged); + } + + private async Task ApplyAsync() + { + await HttpClient.PostAsJsonAsync("api/admin/setup", SetupDto); + Navigation.NavigateTo("/", true); + } +} \ No newline at end of file diff --git a/Moonlight.Frontend/Mappers/ApiKeyMapper.cs b/Moonlight.Frontend/Admin/Sys/ApiKeys/ApiKeyMapper.cs similarity index 71% rename from Moonlight.Frontend/Mappers/ApiKeyMapper.cs rename to Moonlight.Frontend/Admin/Sys/ApiKeys/ApiKeyMapper.cs index b1bb2ad6..d0f424d8 100644 --- a/Moonlight.Frontend/Mappers/ApiKeyMapper.cs +++ b/Moonlight.Frontend/Admin/Sys/ApiKeys/ApiKeyMapper.cs @@ -1,9 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.Admin.ApiKeys; -using Moonlight.Shared.Http.Responses.Admin.ApiKeys; +using Moonlight.Shared.Admin.Sys.ApiKeys; using Riok.Mapperly.Abstractions; -namespace Moonlight.Frontend.Mappers; +namespace Moonlight.Frontend.Admin.Sys.ApiKeys; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor b/Moonlight.Frontend/Admin/Sys/ApiKeys/CreateApiKeyDialog.razor similarity index 86% rename from Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor rename to Moonlight.Frontend/Admin/Sys/ApiKeys/CreateApiKeyDialog.razor index 6452d584..9b54f34d 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor +++ b/Moonlight.Frontend/Admin/Sys/ApiKeys/CreateApiKeyDialog.razor @@ -1,8 +1,7 @@ -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.ApiKeys -@using Moonlight.Shared.Http.Responses +@using Moonlight.Frontend.Admin.Users.Shared +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys.ApiKeys @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @@ -26,7 +25,7 @@ - +
Name @@ -34,11 +33,12 @@ Description - + Valid until - + Permissions @@ -59,11 +59,11 @@ private CreateApiKeyDto Request; - private List Permissions = new(); + private readonly List Permissions = []; protected override void OnInitialized() { - Request = new() + Request = new CreateApiKeyDto { Permissions = [], ValidUntil = DateTimeOffset.UtcNow @@ -74,13 +74,13 @@ { Request.Permissions = Permissions.ToArray(); Request.ValidUntil = Request.ValidUntil.ToUniversalTime(); - + var response = await HttpClient.PostAsJsonAsync( "/api/admin/apiKeys", Request, SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); @@ -88,7 +88,7 @@ } await ToastService.SuccessAsync( - "API Key creation", + "API Key Creation", $"Successfully created API key {Request.Name}" ); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor b/Moonlight.Frontend/Admin/Sys/ApiKeys/Index.razor similarity index 89% rename from Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor rename to Moonlight.Frontend/Admin/Sys/ApiKeys/Index.razor index 6ce7ec0d..6501aa84 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor +++ b/Moonlight.Frontend/Admin/Sys/ApiKeys/Index.razor @@ -1,19 +1,17 @@ @using LucideBlazor @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization -@using Moonlight.Frontend.UI.Admin.Modals +@using Moonlight.Frontend.Infrastructure.Helpers @using Moonlight.Shared -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Admin.ApiKeys +@using Moonlight.Shared.Admin.Sys.ApiKeys +@using Moonlight.Shared.Shared +@using ShadcnBlazor.Buttons @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Extras.AlertDialogs @using ShadcnBlazor.Extras.Dialogs -@using ShadcnBlazor.Tabels -@using ShadcnBlazor.Buttons @using ShadcnBlazor.Extras.Toasts +@using ShadcnBlazor.Tabels @inject ToastService ToastService @inject DialogService DialogService @@ -49,15 +47,17 @@ - + Identifier="@nameof(ApiKeyDto.Description)" Field="k => k.Description" + HeadClassName="hidden lg:table-cell" CellClassName="hidden lg:table-cell"/> + @{ var diff = context.ValidUntil - DateTimeOffset.UtcNow; var text = string.Format(diff.TotalSeconds < 0 ? "Expired since {0}" : "Expires in {0}", Formatter.FormatDuration(diff)); } - + @text @@ -78,7 +78,8 @@ - + Edit @@ -104,9 +105,9 @@ @code { [CascadingParameter] public Task AuthState { get; set; } - + private DataGrid Grid; - + private AuthorizationResult EditAccess; private AuthorizationResult DeleteAccess; private AuthorizationResult CreateAccess; @@ -114,7 +115,7 @@ protected override async Task OnInitializedAsync() { var authState = await AuthState; - + EditAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.ApiKeys.Edit); DeleteAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.ApiKeys.Delete); CreateAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.ApiKeys.Create); @@ -135,13 +136,7 @@ private async Task CreateAsync() { - await DialogService.LaunchAsync(parameters => - { - parameters[nameof(CreateApiKeyDialog.OnSubmit)] = async () => - { - await Grid.RefreshAsync(); - }; - }); + await DialogService.LaunchAsync(parameters => { parameters[nameof(CreateApiKeyDialog.OnSubmit)] = async () => { await Grid.RefreshAsync(); }; }); } private async Task EditAsync(ApiKeyDto key) @@ -149,10 +144,7 @@ await DialogService.LaunchAsync(parameters => { parameters[nameof(UpdateApiKeyDialog.Key)] = key; - parameters[nameof(UpdateApiKeyDialog.OnSubmit)] = async () => - { - await Grid.RefreshAsync(); - }; + parameters[nameof(UpdateApiKeyDialog.OnSubmit)] = async () => { await Grid.RefreshAsync(); }; }); } diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor b/Moonlight.Frontend/Admin/Sys/ApiKeys/UpdateApiKeyDialog.razor similarity index 87% rename from Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor rename to Moonlight.Frontend/Admin/Sys/ApiKeys/UpdateApiKeyDialog.razor index 7b4995fb..d53ad01c 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor +++ b/Moonlight.Frontend/Admin/Sys/ApiKeys/UpdateApiKeyDialog.razor @@ -1,9 +1,7 @@ -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.Mappers -@using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.ApiKeys -@using Moonlight.Shared.Http.Responses.Admin.ApiKeys +@using Moonlight.Frontend.Admin.Users.Shared +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys.ApiKeys @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @@ -34,11 +32,12 @@ Description - + Valid until - + Permissions @@ -71,13 +70,13 @@ { Request.Permissions = Permissions.ToArray(); Request.ValidUntil = Request.ValidUntil.ToUniversalTime(); - + var response = await HttpClient.PatchAsJsonAsync( $"/api/admin/apiKeys/{Key.Id}", Request, SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); @@ -85,10 +84,10 @@ } await ToastService.SuccessAsync( - "API Key update", + "API Key Update", $"Successfully updated API key {Request.Name}" ); - + await OnSubmit.Invoke(); await CloseAsync(); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/Admin/Sys/ContainerHelper/Index.razor similarity index 97% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor rename to Moonlight.Frontend/Admin/Sys/ContainerHelper/Index.razor index 7a4f00d8..b572db95 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor +++ b/Moonlight.Frontend/Admin/Sys/ContainerHelper/Index.razor @@ -1,16 +1,15 @@ @using LucideBlazor -@using Moonlight.Frontend.UI.Admin.Modals -@using Moonlight.Shared.Http.Responses.Admin +@using Moonlight.Shared.Admin.Sys.ContainerHelper +@using Moonlight.Shared.Admin.Sys.Versions +@using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards @using ShadcnBlazor.Emptys -@using ShadcnBlazor.Buttons @using ShadcnBlazor.Extras.AlertDialogs @using ShadcnBlazor.Extras.Common @using ShadcnBlazor.Extras.Dialogs @using ShadcnBlazor.Fields @using ShadcnBlazor.Selects @using ShadcnBlazor.Switches - @inject HttpClient HttpClient @inject DialogService DialogService @inject AlertDialogService AlertDialogService @@ -43,10 +42,10 @@ if (version.IsDevelopment) displayName += " (dev)"; - + if (version.IsPreRelease) displayName += " (beta)"; - + @displayName @@ -123,10 +122,10 @@ @code { - private ContainerHelperStatusDto StatusDto; private string SelectedVersion = "v2.1"; private bool NoBuildCache; - + + private ContainerHelperStatusDto StatusDto; private VersionDto[] Versions; private async Task LoadAsync(LazyLoader _) @@ -137,7 +136,7 @@ if (currentVersion != null) SelectedVersion = currentVersion.Identifier; - + Versions = (await HttpClient.GetFromJsonAsync("api/admin/versions"))!; } @@ -149,7 +148,7 @@ parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; parameters[nameof(UpdateInstanceModal.NoBuildCache)] = NoBuildCache; }, - onConfigure: model => + model => { model.ShowCloseButton = false; model.ClassName = "sm:max-w-4xl!"; diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/Admin/Sys/ContainerHelper/UpdateInstanceModal.razor similarity index 97% rename from Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor rename to Moonlight.Frontend/Admin/Sys/ContainerHelper/UpdateInstanceModal.razor index dc294f4a..41c26e55 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/Admin/Sys/ContainerHelper/UpdateInstanceModal.razor @@ -1,10 +1,7 @@ -@inherits ShadcnBlazor.Extras.Dialogs.DialogBase - @using System.Text.Json @using LucideBlazor -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Events -@using Moonlight.Shared.Http.Requests.Admin.ContainerHelper +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys.ContainerHelper @using ShadcnBlazor.Buttons @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Progresses @@ -12,6 +9,8 @@ @inject HttpClient HttpClient +@inherits ShadcnBlazor.Extras.Dialogs.DialogBase + Updating instance to @Version... @@ -121,7 +120,7 @@ else Progress = 20; await InvokeAsync(StateHasChanged); - await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto() + await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto { Version = Version }, SerializationContext.Default.Options); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor b/Moonlight.Frontend/Admin/Sys/Diagnose.razor similarity index 98% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor rename to Moonlight.Frontend/Admin/Sys/Diagnose.razor index f6433df8..538c146f 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor +++ b/Moonlight.Frontend/Admin/Sys/Diagnose.razor @@ -2,7 +2,7 @@ @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Moonlight.Shared -@using Moonlight.Shared.Http.Responses.Admin +@using Moonlight.Shared.Admin.Sys.Diagnose @using ShadcnBlazor.Accordions @using ShadcnBlazor.Alerts @using ShadcnBlazor.Buttons @@ -223,15 +223,15 @@ [CascadingParameter] public Task AuthState { get; set; } private AuthorizationResult AccessResult; - - private bool IsLoading = false; - private bool HasDiagnosed = false; + + private bool IsLoading; + private bool HasDiagnosed; private DiagnoseResultDto[] Entries; protected override async Task OnInitializedAsync() { var authState = await AuthState; - + AccessResult = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.System.Diagnose); } diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor b/Moonlight.Frontend/Admin/Sys/Index.razor similarity index 91% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor rename to Moonlight.Frontend/Admin/Sys/Index.razor index 78a53dd6..86da0918 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor +++ b/Moonlight.Frontend/Admin/Sys/Index.razor @@ -1,5 +1,4 @@ @page "/admin/system" - @using LucideBlazor @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @@ -12,7 +11,7 @@ - + Settings @@ -35,31 +34,31 @@ @if (SettingsResult.Succeeded) { - + < } @if (DiagnoseResult.Succeeded) { - + } @if (ApiKeyAccess.Succeeded) { - + } @if (ThemesAccess.Succeeded) { - + } @if (InstanceResult.Succeeded && VersionsResult.Succeeded) { - + } @@ -69,7 +68,7 @@ [SupplyParameterFromQuery(Name = "tab")] [Parameter] public string? Tab { get; set; } - + [CascadingParameter] public Task AuthState { get; set; } private AuthorizationResult ApiKeyAccess; @@ -78,7 +77,7 @@ private AuthorizationResult VersionsResult; private AuthorizationResult SettingsResult; private AuthorizationResult DiagnoseResult; - + protected override async Task OnInitializedAsync() { var authState = await AuthState; diff --git a/Moonlight.Frontend/UI/Admin/Views/Overview.razor b/Moonlight.Frontend/Admin/Sys/Overview.razor similarity index 94% rename from Moonlight.Frontend/UI/Admin/Views/Overview.razor rename to Moonlight.Frontend/Admin/Sys/Overview.razor index 57a0a4ab..a9901188 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Overview.razor +++ b/Moonlight.Frontend/Admin/Sys/Overview.razor @@ -1,15 +1,14 @@ @page "/admin" + @using LucideBlazor -@using Moonlight.Frontend.UI.Admin.Modals -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Responses.Admin +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys @using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards -@using ShadcnBlazor.Extras.Dialogs @using ShadcnBlazor.Spinners @inject HttpClient HttpClient -@inject DialogService DialogService

Overview

@@ -30,12 +29,12 @@ CPU Usage @Math.Round(InfoResponse.CpuUsage, 2)% - + } - + @if (IsInfoLoading || InfoResponse == null) { @@ -49,12 +48,12 @@ Memory Usage @Formatter.FormatSize(InfoResponse.MemoryUsage) - + } - + @if (IsInfoLoading || InfoResponse == null) { @@ -68,12 +67,12 @@ Operating System @InfoResponse.OperatingSystem - + } - + @if (IsInfoLoading || InfoResponse == null) { @@ -87,12 +86,12 @@ Uptime @Formatter.FormatDuration(InfoResponse.Uptime) - + } - + @if (IsInfoLoading || InfoResponse == null) { @@ -106,12 +105,12 @@ Version @InfoResponse.VersionName - + } - + @if (IsInfoLoading || InfoResponse == null) { @@ -127,7 +126,7 @@ { Up-to-date - + } else @@ -153,7 +152,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { - if(!firstRender) + if (!firstRender) return; InfoResponse = await HttpClient.GetFromJsonAsync("api/admin/system/info", SerializationContext.Default.Options); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Settings.razor b/Moonlight.Frontend/Admin/Sys/Settings/Index.razor similarity index 89% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Settings.razor rename to Moonlight.Frontend/Admin/Sys/Settings/Index.razor index 79d3f66a..cf136001 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Settings.razor +++ b/Moonlight.Frontend/Admin/Sys/Settings/Index.razor @@ -1,8 +1,6 @@ @using Microsoft.Extensions.Options -@using Moonlight.Frontend.Configuration @using ShadcnBlazor.Cards @using ShadcnBlazor.Sidebars - @inject IOptions Options
@@ -10,8 +8,9 @@ @foreach (var menuPage in Pages) { - - + + @menuPage.Name } @@ -25,7 +24,7 @@ @CurrentPage.Description - + } @@ -48,5 +47,7 @@ } private void Navigate(SystemSettingsPage page) - => CurrentPage = page; + { + CurrentPage = page; + } } \ No newline at end of file diff --git a/Moonlight.Frontend/Admin/Sys/Settings/SystemSettingsOptions.cs b/Moonlight.Frontend/Admin/Sys/Settings/SystemSettingsOptions.cs new file mode 100644 index 00000000..14e379f1 --- /dev/null +++ b/Moonlight.Frontend/Admin/Sys/Settings/SystemSettingsOptions.cs @@ -0,0 +1,52 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Components; + +namespace Moonlight.Frontend.Admin.Sys.Settings; + +public class SystemSettingsOptions +{ + public IReadOnlyList Components => InnerComponents; + + private readonly List InnerComponents = []; + + public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TIcon, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + TComponent>(string name, string description, + int order + ) where TIcon : ComponentBase where TComponent : ComponentBase + { + Add(name, description, order, typeof(TIcon), typeof(TComponent)); + } + + public void Add( + string name, + string description, + int order, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + Type iconComponent, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + Type component + ) + { + InnerComponents.Add(new SystemSettingsPage(name, description, order, iconComponent, component)); + } + + public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TComponent>() + where TComponent : ComponentBase + { + Remove(typeof(TComponent)); + } + + public void Remove([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type componentType) + { + InnerComponents.RemoveAll(x => x.ComponentType == componentType); + } +} + +public record SystemSettingsPage( + string Name, + string Description, + int Order, + Type IconComponentType, + Type ComponentType +); \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Settings/WhiteLabelingSetting.razor b/Moonlight.Frontend/Admin/Sys/Settings/WhiteLabelingSetting.razor similarity index 83% rename from Moonlight.Frontend/UI/Admin/Settings/WhiteLabelingSetting.razor rename to Moonlight.Frontend/Admin/Sys/Settings/WhiteLabelingSetting.razor index 270416d3..38f0020a 100644 --- a/Moonlight.Frontend/UI/Admin/Settings/WhiteLabelingSetting.razor +++ b/Moonlight.Frontend/Admin/Sys/Settings/WhiteLabelingSetting.razor @@ -1,9 +1,8 @@ @using LucideBlazor -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.Services -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.Settings -@using Moonlight.Shared.Http.Responses.Admin.Settings +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Frontend.Shared.Frontend +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys.Settings @using ShadcnBlazor.Extras.Common @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @@ -16,11 +15,11 @@ - - + +
- - + + Name @@ -46,8 +45,8 @@ "api/admin/system/settings/whiteLabeling", SerializationContext.Default.Options ); - - Request = new SetWhiteLabelingDto() + + Request = new SetWhiteLabelingDto { Name = dto!.Name }; @@ -65,7 +64,7 @@ { await FrontendService.ReloadAsync(); await ToastService.SuccessAsync("Setting", "Successfully updated white labeling settings"); - + return true; } diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor b/Moonlight.Frontend/Admin/Sys/Themes/Create.razor similarity index 95% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor rename to Moonlight.Frontend/Admin/Sys/Themes/Create.razor index 35e38e6e..cb0301df 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor +++ b/Moonlight.Frontend/Admin/Sys/Themes/Create.razor @@ -1,12 +1,11 @@ @page "/admin/system/themes/create" -@using Microsoft.AspNetCore.Authorization -@using Moonlight.Shared @using LucideBlazor -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.Services -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.Themes +@using Microsoft.AspNetCore.Authorization +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Frontend.Shared.Frontend +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys.Themes @using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards @using ShadcnBlazor.Extras.Editors @@ -109,7 +108,7 @@ @code { - private CreateThemeDto Request = new() + private readonly CreateThemeDto Request = new() { CssContent = "/* Define your css here */" }; @@ -125,7 +124,7 @@ Request, SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor b/Moonlight.Frontend/Admin/Sys/Themes/Index.razor similarity index 98% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor rename to Moonlight.Frontend/Admin/Sys/Themes/Index.razor index 7a434892..727ba033 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor +++ b/Moonlight.Frontend/Admin/Sys/Themes/Index.razor @@ -2,16 +2,14 @@ @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Moonlight.Shared -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Admin.Themes +@using Moonlight.Shared.Admin.Sys.Themes +@using Moonlight.Shared.Shared +@using ShadcnBlazor.Buttons @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Extras.AlertDialogs -@using ShadcnBlazor.Tabels -@using ShadcnBlazor.Buttons @using ShadcnBlazor.Extras.Toasts +@using ShadcnBlazor.Tabels @inject ToastService ToastService @inject NavigationManager Navigation diff --git a/Moonlight.Frontend/Mappers/ThemeMapper.cs b/Moonlight.Frontend/Admin/Sys/Themes/ThemeMapper.cs similarity index 64% rename from Moonlight.Frontend/Mappers/ThemeMapper.cs rename to Moonlight.Frontend/Admin/Sys/Themes/ThemeMapper.cs index 2e1747e7..4dacad70 100644 --- a/Moonlight.Frontend/Mappers/ThemeMapper.cs +++ b/Moonlight.Frontend/Admin/Sys/Themes/ThemeMapper.cs @@ -1,14 +1,13 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.Admin.Themes; -using Moonlight.Shared.Http.Responses.Admin.Themes; +using Moonlight.Shared.Admin.Sys.Themes; using Riok.Mapperly.Abstractions; -namespace Moonlight.Frontend.Mappers; +namespace Moonlight.Frontend.Admin.Sys.Themes; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] [SuppressMessage("Mapper", "RMG012:No members are mapped in an object mapping")] -public partial class ThemeMapper +public static partial class ThemeMapper { public static partial UpdateThemeDto ToUpdate(ThemeDto theme); } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor b/Moonlight.Frontend/Admin/Sys/Themes/Update.razor similarity index 95% rename from Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor rename to Moonlight.Frontend/Admin/Sys/Themes/Update.razor index 8ac377b5..9df311e8 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor +++ b/Moonlight.Frontend/Admin/Sys/Themes/Update.razor @@ -1,14 +1,11 @@ @page "/admin/system/themes/{Id:int}" -@using Microsoft.AspNetCore.Authorization -@using Moonlight.Shared @using LucideBlazor -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.Mappers -@using Moonlight.Frontend.Services -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.Themes -@using Moonlight.Shared.Http.Responses.Admin.Themes +@using Microsoft.AspNetCore.Authorization +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Frontend.Shared.Frontend +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Sys.Themes @using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards @using ShadcnBlazor.Extras.Common @@ -139,7 +136,7 @@ Request, SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Index.razor b/Moonlight.Frontend/Admin/Users/Index.razor similarity index 77% rename from Moonlight.Frontend/UI/Admin/Views/Users/Index.razor rename to Moonlight.Frontend/Admin/Users/Index.razor index 0578535a..e8a507ed 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Index.razor +++ b/Moonlight.Frontend/Admin/Users/Index.razor @@ -1,6 +1,8 @@ @page "/admin/users" @using LucideBlazor @using Microsoft.AspNetCore.Authorization +@using Moonlight.Frontend.Admin.Users.Roles +@using Moonlight.Frontend.Admin.Users.Users @using Moonlight.Shared @using ShadcnBlazor.Tab @@ -11,19 +13,19 @@ - + Users - + Roles - + - + @@ -37,4 +39,4 @@ { Navigation.NavigateTo($"/admin/users?tab={name}"); } -} +} \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor b/Moonlight.Frontend/Admin/Users/Roles/CreateRoleDialog.razor similarity index 89% rename from Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor rename to Moonlight.Frontend/Admin/Users/Roles/CreateRoleDialog.razor index 442befdb..6a8bc2d4 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor +++ b/Moonlight.Frontend/Admin/Users/Roles/CreateRoleDialog.razor @@ -1,7 +1,7 @@ -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.Roles +@using Moonlight.Frontend.Admin.Users.Shared +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Users.Roles @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @@ -62,31 +62,31 @@ protected override void OnInitialized() { - Request = new() + Request = new CreateRoleDto { Permissions = [] }; - Permissions = new(); + Permissions = []; } private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); - + var response = await HttpClient.PostAsJsonAsync( "api/admin/roles", Request, SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); return false; } - await ToastService.SuccessAsync("Role creation", $"Role {Request.Name} has been successfully created"); + await ToastService.SuccessAsync("Role Creation", $"Role {Request.Name} has been successfully created"); await OnSubmit.Invoke(); await CloseAsync(); diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor b/Moonlight.Frontend/Admin/Users/Roles/Index.razor similarity index 91% rename from Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor rename to Moonlight.Frontend/Admin/Users/Roles/Index.razor index a6cb1a53..a6781636 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor +++ b/Moonlight.Frontend/Admin/Users/Roles/Index.razor @@ -1,14 +1,11 @@ @using LucideBlazor @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization -@using Moonlight.Frontend.UI.Admin.Modals @using Moonlight.Shared -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Admin -@using ShadcnBlazor.DataGrids +@using Moonlight.Shared.Admin.Users.Roles +@using Moonlight.Shared.Shared @using ShadcnBlazor.Buttons +@using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Extras.AlertDialogs @using ShadcnBlazor.Extras.Dialogs @@ -67,13 +64,15 @@ - + Members - + Edit @@ -99,7 +98,7 @@ @code { [CascadingParameter] public Task AuthState { get; set; } - + private DataGrid Grid; private AuthorizationResult MembersAccess; @@ -110,7 +109,7 @@ protected override async Task OnInitializedAsync() { var authState = await AuthState; - + MembersAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Roles.Members); EditAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Roles.Edit); DeleteAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Roles.Delete); @@ -132,13 +131,7 @@ private async Task CreateAsync() { - await DialogService.LaunchAsync(parameters => - { - parameters[nameof(CreateRoleDialog.OnSubmit)] = async Task () => - { - await Grid.RefreshAsync(); - }; - }); + await DialogService.LaunchAsync(parameters => { parameters[nameof(CreateRoleDialog.OnSubmit)] = async Task () => { await Grid.RefreshAsync(); }; }); } private async Task EditAsync(RoleDto role) @@ -146,10 +139,7 @@ await DialogService.LaunchAsync(parameters => { parameters[nameof(UpdateRoleDialog.Role)] = role; - parameters[nameof(UpdateRoleDialog.OnSubmit)] = async Task () => - { - await Grid.RefreshAsync(); - }; + parameters[nameof(UpdateRoleDialog.OnSubmit)] = async Task () => { await Grid.RefreshAsync(); }; }); } @@ -160,7 +150,7 @@ await ToastService.ErrorAsync("Permission denied", "You dont have the required permission to manage members"); return; } - + await DialogService.LaunchAsync(parameters => { parameters[nameof(ManageRoleMembersDialog.Role)] = role; }, model => { model.ClassName = "sm:max-w-xl"; }); } @@ -173,7 +163,7 @@ { var response = await HttpClient.DeleteAsync($"api/admin/roles/{role.Id}"); response.EnsureSuccessStatusCode(); - + await ToastService.SuccessAsync("User deletion", $"Successfully deleted role {role.Name}"); await Grid.RefreshAsync(); diff --git a/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor b/Moonlight.Frontend/Admin/Users/Roles/ManageRoleMembersDialog.razor similarity index 89% rename from Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor rename to Moonlight.Frontend/Admin/Users/Roles/ManageRoleMembersDialog.razor index 403d9c3f..84c42c4c 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor +++ b/Moonlight.Frontend/Admin/Users/Roles/ManageRoleMembersDialog.razor @@ -1,7 +1,8 @@ @using LucideBlazor -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Admin -@using Moonlight.Shared.Http.Responses.Admin.Users +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Users.Roles +@using Moonlight.Shared.Admin.Users.Users +@using Moonlight.Shared.Shared @using ShadcnBlazor.Buttons @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dialogs @@ -10,10 +11,10 @@ @using ShadcnBlazor.Labels @using ShadcnBlazor.Tabels -@inherits ShadcnBlazor.Extras.Dialogs.DialogBase - @inject HttpClient HttpClient +@inherits ShadcnBlazor.Extras.Dialogs.DialogBase + Manage members of @Role.Name @@ -50,7 +51,8 @@
- +
@@ -75,7 +77,8 @@ query += $"&searchTerm={request.SearchTerm}"; var response = await HttpClient.GetFromJsonAsync>( - $"api/admin/roles/{Role.Id}/members{query}" + $"api/admin/roles/{Role.Id}/members{query}", + SerializationContext.Default.Options ); return new DataGridResponse(response!.Data, response.TotalLength); @@ -89,7 +92,8 @@ query += $"&searchTerm={searchTerm}"; var response = await HttpClient.GetFromJsonAsync>( - $"api/admin/roles/{Role.Id}/members/available{query}" + $"api/admin/roles/{Role.Id}/members/available{query}", + SerializationContext.Default.Options ); return response!.Data; diff --git a/Moonlight.Frontend/Mappers/RoleMapper.cs b/Moonlight.Frontend/Admin/Users/Roles/RoleMapper.cs similarity index 72% rename from Moonlight.Frontend/Mappers/RoleMapper.cs rename to Moonlight.Frontend/Admin/Users/Roles/RoleMapper.cs index 4c4861f1..924b36bd 100644 --- a/Moonlight.Frontend/Mappers/RoleMapper.cs +++ b/Moonlight.Frontend/Admin/Users/Roles/RoleMapper.cs @@ -1,9 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.Admin.Roles; -using Moonlight.Shared.Http.Responses.Admin; +using Moonlight.Shared.Admin.Users.Roles; using Riok.Mapperly.Abstractions; -namespace Moonlight.Frontend.Mappers; +namespace Moonlight.Frontend.Admin.Users.Roles; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor b/Moonlight.Frontend/Admin/Users/Roles/UpdateRoleDialog.razor similarity index 91% rename from Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor rename to Moonlight.Frontend/Admin/Users/Roles/UpdateRoleDialog.razor index f53b792b..102c83dc 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor +++ b/Moonlight.Frontend/Admin/Users/Roles/UpdateRoleDialog.razor @@ -1,9 +1,7 @@ -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.Mappers -@using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.Roles -@using Moonlight.Shared.Http.Responses.Admin +@using Moonlight.Frontend.Admin.Users.Shared +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Users.Roles @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @@ -72,13 +70,13 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); - + var response = await HttpClient.PatchAsJsonAsync( $"api/admin/roles/{Role.Id}", Request, SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); @@ -86,7 +84,7 @@ } await ToastService.SuccessAsync("Role update", $"Role {Request.Name} has been successfully updated"); - + await OnSubmit.Invoke(); await CloseAsync(); diff --git a/Moonlight.Frontend/Models/Permission.cs b/Moonlight.Frontend/Admin/Users/Shared/Permission.cs similarity index 80% rename from Moonlight.Frontend/Models/Permission.cs rename to Moonlight.Frontend/Admin/Users/Shared/Permission.cs index cce3d96f..6417c906 100644 --- a/Moonlight.Frontend/Models/Permission.cs +++ b/Moonlight.Frontend/Admin/Users/Shared/Permission.cs @@ -1,17 +1,15 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Moonlight.Frontend.Models; +namespace Moonlight.Frontend.Admin.Users.Shared; public class Permission { - public string Identifier { get; init; } - public string Name { get; init; } - public string Description { get; init; } - public Permission(string identifier, string name, string description) { Identifier = identifier; Name = name; Description = description; } + + public string Identifier { get; init; } + public string Name { get; init; } + public string Description { get; init; } } \ No newline at end of file diff --git a/Moonlight.Frontend/Models/PermissionCategory.cs b/Moonlight.Frontend/Admin/Users/Shared/PermissionCategory.cs similarity index 91% rename from Moonlight.Frontend/Models/PermissionCategory.cs rename to Moonlight.Frontend/Admin/Users/Shared/PermissionCategory.cs index 1004d835..cc92ba9f 100644 --- a/Moonlight.Frontend/Models/PermissionCategory.cs +++ b/Moonlight.Frontend/Admin/Users/Shared/PermissionCategory.cs @@ -1,21 +1,22 @@ using System.Diagnostics.CodeAnalysis; -namespace Moonlight.Frontend.Models; +namespace Moonlight.Frontend.Admin.Users.Shared; public record PermissionCategory { - public string Name { get; init; } - - // Used to prevent the IL-Trimming from removing this type as its dynamically assigned a type, and we - // need it to work properly - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] - public Type Icon { get; init; } - public Permission[] Permissions { get; init; } - public PermissionCategory(string name, Type icon, Permission[] permissions) { Name = name; Icon = icon; Permissions = permissions; } + + public string Name { get; init; } + + // Used to prevent the IL-Trimming from removing this type as its dynamically assigned a type, and we + // need it to work properly + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] + public Type Icon { get; init; } + + public Permission[] Permissions { get; init; } } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Components/PermissionSelector.razor b/Moonlight.Frontend/Admin/Users/Shared/PermissionSelector.razor similarity index 97% rename from Moonlight.Frontend/UI/Admin/Components/PermissionSelector.razor rename to Moonlight.Frontend/Admin/Users/Shared/PermissionSelector.razor index acd92c04..f1a5bea5 100644 --- a/Moonlight.Frontend/UI/Admin/Components/PermissionSelector.razor +++ b/Moonlight.Frontend/Admin/Users/Shared/PermissionSelector.razor @@ -1,8 +1,7 @@ -@using Moonlight.Frontend.Interfaces -@using Moonlight.Frontend.Models -@using ShadcnBlazor.Extras.Common +@using Moonlight.Frontend.Infrastructure.Hooks @using ShadcnBlazor.Accordions @using ShadcnBlazor.Checkboxes +@using ShadcnBlazor.Extras.Common @using ShadcnBlazor.Labels @inject IEnumerable Providers diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor b/Moonlight.Frontend/Admin/Users/Users/CreateUserDialog.razor similarity index 91% rename from Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor rename to Moonlight.Frontend/Admin/Users/Users/CreateUserDialog.razor index 4cff020f..d197931d 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor +++ b/Moonlight.Frontend/Admin/Users/Users/CreateUserDialog.razor @@ -1,17 +1,16 @@ -@using Moonlight.Frontend.Helpers -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Requests.Admin.Users -@using Moonlight.Shared.Http.Responses +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Users.Users @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@inherits ShadcnBlazor.Extras.Dialogs.DialogBase - -@inject HttpClient HttpClient @inject ToastService ToastService +@inject HttpClient HttpClient + +@inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -26,7 +25,7 @@ - +
@@ -58,7 +57,7 @@ protected override void OnInitialized() { - Request = new(); + Request = new CreateUserDto(); } private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor b/Moonlight.Frontend/Admin/Users/Users/Index.razor similarity index 92% rename from Moonlight.Frontend/UI/Admin/Views/Users/Users.razor rename to Moonlight.Frontend/Admin/Users/Users/Index.razor index 69e4c6b3..1d3d43a7 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor +++ b/Moonlight.Frontend/Admin/Users/Users/Index.razor @@ -1,19 +1,16 @@ @using LucideBlazor @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization -@using Moonlight.Frontend.UI.Admin.Modals @using Moonlight.Shared -@using Moonlight.Shared.Http +@using Moonlight.Shared.Admin.Users.Users +@using Moonlight.Shared.Shared @using ShadcnBlazor.Buttons @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Extras.AlertDialogs +@using ShadcnBlazor.Extras.Dialogs @using ShadcnBlazor.Extras.Toasts @using ShadcnBlazor.Tabels -@using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Admin.Users -@using ShadcnBlazor.Extras.Dialogs @inject HttpClient HttpClient @inject AlertDialogService AlertDialogService @@ -65,13 +62,15 @@ - + Logout - + Edit @@ -97,9 +96,9 @@ @code { [CascadingParameter] public Task AuthState { get; set; } - + private DataGrid Grid; - + private AuthorizationResult LogoutAccess; private AuthorizationResult EditAccess; private AuthorizationResult DeleteAccess; @@ -108,7 +107,7 @@ protected override async Task OnInitializedAsync() { var authState = await AuthState; - + LogoutAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Users.Logout); EditAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Users.Edit); DeleteAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Users.Delete); @@ -130,13 +129,7 @@ private async Task CreateAsync() { - await DialogService.LaunchAsync(parameters => - { - parameters[nameof(CreateUserDialog.OnCompleted)] = async () => - { - await Grid.RefreshAsync(); - }; - }); + await DialogService.LaunchAsync(parameters => { parameters[nameof(CreateUserDialog.OnCompleted)] = async () => { await Grid.RefreshAsync(); }; }); } private async Task EditAsync(UserDto user) @@ -144,10 +137,7 @@ await DialogService.LaunchAsync(parameters => { parameters[nameof(UpdateUserDialog.User)] = user; - parameters[nameof(UpdateUserDialog.OnCompleted)] = async () => - { - await Grid.RefreshAsync(); - }; + parameters[nameof(UpdateUserDialog.OnCompleted)] = async () => { await Grid.RefreshAsync(); }; }); } diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor b/Moonlight.Frontend/Admin/Users/Users/UpdateUserDialog.razor similarity index 90% rename from Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor rename to Moonlight.Frontend/Admin/Users/Users/UpdateUserDialog.razor index f23a2ec7..f25dac09 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor +++ b/Moonlight.Frontend/Admin/Users/Users/UpdateUserDialog.razor @@ -1,14 +1,11 @@ -@using Moonlight.Frontend.Helpers -@using Moonlight.Frontend.Mappers -@using Moonlight.Shared.Http.Requests.Admin.Users -@using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Admin.Users +@using Moonlight.Frontend.Infrastructure.Helpers +@using Moonlight.Shared +@using Moonlight.Shared.Admin.Users.Users @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts @using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs - @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @inject HttpClient HttpClient @@ -66,9 +63,10 @@ { var response = await HttpClient.PatchAsJsonAsync( $"/api/admin/users/{User.Id}", - Request + Request, + SerializationContext.Default.Options ); - + if (!response.IsSuccessStatusCode) { await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); @@ -79,7 +77,7 @@ "User update", $"Successfully updated user {Request.Username}" ); - + await OnCompleted.Invoke(); await CloseAsync(); diff --git a/Moonlight.Frontend/Mappers/UserMapper.cs b/Moonlight.Frontend/Admin/Users/Users/UserMapper.cs similarity index 71% rename from Moonlight.Frontend/Mappers/UserMapper.cs rename to Moonlight.Frontend/Admin/Users/Users/UserMapper.cs index c20a8c8f..375d844f 100644 --- a/Moonlight.Frontend/Mappers/UserMapper.cs +++ b/Moonlight.Frontend/Admin/Users/Users/UserMapper.cs @@ -1,9 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.Admin.Users; -using Moonlight.Shared.Http.Responses.Admin.Users; +using Moonlight.Shared.Admin.Users.Users; using Riok.Mapperly.Abstractions; -namespace Moonlight.Frontend.Mappers; +namespace Moonlight.Frontend.Admin.Users.Users; [Mapper] [SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] diff --git a/Moonlight.Frontend/UI/User/Views/Index.razor b/Moonlight.Frontend/Client/Index.razor similarity index 100% rename from Moonlight.Frontend/UI/User/Views/Index.razor rename to Moonlight.Frontend/Client/Index.razor diff --git a/Moonlight.Frontend/Configuration/SystemSettingsOptions.cs b/Moonlight.Frontend/Configuration/SystemSettingsOptions.cs deleted file mode 100644 index b5f8bb80..00000000 --- a/Moonlight.Frontend/Configuration/SystemSettingsOptions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Microsoft.AspNetCore.Components; - -namespace Moonlight.Frontend.Configuration; - -public class SystemSettingsOptions -{ - public IReadOnlyList Components => InnerComponents; - - private readonly List InnerComponents = new(); - - public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TIcon, - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TComponent>(string name, string description, - int order) - where TIcon : ComponentBase where TComponent : ComponentBase - => Add(name, description, order, typeof(TIcon), typeof(TComponent)); - - public void Add(string name, string description, int order, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iconComponent, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type component) - => InnerComponents.Add(new SystemSettingsPage(name, description, order, iconComponent, component)); - - public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TComponent>() - where TComponent : ComponentBase - => Remove(typeof(TComponent)); - - public void Remove([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type componentType) - => InnerComponents.RemoveAll(x => x.ComponentType == componentType); -} - -public record SystemSettingsPage( - string Name, - string Description, - int Order, - Type IconComponentType, - Type ComponentType -); \ No newline at end of file diff --git a/Moonlight.Frontend/Implementations/PermissionProvider.cs b/Moonlight.Frontend/Implementations/PermissionProvider.cs deleted file mode 100644 index d3cc7c73..00000000 --- a/Moonlight.Frontend/Implementations/PermissionProvider.cs +++ /dev/null @@ -1,48 +0,0 @@ -using LucideBlazor; -using Moonlight.Frontend.Interfaces; -using Moonlight.Frontend.Models; -using Moonlight.Shared; - -namespace Moonlight.Frontend.Implementations; - -public sealed class PermissionProvider : IPermissionProvider -{ - public Task GetPermissionsAsync() - { - return Task.FromResult([ - new PermissionCategory("Users", typeof(UserRoundIcon), [ - new Permission(Permissions.Users.Create, "Create", "Create new users"), - new Permission(Permissions.Users.View, "View", "View all users"), - new Permission(Permissions.Users.Edit, "Edit", "Edit user details"), - new Permission(Permissions.Users.Delete, "Delete", "Delete user accounts"), - new Permission(Permissions.Users.Logout, "Logout", "Logout user accounts"), - ]), - new PermissionCategory("Roles", typeof(UsersRoundIcon), [ - new Permission(Permissions.Roles.Create, "Create", "Create new roles"), - new Permission(Permissions.Roles.View, "View", "View all roles"), - new Permission(Permissions.Roles.Edit, "Edit", "Edit role details"), - new Permission(Permissions.Roles.Delete, "Delete", "Delete role accounts"), - new Permission(Permissions.Roles.Members, "Members", "Manage role members"), - ]), - new PermissionCategory("System", typeof(CogIcon), [ - new Permission(Permissions.System.Info, "Info", "View system info"), - new Permission(Permissions.System.Diagnose, "Diagnose", "Run diagnostics"), - new Permission(Permissions.System.Versions, "Versions", "Look at the available versions"), - new Permission(Permissions.System.Instance, "Instance", "Update the moonlight instance and add plugins"), - new Permission(Permissions.System.Settings, "Settings", "Change settings of the instance"), - ]), - new PermissionCategory("API Keys", typeof(KeyIcon), [ - new Permission(Permissions.ApiKeys.Create, "Create", "Create new API keys"), - new Permission(Permissions.ApiKeys.View, "View", "View all API keys"), - new Permission(Permissions.ApiKeys.Edit, "Edit", "Edit API key details"), - new Permission(Permissions.ApiKeys.Delete, "Delete", "Delete API keys"), - ]), - new PermissionCategory("Themes", typeof(PaintRollerIcon), [ - new Permission(Permissions.Themes.Create, "Create", "Create new theme"), - new Permission(Permissions.Themes.View, "View", "View all themes"), - new Permission(Permissions.Themes.Edit, "Edit", "Edit themes"), - new Permission(Permissions.Themes.Delete, "Delete", "Delete themes"), - ]), - ]); - } -} \ No newline at end of file diff --git a/Moonlight.Frontend/Configuration/LayoutMiddlewareOptions.cs b/Moonlight.Frontend/Infrastructure/Configuration/LayoutMiddlewareOptions.cs similarity index 71% rename from Moonlight.Frontend/Configuration/LayoutMiddlewareOptions.cs rename to Moonlight.Frontend/Infrastructure/Configuration/LayoutMiddlewareOptions.cs index 53f75ccf..035e9492 100644 --- a/Moonlight.Frontend/Configuration/LayoutMiddlewareOptions.cs +++ b/Moonlight.Frontend/Infrastructure/Configuration/LayoutMiddlewareOptions.cs @@ -1,25 +1,26 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Frontend.Interfaces; +using Moonlight.Frontend.Infrastructure.Hooks; -namespace Moonlight.Frontend.Configuration; +namespace Moonlight.Frontend.Infrastructure.Configuration; public class LayoutMiddlewareOptions { - public IReadOnlyList Components => InnerComponents; - private readonly List InnerComponents = new(); + public IReadOnlyList Components => InnerComponents; public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : LayoutMiddlewareBase { InnerComponents.Add(typeof(T)); } - - public void Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(int index) where T : LayoutMiddlewareBase + + public void Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(int index) + where T : LayoutMiddlewareBase { InnerComponents.Insert(index, typeof(T)); } - public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : LayoutMiddlewareBase + public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() + where T : LayoutMiddlewareBase { InnerComponents.Remove(typeof(T)); } diff --git a/Moonlight.Frontend/Configuration/LayoutPageOptions.cs b/Moonlight.Frontend/Infrastructure/Configuration/LayoutPageOptions.cs similarity index 71% rename from Moonlight.Frontend/Configuration/LayoutPageOptions.cs rename to Moonlight.Frontend/Infrastructure/Configuration/LayoutPageOptions.cs index bc83800e..50fd1802 100644 --- a/Moonlight.Frontend/Configuration/LayoutPageOptions.cs +++ b/Moonlight.Frontend/Infrastructure/Configuration/LayoutPageOptions.cs @@ -1,27 +1,34 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Components; -namespace Moonlight.Frontend.Configuration; +namespace Moonlight.Frontend.Infrastructure.Configuration; public class LayoutPageOptions { - public IReadOnlyList Components => InnerComponents; - private readonly List InnerComponents = new(); + public IReadOnlyList Components => InnerComponents; public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(LayoutPageSlot slot, int order) where T : ComponentBase - => Add(typeof(T), slot, order); - + { + Add(typeof(T), slot, order); + } + public void Add(Type componentType, LayoutPageSlot slot, int order) - => InnerComponents.Add(new LayoutPageComponent(componentType, order, slot)); + { + InnerComponents.Add(new LayoutPageComponent(componentType, order, slot)); + } public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : ComponentBase - => Remove(typeof(T)); + { + Remove(typeof(T)); + } public void Remove(Type componentType) - => InnerComponents.RemoveAll(x => x.ComponentType == componentType); + { + InnerComponents.RemoveAll(x => x.ComponentType == componentType); + } } public record LayoutPageComponent(Type ComponentType, int Order, LayoutPageSlot Slot); diff --git a/Moonlight.Frontend/Configuration/NavigationAssemblyOptions.cs b/Moonlight.Frontend/Infrastructure/Configuration/NavigationAssemblyOptions.cs similarity index 70% rename from Moonlight.Frontend/Configuration/NavigationAssemblyOptions.cs rename to Moonlight.Frontend/Infrastructure/Configuration/NavigationAssemblyOptions.cs index bba1104a..b32a7e35 100644 --- a/Moonlight.Frontend/Configuration/NavigationAssemblyOptions.cs +++ b/Moonlight.Frontend/Infrastructure/Configuration/NavigationAssemblyOptions.cs @@ -1,6 +1,6 @@ using System.Reflection; -namespace Moonlight.Frontend.Configuration; +namespace Moonlight.Frontend.Infrastructure.Configuration; public class NavigationAssemblyOptions { diff --git a/Moonlight.Frontend/Formatter.cs b/Moonlight.Frontend/Infrastructure/Helpers/Formatter.cs similarity index 93% rename from Moonlight.Frontend/Formatter.cs rename to Moonlight.Frontend/Infrastructure/Helpers/Formatter.cs index 6fa70136..ab8ecaf7 100644 --- a/Moonlight.Frontend/Formatter.cs +++ b/Moonlight.Frontend/Infrastructure/Helpers/Formatter.cs @@ -1,44 +1,44 @@ -namespace Moonlight.Frontend; +namespace Moonlight.Frontend.Infrastructure.Helpers; public static class Formatter { public static string FormatSize(long bytes, double conversionStep = 1024) { if (bytes == 0) return "0 B"; - + string[] units = ["B", "KB", "MB", "GB", "TB", "PB", "EB"]; var unitIndex = 0; double size = bytes; - + while (size >= conversionStep && unitIndex < units.Length - 1) { size /= conversionStep; unitIndex++; } - + var decimals = unitIndex == 0 ? 0 : 2; return $"{Math.Round(size, decimals)} {units[unitIndex]}"; } - + public static string FormatDuration(TimeSpan timeSpan) { var abs = timeSpan.Duration(); // Handle negative timespans - + if (abs.TotalSeconds < 1) return $"{abs.TotalMilliseconds:F0}ms"; - + if (abs.TotalMinutes < 1) return $"{abs.TotalSeconds:F1}s"; - + if (abs.TotalHours < 1) return $"{abs.Minutes}m {abs.Seconds}s"; - + if (abs.TotalDays < 1) return $"{abs.Hours}h {abs.Minutes}m"; - + if (abs.TotalDays < 365) return $"{abs.Days}d {abs.Hours}h"; - + var years = (int)(abs.TotalDays / 365); var days = abs.Days % 365; return days > 0 ? $"{years}y {days}d" : $"{years}y"; diff --git a/Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs b/Moonlight.Frontend/Infrastructure/Helpers/ProblemDetailsHelper.cs similarity index 60% rename from Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs rename to Moonlight.Frontend/Infrastructure/Helpers/ProblemDetailsHelper.cs index 0f04d8ba..90e9fad1 100644 --- a/Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs +++ b/Moonlight.Frontend/Infrastructure/Helpers/ProblemDetailsHelper.cs @@ -1,30 +1,29 @@ using System.Net.Http.Json; using Microsoft.AspNetCore.Components.Forms; -using Moonlight.Shared.Http.Responses; +using Moonlight.Shared.Shared; -namespace Moonlight.Frontend.Helpers; +namespace Moonlight.Frontend.Infrastructure.Helpers; public static class ProblemDetailsHelper { - public static async Task HandleProblemDetailsAsync(HttpResponseMessage response, object model, ValidationMessageStore validationMessageStore) + public static async Task HandleProblemDetailsAsync(HttpResponseMessage response, object model, + ValidationMessageStore validationMessageStore) { var problemDetails = await response.Content.ReadFromJsonAsync(); if (problemDetails == null) + { response.EnsureSuccessStatusCode(); // Trigger exception when unable to parse + } else { - if(!string.IsNullOrEmpty(problemDetails.Detail)) + if (!string.IsNullOrEmpty(problemDetails.Detail)) validationMessageStore.Add(new FieldIdentifier(model, string.Empty), problemDetails.Detail); if (problemDetails.Errors != null) - { foreach (var error in problemDetails.Errors) - { - foreach (var message in error.Value) - validationMessageStore.Add(new FieldIdentifier(model, error.Key), message); - } - } + foreach (var message in error.Value) + validationMessageStore.Add(new FieldIdentifier(model, error.Key), message); } } } \ No newline at end of file diff --git a/Moonlight.Frontend/Interfaces/IPermissionProvider.cs b/Moonlight.Frontend/Infrastructure/Hooks/IPermissionProvider.cs similarity index 51% rename from Moonlight.Frontend/Interfaces/IPermissionProvider.cs rename to Moonlight.Frontend/Infrastructure/Hooks/IPermissionProvider.cs index c2cc75e8..858c7c8c 100644 --- a/Moonlight.Frontend/Interfaces/IPermissionProvider.cs +++ b/Moonlight.Frontend/Infrastructure/Hooks/IPermissionProvider.cs @@ -1,6 +1,6 @@ -using Moonlight.Frontend.Models; +using Moonlight.Frontend.Admin.Users.Shared; -namespace Moonlight.Frontend.Interfaces; +namespace Moonlight.Frontend.Infrastructure.Hooks; public interface IPermissionProvider { diff --git a/Moonlight.Frontend/Infrastructure/Hooks/ISidebarProvider.cs b/Moonlight.Frontend/Infrastructure/Hooks/ISidebarProvider.cs new file mode 100644 index 00000000..fdacbb20 --- /dev/null +++ b/Moonlight.Frontend/Infrastructure/Hooks/ISidebarProvider.cs @@ -0,0 +1,8 @@ +using Moonlight.Frontend.Infrastructure.Models; + +namespace Moonlight.Frontend.Infrastructure.Hooks; + +public interface ISidebarProvider +{ + public Task GetItemsAsync(); +} \ No newline at end of file diff --git a/Moonlight.Frontend/Interfaces/LayoutMiddlewareBase.cs b/Moonlight.Frontend/Infrastructure/Hooks/LayoutMiddlewareBase.cs similarity index 77% rename from Moonlight.Frontend/Interfaces/LayoutMiddlewareBase.cs rename to Moonlight.Frontend/Infrastructure/Hooks/LayoutMiddlewareBase.cs index b92303b2..f15a2618 100644 --- a/Moonlight.Frontend/Interfaces/LayoutMiddlewareBase.cs +++ b/Moonlight.Frontend/Infrastructure/Hooks/LayoutMiddlewareBase.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Components; -namespace Moonlight.Frontend.Interfaces; +namespace Moonlight.Frontend.Infrastructure.Hooks; public abstract class LayoutMiddlewareBase : ComponentBase { diff --git a/Moonlight.Frontend/Implementations/PermissionAuthorizationHandler.cs b/Moonlight.Frontend/Infrastructure/Implementations/PermissionAuthorizationHandler.cs similarity index 93% rename from Moonlight.Frontend/Implementations/PermissionAuthorizationHandler.cs rename to Moonlight.Frontend/Infrastructure/Implementations/PermissionAuthorizationHandler.cs index dbfeb446..4c8d31bf 100644 --- a/Moonlight.Frontend/Implementations/PermissionAuthorizationHandler.cs +++ b/Moonlight.Frontend/Infrastructure/Implementations/PermissionAuthorizationHandler.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Moonlight.Shared; -namespace Moonlight.Frontend.Implementations; +namespace Moonlight.Frontend.Infrastructure.Implementations; public class PermissionAuthorizationHandler : AuthorizationHandler { diff --git a/Moonlight.Frontend/Implementations/PermissionPolicyProvider.cs b/Moonlight.Frontend/Infrastructure/Implementations/PermissionPolicyProvider.cs similarity index 84% rename from Moonlight.Frontend/Implementations/PermissionPolicyProvider.cs rename to Moonlight.Frontend/Infrastructure/Implementations/PermissionPolicyProvider.cs index f5df4924..35432fad 100644 --- a/Moonlight.Frontend/Implementations/PermissionPolicyProvider.cs +++ b/Moonlight.Frontend/Infrastructure/Implementations/PermissionPolicyProvider.cs @@ -2,22 +2,22 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Moonlight.Shared; -namespace Moonlight.Frontend.Implementations; +namespace Moonlight.Frontend.Infrastructure.Implementations; public class PermissionPolicyProvider : IAuthorizationPolicyProvider { private readonly DefaultAuthorizationPolicyProvider FallbackProvider; - + public PermissionPolicyProvider(IOptions options) { FallbackProvider = new DefaultAuthorizationPolicyProvider(options); } - + public async Task GetPolicyAsync(string policyName) { if (!policyName.StartsWith(Permissions.Prefix, StringComparison.OrdinalIgnoreCase)) return await FallbackProvider.GetPolicyAsync(policyName); - + var policy = new AuthorizationPolicyBuilder(); policy.AddRequirements(new PermissionRequirement(policyName)); @@ -25,18 +25,22 @@ public class PermissionPolicyProvider : IAuthorizationPolicyProvider } public Task GetDefaultPolicyAsync() - => FallbackProvider.GetDefaultPolicyAsync(); + { + return FallbackProvider.GetDefaultPolicyAsync(); + } public Task GetFallbackPolicyAsync() - => FallbackProvider.GetFallbackPolicyAsync(); + { + return FallbackProvider.GetFallbackPolicyAsync(); + } } public class PermissionRequirement : IAuthorizationRequirement { - public string Identifier { get; } - public PermissionRequirement(string identifier) { Identifier = identifier; } + + public string Identifier { get; } } \ No newline at end of file diff --git a/Moonlight.Frontend/Infrastructure/Implementations/PermissionProvider.cs b/Moonlight.Frontend/Infrastructure/Implementations/PermissionProvider.cs new file mode 100644 index 00000000..3ee8e120 --- /dev/null +++ b/Moonlight.Frontend/Infrastructure/Implementations/PermissionProvider.cs @@ -0,0 +1,49 @@ +using LucideBlazor; +using Moonlight.Frontend.Admin.Users.Shared; +using Moonlight.Frontend.Infrastructure.Hooks; +using Moonlight.Shared; + +namespace Moonlight.Frontend.Infrastructure.Implementations; + +public sealed class PermissionProvider : IPermissionProvider +{ + public Task GetPermissionsAsync() + { + return Task.FromResult([ + new PermissionCategory("Users", typeof(UserRoundIcon), [ + new Permission(Permissions.Users.Create, "Create", "Create new users"), + new Permission(Permissions.Users.View, "View", "View all users"), + new Permission(Permissions.Users.Edit, "Edit", "Edit user details"), + new Permission(Permissions.Users.Delete, "Delete", "Delete user accounts"), + new Permission(Permissions.Users.Logout, "Logout", "Logout user accounts") + ]), + new PermissionCategory("Roles", typeof(UsersRoundIcon), [ + new Permission(Permissions.Roles.Create, "Create", "Create new roles"), + new Permission(Permissions.Roles.View, "View", "View all roles"), + new Permission(Permissions.Roles.Edit, "Edit", "Edit role details"), + new Permission(Permissions.Roles.Delete, "Delete", "Delete role accounts"), + new Permission(Permissions.Roles.Members, "Members", "Manage role members") + ]), + new PermissionCategory("System", typeof(CogIcon), [ + new Permission(Permissions.System.Info, "Info", "View system info"), + new Permission(Permissions.System.Diagnose, "Diagnose", "Run diagnostics"), + new Permission(Permissions.System.Versions, "Versions", "Look at the available versions"), + new Permission(Permissions.System.Instance, "Instance", + "Update the moonlight instance and add plugins"), + new Permission(Permissions.System.Settings, "Settings", "Change settings of the instance") + ]), + new PermissionCategory("API Keys", typeof(KeyIcon), [ + new Permission(Permissions.ApiKeys.Create, "Create", "Create new API keys"), + new Permission(Permissions.ApiKeys.View, "View", "View all API keys"), + new Permission(Permissions.ApiKeys.Edit, "Edit", "Edit API key details"), + new Permission(Permissions.ApiKeys.Delete, "Delete", "Delete API keys") + ]), + new PermissionCategory("Themes", typeof(PaintRollerIcon), [ + new Permission(Permissions.Themes.Create, "Create", "Create new theme"), + new Permission(Permissions.Themes.View, "View", "View all themes"), + new Permission(Permissions.Themes.Edit, "Edit", "Edit themes"), + new Permission(Permissions.Themes.Delete, "Delete", "Delete themes") + ]) + ]); + } +} \ No newline at end of file diff --git a/Moonlight.Frontend/Implementations/SidebarProvider.cs b/Moonlight.Frontend/Infrastructure/Implementations/SidebarProvider.cs similarity index 83% rename from Moonlight.Frontend/Implementations/SidebarProvider.cs rename to Moonlight.Frontend/Infrastructure/Implementations/SidebarProvider.cs index 8cd52510..09c639bc 100644 --- a/Moonlight.Frontend/Implementations/SidebarProvider.cs +++ b/Moonlight.Frontend/Infrastructure/Implementations/SidebarProvider.cs @@ -1,16 +1,16 @@ using LucideBlazor; -using Moonlight.Frontend.Interfaces; -using Moonlight.Frontend.Models; +using Moonlight.Frontend.Infrastructure.Hooks; +using Moonlight.Frontend.Infrastructure.Models; using Moonlight.Shared; -namespace Moonlight.Frontend.Implementations; +namespace Moonlight.Frontend.Infrastructure.Implementations; public sealed class SidebarProvider : ISidebarProvider { public Task GetItemsAsync() { return Task.FromResult([ - new() + new SidebarItem { Name = "Overview", IconType = typeof(LayoutDashboardIcon), @@ -18,7 +18,7 @@ public sealed class SidebarProvider : ISidebarProvider IsExactPath = true, Order = 0 }, - new() + new SidebarItem { Name = "Overview", IconType = typeof(LayoutDashboardIcon), @@ -28,7 +28,7 @@ public sealed class SidebarProvider : ISidebarProvider Order = 0, Policy = Permissions.System.Info }, - new() + new SidebarItem { Name = "Users", IconType = typeof(UsersRoundIcon), @@ -38,7 +38,7 @@ public sealed class SidebarProvider : ISidebarProvider Order = 10, Policy = Permissions.Users.View }, - new() + new SidebarItem { Name = "System", IconType = typeof(SettingsIcon), diff --git a/Moonlight.Frontend/Models/SidebarItem.cs b/Moonlight.Frontend/Infrastructure/Models/SidebarItem.cs similarity index 91% rename from Moonlight.Frontend/Models/SidebarItem.cs rename to Moonlight.Frontend/Infrastructure/Models/SidebarItem.cs index 66c73ec7..ab49042c 100644 --- a/Moonlight.Frontend/Models/SidebarItem.cs +++ b/Moonlight.Frontend/Infrastructure/Models/SidebarItem.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -namespace Moonlight.Frontend.Models; +namespace Moonlight.Frontend.Infrastructure.Models; public record SidebarItem { diff --git a/Moonlight.Frontend/UI/App.razor b/Moonlight.Frontend/Infrastructure/Partials/App.razor similarity index 88% rename from Moonlight.Frontend/UI/App.razor rename to Moonlight.Frontend/Infrastructure/Partials/App.razor index 86facf99..d8ebad55 100644 --- a/Moonlight.Frontend/UI/App.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/App.razor @@ -3,17 +3,13 @@ @using LucideBlazor @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.Extensions.Options -@using Moonlight.Frontend.Configuration -@using Moonlight.Frontend.UI.Shared -@using Moonlight.Frontend.UI.Shared.Components +@using Moonlight.Frontend.Infrastructure.Configuration +@using Moonlight.Frontend.Shared.Auth @using ShadcnBlazor.Emptys -@using Moonlight.Frontend.UI.Shared.Components.Auth -@using Moonlight.Frontend.UI.Shared.Partials @using ShadcnBlazor.Extras.AlertDialogs @using ShadcnBlazor.Extras.Dialogs @using ShadcnBlazor.Extras.Toasts @using ShadcnBlazor.Portals - @inject NavigationManager Navigation @inject IOptions NavigationOptions @@ -22,7 +18,8 @@ - + @@ -32,12 +29,12 @@ - + - - + + @@ -53,7 +50,7 @@ if (uri.LocalPath.StartsWith("/setup")) { - + } else { diff --git a/Moonlight.Frontend/UI/Shared/Partials/AppHeader.razor b/Moonlight.Frontend/Infrastructure/Partials/AppHeader.razor similarity index 99% rename from Moonlight.Frontend/UI/Shared/Partials/AppHeader.razor rename to Moonlight.Frontend/Infrastructure/Partials/AppHeader.razor index d038244e..cd27a4e5 100644 --- a/Moonlight.Frontend/UI/Shared/Partials/AppHeader.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/AppHeader.razor @@ -1,5 +1,4 @@ @using ShadcnBlazor.Sidebars -
diff --git a/Moonlight.Frontend/UI/Shared/Partials/AppSidebar.razor b/Moonlight.Frontend/Infrastructure/Partials/AppSidebar.razor similarity index 93% rename from Moonlight.Frontend/UI/Shared/Partials/AppSidebar.razor rename to Moonlight.Frontend/Infrastructure/Partials/AppSidebar.razor index 6aca26b3..ffd8fc3a 100644 --- a/Moonlight.Frontend/UI/Shared/Partials/AppSidebar.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/AppSidebar.razor @@ -1,16 +1,15 @@ -@using System.Text.Json -@using Microsoft.AspNetCore.Authorization -@using Microsoft.AspNetCore.Components.Authorization -@using Moonlight.Frontend.Interfaces -@using Moonlight.Frontend.Models -@using Moonlight.Frontend.Services -@using ShadcnBlazor.Sidebars - -@inject NavigationManager Navigation +@inject NavigationManager Navigation @inject IAuthorizationService AuthorizationService @inject FrontendService FrontendService @inject IEnumerable Providers +@using System.Text.Json +@using Microsoft.AspNetCore.Authorization +@using Microsoft.AspNetCore.Components.Authorization +@using Moonlight.Frontend.Infrastructure.Hooks +@using Moonlight.Frontend.Infrastructure.Models +@using Moonlight.Frontend.Shared.Frontend +@using ShadcnBlazor.Sidebars @implements IDisposable @{ @@ -75,32 +74,32 @@ @code { [CascadingParameter] public Task AuthState { get; set; } - + private readonly List Items = new(); private FrontendConfiguration? FrontendConfiguration; protected override async Task OnInitializedAsync() { var authState = await AuthState; - + foreach (var provider in Providers) { var items = await provider.GetItemsAsync(); - + foreach (var item in items) { if (!string.IsNullOrWhiteSpace(item.Policy)) { var result = await AuthorizationService.AuthorizeAsync(authState.User, item.Policy); - - if(!result.Succeeded) + + if (!result.Succeeded) continue; } - + Items.Add(item); } } - + Navigation.LocationChanged += OnLocationChanged; FrontendConfiguration = await FrontendService.GetConfigurationAsync(); diff --git a/Moonlight.Frontend/UI/Shared/LayoutMiddleware.razor b/Moonlight.Frontend/Infrastructure/Partials/LayoutMiddleware.razor similarity index 88% rename from Moonlight.Frontend/UI/Shared/LayoutMiddleware.razor rename to Moonlight.Frontend/Infrastructure/Partials/LayoutMiddleware.razor index 42323132..8014b306 100644 --- a/Moonlight.Frontend/UI/Shared/LayoutMiddleware.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/LayoutMiddleware.razor @@ -1,7 +1,6 @@ @using Microsoft.Extensions.Options -@using Moonlight.Frontend.Configuration -@using Moonlight.Frontend.Interfaces - +@using Moonlight.Frontend.Infrastructure.Configuration +@using Moonlight.Frontend.Infrastructure.Hooks @inject IOptions Options @Chain @@ -9,7 +8,7 @@ @code { [Parameter] public RenderFragment ChildContent { get; set; } - + private RenderFragment Chain; protected override void OnInitialized() @@ -21,7 +20,7 @@ // Capture current values var currentChain = Chain; var currentComponent = component; - + Chain = builder => { builder.OpenComponent(0, currentComponent); diff --git a/Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor b/Moonlight.Frontend/Infrastructure/Partials/MainLayout.razor similarity index 86% rename from Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor rename to Moonlight.Frontend/Infrastructure/Partials/MainLayout.razor index 57a113c6..514f1431 100644 --- a/Moonlight.Frontend/UI/Shared/Partials/MainLayout.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/MainLayout.razor @@ -1,8 +1,7 @@ @using Microsoft.Extensions.Options -@using Moonlight.Frontend.Configuration +@using Moonlight.Frontend.Infrastructure.Configuration @using ShadcnBlazor.Extras.Alerts @using ShadcnBlazor.Sidebars - @inherits LayoutComponentBase @inject IOptions LayoutPageOptions @@ -15,18 +14,18 @@ @foreach (var headerComponent in HeaderComponents) { - + } - +
@Body
- + @foreach (var footerComponent in FooterComponents) { - + } @@ -35,7 +34,7 @@ { private Type[] HeaderComponents; private Type[] FooterComponents; - + protected override void OnInitialized() { HeaderComponents = LayoutPageOptions.Value.Components @@ -43,7 +42,7 @@ .OrderBy(x => x.Order) .Select(x => x.ComponentType) .ToArray(); - + FooterComponents = LayoutPageOptions.Value.Components .Where(x => x.Slot == LayoutPageSlot.Footer) .OrderBy(x => x.Order) diff --git a/Moonlight.Frontend/UI/Shared/Partials/NavUser.razor b/Moonlight.Frontend/Infrastructure/Partials/NavUser.razor similarity index 97% rename from Moonlight.Frontend/UI/Shared/Partials/NavUser.razor rename to Moonlight.Frontend/Infrastructure/Partials/NavUser.razor index 7763d39a..3df9770c 100644 --- a/Moonlight.Frontend/UI/Shared/Partials/NavUser.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/NavUser.razor @@ -5,7 +5,6 @@ @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Interop @using ShadcnBlazor.Sidebars - @inject NavigationManager Navigation @@ -72,5 +71,8 @@ Email = authState.User.FindFirst(ClaimTypes.Email)?.Value ?? "N/A"; } - private void Logout() => Navigation.NavigateTo("/api/auth/logout", true); + private void Logout() + { + Navigation.NavigateTo("/api/auth/logout", true); + } } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Shared/NotFound.razor b/Moonlight.Frontend/Infrastructure/Partials/NotFound.razor similarity index 99% rename from Moonlight.Frontend/UI/Shared/NotFound.razor rename to Moonlight.Frontend/Infrastructure/Partials/NotFound.razor index 39e85451..25cb0c57 100644 --- a/Moonlight.Frontend/UI/Shared/NotFound.razor +++ b/Moonlight.Frontend/Infrastructure/Partials/NotFound.razor @@ -1,8 +1,7 @@ @page "/notfound" - @using LucideBlazor -@using ShadcnBlazor.Emptys @using ShadcnBlazor.Buttons +@using ShadcnBlazor.Emptys diff --git a/Moonlight.Frontend/Services/RemoteAuthProvider.cs b/Moonlight.Frontend/Infrastructure/Services/RemoteAuthProvider.cs similarity index 90% rename from Moonlight.Frontend/Services/RemoteAuthProvider.cs rename to Moonlight.Frontend/Infrastructure/Services/RemoteAuthProvider.cs index 2ec3a0dd..3e453b87 100644 --- a/Moonlight.Frontend/Services/RemoteAuthProvider.cs +++ b/Moonlight.Frontend/Infrastructure/Services/RemoteAuthProvider.cs @@ -3,16 +3,15 @@ using System.Net.Http.Json; using System.Security.Claims; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.Logging; -using Microsoft.VisualBasic; -using Moonlight.Shared.Http; -using Moonlight.Shared.Http.Responses.Admin.Auth; +using Moonlight.Shared; +using Moonlight.Shared.Shared.Auth; -namespace Moonlight.Frontend.Services; +namespace Moonlight.Frontend.Infrastructure.Services; public class RemoteAuthProvider : AuthenticationStateProvider { - private readonly ILogger Logger; private readonly HttpClient HttpClient; + private readonly ILogger Logger; public RemoteAuthProvider(ILogger logger, HttpClient httpClient) { diff --git a/Moonlight.Frontend/Interfaces/ISidebarProvider.cs b/Moonlight.Frontend/Interfaces/ISidebarProvider.cs deleted file mode 100644 index 83a3c9f0..00000000 --- a/Moonlight.Frontend/Interfaces/ISidebarProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Moonlight.Frontend.Models; - -namespace Moonlight.Frontend.Interfaces; - -public interface ISidebarProvider -{ - public Task GetItemsAsync(); -} \ No newline at end of file diff --git a/Moonlight.Frontend/Models/FrontendConfiguration.cs b/Moonlight.Frontend/Models/FrontendConfiguration.cs deleted file mode 100644 index aa960211..00000000 --- a/Moonlight.Frontend/Models/FrontendConfiguration.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Moonlight.Frontend.Models; - -public class FrontendConfiguration -{ - [JsonPropertyName("name")] - public string Name { get; set; } -} \ No newline at end of file diff --git a/Moonlight.Frontend/Moonlight.Frontend.csproj b/Moonlight.Frontend/Moonlight.Frontend.csproj index f29c21f0..63741af5 100644 --- a/Moonlight.Frontend/Moonlight.Frontend.csproj +++ b/Moonlight.Frontend/Moonlight.Frontend.csproj @@ -21,21 +21,48 @@ - - - - - - + + + + + + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Moonlight.Frontend/Moonlight.Frontend.targets b/Moonlight.Frontend/Moonlight.Frontend.targets index 95a0f686..8ade2e89 100644 --- a/Moonlight.Frontend/Moonlight.Frontend.targets +++ b/Moonlight.Frontend/Moonlight.Frontend.targets @@ -7,9 +7,9 @@ - + - + \ No newline at end of file diff --git a/Moonlight.Frontend/MoonlightPlugin.cs b/Moonlight.Frontend/MoonlightPlugin.cs index df5bbc75..613a088a 100644 --- a/Moonlight.Frontend/MoonlightPlugin.cs +++ b/Moonlight.Frontend/MoonlightPlugin.cs @@ -11,7 +11,12 @@ public abstract class MoonlightPlugin : IPluginModule { Plugins = plugins; } - - public virtual void PreBuild(WebAssemblyHostBuilder builder){} - public virtual void PostBuild(WebAssemblyHost application){} + + public virtual void PreBuild(WebAssemblyHostBuilder builder) + { + } + + public virtual void PostBuild(WebAssemblyHost application) + { + } } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Shared/Components/Auth/AccessDenied.razor b/Moonlight.Frontend/Shared/Auth/AccessDenied.razor similarity index 99% rename from Moonlight.Frontend/UI/Shared/Components/Auth/AccessDenied.razor rename to Moonlight.Frontend/Shared/Auth/AccessDenied.razor index 94998665..e6cb948c 100644 --- a/Moonlight.Frontend/UI/Shared/Components/Auth/AccessDenied.razor +++ b/Moonlight.Frontend/Shared/Auth/AccessDenied.razor @@ -1,6 +1,5 @@ @using LucideBlazor @using ShadcnBlazor.Emptys -
diff --git a/Moonlight.Frontend/UI/Shared/Components/Auth/Authenticating.razor b/Moonlight.Frontend/Shared/Auth/Authenticating.razor similarity index 99% rename from Moonlight.Frontend/UI/Shared/Components/Auth/Authenticating.razor rename to Moonlight.Frontend/Shared/Auth/Authenticating.razor index 4611a40f..60541d8d 100644 --- a/Moonlight.Frontend/UI/Shared/Components/Auth/Authenticating.razor +++ b/Moonlight.Frontend/Shared/Auth/Authenticating.razor @@ -1,6 +1,5 @@ @using LucideBlazor @using ShadcnBlazor.Emptys -
diff --git a/Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor b/Moonlight.Frontend/Shared/Auth/Authentication.razor similarity index 95% rename from Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor rename to Moonlight.Frontend/Shared/Auth/Authentication.razor index 3187e747..fbfe4635 100644 --- a/Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor +++ b/Moonlight.Frontend/Shared/Auth/Authentication.razor @@ -1,8 +1,8 @@ -@using Moonlight.Shared.Http -@using Moonlight.Shared.Http.Responses.Admin.Auth +@using Moonlight.Shared +@using Moonlight.Shared.Shared.Auth +@using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards @using ShadcnBlazor.Spinners -@using ShadcnBlazor.Buttons @inject HttpClient HttpClient @inject NavigationManager Navigation diff --git a/Moonlight.Frontend/Shared/Frontend/FrontendConfiguration.cs b/Moonlight.Frontend/Shared/Frontend/FrontendConfiguration.cs new file mode 100644 index 00000000..7db29c46 --- /dev/null +++ b/Moonlight.Frontend/Shared/Frontend/FrontendConfiguration.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace Moonlight.Frontend.Shared.Frontend; + +public class FrontendConfiguration +{ + [JsonPropertyName("name")] public string Name { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Frontend/Services/FrontendService.cs b/Moonlight.Frontend/Shared/Frontend/FrontendService.cs similarity index 86% rename from Moonlight.Frontend/Services/FrontendService.cs rename to Moonlight.Frontend/Shared/Frontend/FrontendService.cs index 268c2783..fd5395c6 100644 --- a/Moonlight.Frontend/Services/FrontendService.cs +++ b/Moonlight.Frontend/Shared/Frontend/FrontendService.cs @@ -1,7 +1,6 @@ using Microsoft.JSInterop; -using Moonlight.Frontend.Models; -namespace Moonlight.Frontend.Services; +namespace Moonlight.Frontend.Shared.Frontend; public class FrontendService { @@ -11,7 +10,7 @@ public class FrontendService { JsRuntime = jsRuntime; } - + public async Task GetConfigurationAsync() { return await JsRuntime.InvokeAsync("frontendConfig.getConfiguration"); diff --git a/Moonlight.Frontend/Startup/Startup.Auth.cs b/Moonlight.Frontend/Startup/Startup.Auth.cs index 0e64c73b..27ceba48 100644 --- a/Moonlight.Frontend/Startup/Startup.Auth.cs +++ b/Moonlight.Frontend/Startup/Startup.Auth.cs @@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.Extensions.DependencyInjection; -using Moonlight.Frontend.Implementations; -using Moonlight.Frontend.Interfaces; -using Moonlight.Frontend.Services; +using Moonlight.Frontend.Infrastructure.Hooks; +using Moonlight.Frontend.Infrastructure.Implementations; +using Moonlight.Frontend.Infrastructure.Services; namespace Moonlight.Frontend.Startup; @@ -17,7 +17,7 @@ public partial class Startup builder.Services.AddCascadingAuthenticationState(); builder.Services.AddSingleton(); - + builder.Services.AddSingleton(); builder.Services.AddSingleton(); } diff --git a/Moonlight.Frontend/Startup/Startup.Base.cs b/Moonlight.Frontend/Startup/Startup.Base.cs index 1c377c50..1de7d5c8 100644 --- a/Moonlight.Frontend/Startup/Startup.Base.cs +++ b/Moonlight.Frontend/Startup/Startup.Base.cs @@ -2,12 +2,12 @@ using LucideBlazor; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.Extensions.DependencyInjection; -using Moonlight.Frontend.Configuration; -using Moonlight.Frontend.Implementations; -using Moonlight.Frontend.Interfaces; -using Moonlight.Frontend.Services; -using Moonlight.Frontend.UI; -using Moonlight.Frontend.UI.Admin.Settings; +using Moonlight.Frontend.Admin.Sys.Settings; +using Moonlight.Frontend.Infrastructure.Configuration; +using Moonlight.Frontend.Infrastructure.Hooks; +using Moonlight.Frontend.Infrastructure.Implementations; +using Moonlight.Frontend.Infrastructure.Partials; +using Moonlight.Frontend.Shared.Frontend; using ShadcnBlazor; using ShadcnBlazor.Extras; diff --git a/Moonlight.Frontend/Startup/Startup.cs b/Moonlight.Frontend/Startup/Startup.cs index 8c461ca6..06495cfe 100644 --- a/Moonlight.Frontend/Startup/Startup.cs +++ b/Moonlight.Frontend/Startup/Startup.cs @@ -14,6 +14,5 @@ public partial class Startup : MoonlightPlugin public override void PostBuild(WebAssemblyHost application) { - } } \ No newline at end of file diff --git a/Moonlight.Frontend/StartupHandler.cs b/Moonlight.Frontend/StartupHandler.cs index 2a7a0817..78c4cb93 100644 --- a/Moonlight.Frontend/StartupHandler.cs +++ b/Moonlight.Frontend/StartupHandler.cs @@ -7,7 +7,7 @@ public static class StartupHandler public static async Task RunAsync(string[] args, MoonlightPlugin[] plugins) { Console.WriteLine($"Starting with: {string.Join(", ", plugins.Select(x => x.GetType().FullName))}"); - + var builder = WebAssemblyHostBuilder.CreateDefault(args); // Setting up context @@ -21,7 +21,7 @@ public static class StartupHandler var app = builder.Build(); // Stage 2: Post Build - foreach(var plugin in plugins) + foreach (var plugin in plugins) plugin.PostBuild(app); await app.RunAsync(); diff --git a/Moonlight.Frontend/UI/Shared/Components/Setup.razor b/Moonlight.Frontend/UI/Shared/Components/Setup.razor deleted file mode 100644 index 7cb3adba..00000000 --- a/Moonlight.Frontend/UI/Shared/Components/Setup.razor +++ /dev/null @@ -1,172 +0,0 @@ -@using LucideBlazor -@using Moonlight.Shared.Http.Requests.Seup -@using ShadcnBlazor.Cards -@using ShadcnBlazor.Spinners -@using ShadcnBlazor.Buttons -@using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels - -@inject HttpClient HttpClient -@inject NavigationManager Navigation - -
- - @if (IsLoaded) - { -
- @if (CurrentStep == 0) - { -
- Moonlight Logo -
- -
-

Welcome to Moonlight Panel

-

- You successfully installed moonlight. Now you are ready to perform some initial steps to complete your installation -

-
- } - else if (CurrentStep == 1) - { -
- -
- -
-

Admin Account Creation

-

- To continue please fill in the account details of the user you want to use as the initial administrator account. - If you use an external OIDC provider, these details need to match with your desired OIDC account -

-
- -
-
- - -
-
- - -
-
- - -
-
- } - else if (CurrentStep == 2) - { -
- -
- -
-

You are all set!

-

- You are now ready to finish the initial setup. - The configured options will be applied to the instance. - You will be redirected to the login after changes have been applied successfully -

-
- } -
-
- @for (var step = 0; step < StepCount; step++) - { - if (step == CurrentStep) - { -
-
- } - else - { -
-
- } - } -
-
- @if (CurrentStep > 0) - { - - } - @if (CurrentStep != StepCount - 1) - { - - } - else - { - - } -
-
-
- } - else - { -
- -
- } -
-
- -@code -{ - private bool IsLoaded; - - private int CurrentStep = 0; - private int StepCount = 3; - - private ApplySetupDto SetupDto = new(); - - private void Navigate(int diff) => CurrentStep += diff; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if(!firstRender) - return; - - var response = await HttpClient.GetAsync("api/admin/setup"); - - if (!response.IsSuccessStatusCode) - { - Navigation.NavigateTo("/", true); - return; - } - - IsLoaded = true; - await InvokeAsync(StateHasChanged); - } - - private async Task ApplyAsync() - { - await HttpClient.PostAsJsonAsync("api/admin/setup", SetupDto); - Navigation.NavigateTo("/", true); - } -} \ No newline at end of file diff --git a/Moonlight.Frontend/UI/_Imports.razor b/Moonlight.Frontend/_Imports.razor similarity index 100% rename from Moonlight.Frontend/UI/_Imports.razor rename to Moonlight.Frontend/_Imports.razor diff --git a/Moonlight.Frontend/wwwroot/logo.svg b/Moonlight.Frontend/wwwroot/logo.svg index 193ebfae..b4a1ccf6 100644 --- a/Moonlight.Frontend/wwwroot/logo.svg +++ b/Moonlight.Frontend/wwwroot/logo.svg @@ -1,5 +1,6 @@ - + @@ -9,6 +10,7 @@ - + diff --git a/Moonlight.Shared/Http/Requests/Seup/ApplySetupDto.cs b/Moonlight.Shared/Admin/Setup/ApplySetupDto.cs similarity index 67% rename from Moonlight.Shared/Http/Requests/Seup/ApplySetupDto.cs rename to Moonlight.Shared/Admin/Setup/ApplySetupDto.cs index 28c29239..41aaad46 100644 --- a/Moonlight.Shared/Http/Requests/Seup/ApplySetupDto.cs +++ b/Moonlight.Shared/Admin/Setup/ApplySetupDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Seup; +namespace Moonlight.Shared.Admin.Setup; public class ApplySetupDto { @@ -8,11 +8,9 @@ public class ApplySetupDto [MinLength(3)] [MaxLength(32)] public string AdminUsername { get; set; } - - [Required] - [EmailAddress] - public string AdminEmail { get; set; } - + + [Required] [EmailAddress] public string AdminEmail { get; set; } + [Required] [MinLength(8)] [MaxLength(64)] diff --git a/Moonlight.Shared/Admin/Sys/ApiKeys/ApiKeyDto.cs b/Moonlight.Shared/Admin/Sys/ApiKeys/ApiKeyDto.cs new file mode 100644 index 00000000..ca499cee --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/ApiKeys/ApiKeyDto.cs @@ -0,0 +1,11 @@ +namespace Moonlight.Shared.Admin.Sys.ApiKeys; + +public record ApiKeyDto( + int Id, + string Name, + string Description, + string[] Permissions, + DateTimeOffset ValidUntil, + string Key, + DateTimeOffset CreatedAt, + DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/ApiKeys/CreateApiKeyDto.cs b/Moonlight.Shared/Admin/Sys/ApiKeys/CreateApiKeyDto.cs similarity index 85% rename from Moonlight.Shared/Http/Requests/Admin/ApiKeys/CreateApiKeyDto.cs rename to Moonlight.Shared/Admin/Sys/ApiKeys/CreateApiKeyDto.cs index 1b58d832..d85b1b30 100644 --- a/Moonlight.Shared/Http/Requests/Admin/ApiKeys/CreateApiKeyDto.cs +++ b/Moonlight.Shared/Admin/Sys/ApiKeys/CreateApiKeyDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.ApiKeys; +namespace Moonlight.Shared.Admin.Sys.ApiKeys; public class CreateApiKeyDto { diff --git a/Moonlight.Shared/Http/Requests/Admin/ApiKeys/UpdateApiKeyDto.cs b/Moonlight.Shared/Admin/Sys/ApiKeys/UpdateApiKeyDto.cs similarity index 85% rename from Moonlight.Shared/Http/Requests/Admin/ApiKeys/UpdateApiKeyDto.cs rename to Moonlight.Shared/Admin/Sys/ApiKeys/UpdateApiKeyDto.cs index 1044904c..5146a057 100644 --- a/Moonlight.Shared/Http/Requests/Admin/ApiKeys/UpdateApiKeyDto.cs +++ b/Moonlight.Shared/Admin/Sys/ApiKeys/UpdateApiKeyDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.ApiKeys; +namespace Moonlight.Shared.Admin.Sys.ApiKeys; public class UpdateApiKeyDto { diff --git a/Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs b/Moonlight.Shared/Admin/Sys/ContainerHelper/ContainerHelperStatusDto.cs similarity index 57% rename from Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs rename to Moonlight.Shared/Admin/Sys/ContainerHelper/ContainerHelperStatusDto.cs index 16bc5866..be0918d0 100644 --- a/Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs +++ b/Moonlight.Shared/Admin/Sys/ContainerHelper/ContainerHelperStatusDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Admin; +namespace Moonlight.Shared.Admin.Sys.ContainerHelper; public record ContainerHelperStatusDto(bool IsEnabled, bool IsReachable); \ No newline at end of file diff --git a/Moonlight.Shared/Admin/Sys/ContainerHelper/RebuildEventDto.cs b/Moonlight.Shared/Admin/Sys/ContainerHelper/RebuildEventDto.cs new file mode 100644 index 00000000..e999122d --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/ContainerHelper/RebuildEventDto.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace Moonlight.Shared.Admin.Sys.ContainerHelper; + +public struct RebuildEventDto +{ + [JsonPropertyName("type")] public RebuildEventType Type { get; set; } + + [JsonPropertyName("data")] public string Data { get; set; } +} + +public enum RebuildEventType +{ + Log = 0, + Failed = 1, + Succeeded = 2, + Step = 3 +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs b/Moonlight.Shared/Admin/Sys/ContainerHelper/RequestRebuildDto.cs similarity index 76% rename from Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs rename to Moonlight.Shared/Admin/Sys/ContainerHelper/RequestRebuildDto.cs index 335f7be5..7601d2d3 100644 --- a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs +++ b/Moonlight.Shared/Admin/Sys/ContainerHelper/RequestRebuildDto.cs @@ -1,9 +1,7 @@ -namespace Moonlight.Shared.Http.Requests.Admin.ContainerHelper; +namespace Moonlight.Shared.Admin.Sys.ContainerHelper; public class RequestRebuildDto { - public bool NoBuildCache { get; set; } - public RequestRebuildDto() { } @@ -12,4 +10,6 @@ public class RequestRebuildDto { NoBuildCache = noBuildCache; } + + public bool NoBuildCache { get; set; } } \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs b/Moonlight.Shared/Admin/Sys/ContainerHelper/SetVersionDto.cs similarity index 79% rename from Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs rename to Moonlight.Shared/Admin/Sys/ContainerHelper/SetVersionDto.cs index fab46fd1..054c160f 100644 --- a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs +++ b/Moonlight.Shared/Admin/Sys/ContainerHelper/SetVersionDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.ContainerHelper; +namespace Moonlight.Shared.Admin.Sys.ContainerHelper; public class SetVersionDto { diff --git a/Moonlight.Shared/Admin/Sys/Diagnose/DiagnoseResultDto.cs b/Moonlight.Shared/Admin/Sys/Diagnose/DiagnoseResultDto.cs new file mode 100644 index 00000000..fc3be8af --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/Diagnose/DiagnoseResultDto.cs @@ -0,0 +1,17 @@ +namespace Moonlight.Shared.Admin.Sys.Diagnose; + +public record DiagnoseResultDto( + DiagnoseLevel Level, + string Title, + string[] Tags, + string? Message, + string? StackStrace, + string? SolutionUrl, + string? ReportUrl); + +public enum DiagnoseLevel +{ + Error = 0, + Warning = 1, + Healthy = 2 +} \ No newline at end of file diff --git a/Moonlight.Shared/Admin/Sys/Settings/SetWhiteLabelingDto.cs b/Moonlight.Shared/Admin/Sys/Settings/SetWhiteLabelingDto.cs new file mode 100644 index 00000000..970db651 --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/Settings/SetWhiteLabelingDto.cs @@ -0,0 +1,8 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Shared.Admin.Sys.Settings; + +public class SetWhiteLabelingDto +{ + [Required] public string Name { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Settings/WhiteLabelingDto.cs b/Moonlight.Shared/Admin/Sys/Settings/WhiteLabelingDto.cs similarity index 55% rename from Moonlight.Shared/Http/Responses/Admin/Settings/WhiteLabelingDto.cs rename to Moonlight.Shared/Admin/Sys/Settings/WhiteLabelingDto.cs index 85697665..6e2f51bd 100644 --- a/Moonlight.Shared/Http/Responses/Admin/Settings/WhiteLabelingDto.cs +++ b/Moonlight.Shared/Admin/Sys/Settings/WhiteLabelingDto.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Shared.Http.Responses.Admin.Settings; +namespace Moonlight.Shared.Admin.Sys.Settings; public class WhiteLabelingDto { diff --git a/Moonlight.Shared/Admin/Sys/SystemInfoDto.cs b/Moonlight.Shared/Admin/Sys/SystemInfoDto.cs new file mode 100644 index 00000000..fda26669 --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/SystemInfoDto.cs @@ -0,0 +1,9 @@ +namespace Moonlight.Shared.Admin.Sys; + +public record SystemInfoDto( + double CpuUsage, + long MemoryUsage, + string OperatingSystem, + TimeSpan Uptime, + string VersionName, + bool IsUpToDate); \ No newline at end of file diff --git a/Moonlight.Shared/Admin/Sys/Themes/CreateThemeDto.cs b/Moonlight.Shared/Admin/Sys/Themes/CreateThemeDto.cs new file mode 100644 index 00000000..470e5978 --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/Themes/CreateThemeDto.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Shared.Admin.Sys.Themes; + +public class CreateThemeDto +{ + [Required] [MaxLength(30)] public string Name { get; set; } + + [Required] [MaxLength(30)] public string Version { get; set; } + + [Required] [MaxLength(30)] public string Author { get; set; } + + public bool IsEnabled { get; set; } + + [Required] [MaxLength(20_000)] public string CssContent { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Themes/ThemeDto.cs b/Moonlight.Shared/Admin/Sys/Themes/ThemeDto.cs similarity index 66% rename from Moonlight.Shared/Http/Responses/Admin/Themes/ThemeDto.cs rename to Moonlight.Shared/Admin/Sys/Themes/ThemeDto.cs index 854bfd6e..ecbaac7d 100644 --- a/Moonlight.Shared/Http/Responses/Admin/Themes/ThemeDto.cs +++ b/Moonlight.Shared/Admin/Sys/Themes/ThemeDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Admin.Themes; +namespace Moonlight.Shared.Admin.Sys.Themes; public record ThemeDto(int Id, string Name, string Author, string Version, string CssContent, bool IsEnabled); \ No newline at end of file diff --git a/Moonlight.Shared/Admin/Sys/Themes/UpdateThemeDto.cs b/Moonlight.Shared/Admin/Sys/Themes/UpdateThemeDto.cs new file mode 100644 index 00000000..35cd2ac8 --- /dev/null +++ b/Moonlight.Shared/Admin/Sys/Themes/UpdateThemeDto.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Shared.Admin.Sys.Themes; + +public class UpdateThemeDto +{ + [Required] [MaxLength(30)] public string Name { get; set; } + + [Required] [MaxLength(30)] public string Version { get; set; } + + [Required] [MaxLength(30)] public string Author { get; set; } + + public bool IsEnabled { get; set; } + + [Required] [MaxLength(20_000)] public string CssContent { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/VersionDto.cs b/Moonlight.Shared/Admin/Sys/Versions/VersionDto.cs similarity index 69% rename from Moonlight.Shared/Http/Responses/Admin/VersionDto.cs rename to Moonlight.Shared/Admin/Sys/Versions/VersionDto.cs index 51116d71..f120c6b3 100644 --- a/Moonlight.Shared/Http/Responses/Admin/VersionDto.cs +++ b/Moonlight.Shared/Admin/Sys/Versions/VersionDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Admin; +namespace Moonlight.Shared.Admin.Sys.Versions; public record VersionDto(string Identifier, bool IsPreRelease, bool IsDevelopment, DateTimeOffset CreatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Roles/CreateRoleDto.cs b/Moonlight.Shared/Admin/Users/Roles/CreateRoleDto.cs similarity index 83% rename from Moonlight.Shared/Http/Requests/Admin/Roles/CreateRoleDto.cs rename to Moonlight.Shared/Admin/Users/Roles/CreateRoleDto.cs index 6573aedd..90497e12 100644 --- a/Moonlight.Shared/Http/Requests/Admin/Roles/CreateRoleDto.cs +++ b/Moonlight.Shared/Admin/Users/Roles/CreateRoleDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.Roles; +namespace Moonlight.Shared.Admin.Users.Roles; public class CreateRoleDto { diff --git a/Moonlight.Shared/Admin/Users/Roles/RoleDto.cs b/Moonlight.Shared/Admin/Users/Roles/RoleDto.cs new file mode 100644 index 00000000..6469917f --- /dev/null +++ b/Moonlight.Shared/Admin/Users/Roles/RoleDto.cs @@ -0,0 +1,10 @@ +namespace Moonlight.Shared.Admin.Users.Roles; + +public record RoleDto( + int Id, + string Name, + string Description, + string[] Permissions, + int MemberCount, + DateTimeOffset CreatedAt, + DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Roles/UpdateRoleDto.cs b/Moonlight.Shared/Admin/Users/Roles/UpdateRoleDto.cs similarity index 83% rename from Moonlight.Shared/Http/Requests/Admin/Roles/UpdateRoleDto.cs rename to Moonlight.Shared/Admin/Users/Roles/UpdateRoleDto.cs index 57538cc2..8dcc8263 100644 --- a/Moonlight.Shared/Http/Requests/Admin/Roles/UpdateRoleDto.cs +++ b/Moonlight.Shared/Admin/Users/Roles/UpdateRoleDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.Roles; +namespace Moonlight.Shared.Admin.Users.Roles; public class UpdateRoleDto { diff --git a/Moonlight.Shared/Http/Requests/Admin/Users/CreateUserDto.cs b/Moonlight.Shared/Admin/Users/Users/CreateUserDto.cs similarity index 81% rename from Moonlight.Shared/Http/Requests/Admin/Users/CreateUserDto.cs rename to Moonlight.Shared/Admin/Users/Users/CreateUserDto.cs index 0c3b9d1b..9026f2f5 100644 --- a/Moonlight.Shared/Http/Requests/Admin/Users/CreateUserDto.cs +++ b/Moonlight.Shared/Admin/Users/Users/CreateUserDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.Users; +namespace Moonlight.Shared.Admin.Users.Users; public class CreateUserDto { diff --git a/Moonlight.Shared/Http/Requests/Admin/Users/UpdateUserDto.cs b/Moonlight.Shared/Admin/Users/Users/UpdateUserDto.cs similarity index 81% rename from Moonlight.Shared/Http/Requests/Admin/Users/UpdateUserDto.cs rename to Moonlight.Shared/Admin/Users/Users/UpdateUserDto.cs index 96b33e87..a2283a79 100644 --- a/Moonlight.Shared/Http/Requests/Admin/Users/UpdateUserDto.cs +++ b/Moonlight.Shared/Admin/Users/Users/UpdateUserDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Admin.Users; +namespace Moonlight.Shared.Admin.Users.Users; public class UpdateUserDto { diff --git a/Moonlight.Shared/Http/Responses/Admin/Users/UserDto.cs b/Moonlight.Shared/Admin/Users/Users/UserDto.cs similarity index 66% rename from Moonlight.Shared/Http/Responses/Admin/Users/UserDto.cs rename to Moonlight.Shared/Admin/Users/Users/UserDto.cs index 1060b50c..e8e9833b 100644 --- a/Moonlight.Shared/Http/Responses/Admin/Users/UserDto.cs +++ b/Moonlight.Shared/Admin/Users/Users/UserDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Admin.Users; +namespace Moonlight.Shared.Admin.Users.Users; public record UserDto(int Id, string Username, string Email, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Events/RebuildEventDto.cs b/Moonlight.Shared/Http/Events/RebuildEventDto.cs deleted file mode 100644 index ecfdefb8..00000000 --- a/Moonlight.Shared/Http/Events/RebuildEventDto.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Moonlight.Shared.Http.Events; - -public struct RebuildEventDto -{ - [JsonPropertyName("type")] - public RebuildEventType Type { get; set; } - - [JsonPropertyName("data")] - public string Data { get; set; } -} - -public enum RebuildEventType -{ - Log = 0, - Failed = 1, - Succeeded = 2, - Step = 3 -} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Settings/SetWhiteLabelingDto.cs b/Moonlight.Shared/Http/Requests/Admin/Settings/SetWhiteLabelingDto.cs deleted file mode 100644 index c0d2fa4a..00000000 --- a/Moonlight.Shared/Http/Requests/Admin/Settings/SetWhiteLabelingDto.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Moonlight.Shared.Http.Requests.Admin.Settings; - -public class SetWhiteLabelingDto -{ - [Required] - public string Name { get; set; } -} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Themes/CreateThemeDto.cs b/Moonlight.Shared/Http/Requests/Admin/Themes/CreateThemeDto.cs deleted file mode 100644 index 36374de0..00000000 --- a/Moonlight.Shared/Http/Requests/Admin/Themes/CreateThemeDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Moonlight.Shared.Http.Requests.Admin.Themes; - -public class CreateThemeDto -{ - [Required] - [MaxLength(30)] - public string Name { get; set; } - - [Required] - [MaxLength(30)] - public string Version { get; set; } - - [Required] - [MaxLength(30)] - public string Author { get; set; } - public bool IsEnabled { get; set; } - - [Required] - [MaxLength(20_000)] - public string CssContent { get; set; } -} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Themes/UpdateThemeDto.cs b/Moonlight.Shared/Http/Requests/Admin/Themes/UpdateThemeDto.cs deleted file mode 100644 index ead52a32..00000000 --- a/Moonlight.Shared/Http/Requests/Admin/Themes/UpdateThemeDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Moonlight.Shared.Http.Requests.Admin.Themes; - -public class UpdateThemeDto -{ - [Required] - [MaxLength(30)] - public string Name { get; set; } - - [Required] - [MaxLength(30)] - public string Version { get; set; } - - [Required] - [MaxLength(30)] - public string Author { get; set; } - public bool IsEnabled { get; set; } - - [Required] - [MaxLength(20_000)] - public string CssContent { get; set; } -} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/ApiKeys/ApiKeyDto.cs b/Moonlight.Shared/Http/Responses/Admin/ApiKeys/ApiKeyDto.cs deleted file mode 100644 index c3129546..00000000 --- a/Moonlight.Shared/Http/Responses/Admin/ApiKeys/ApiKeyDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Shared.Http.Responses.Admin.ApiKeys; - -public record ApiKeyDto(int Id, string Name, string Description, string[] Permissions, DateTimeOffset ValidUntil, string Key, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs b/Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs deleted file mode 100644 index 7d9ee7c1..00000000 --- a/Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Shared.Http.Responses.Admin.Auth; - -public record ClaimDto(string Type, string Value); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/DiagnoseResultDto.cs b/Moonlight.Shared/Http/Responses/Admin/DiagnoseResultDto.cs deleted file mode 100644 index 104b3e67..00000000 --- a/Moonlight.Shared/Http/Responses/Admin/DiagnoseResultDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Moonlight.Shared.Http.Responses.Admin; - -public record DiagnoseResultDto(DiagnoseLevel Level, string Title, string[] Tags, string? Message, string? StackStrace, string? SolutionUrl, string? ReportUrl); - -public enum DiagnoseLevel -{ - Error = 0, - Warning = 1, - Healthy = 2 -} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/RoleDto.cs b/Moonlight.Shared/Http/Responses/Admin/RoleDto.cs deleted file mode 100644 index 16675658..00000000 --- a/Moonlight.Shared/Http/Responses/Admin/RoleDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Shared.Http.Responses.Admin; - -public record RoleDto(int Id, string Name, string Description, string[] Permissions, int MemberCount, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/SystemInfoDto.cs b/Moonlight.Shared/Http/Responses/Admin/SystemInfoDto.cs deleted file mode 100644 index 48156082..00000000 --- a/Moonlight.Shared/Http/Responses/Admin/SystemInfoDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Shared.Http.Responses.Admin; - -public record SystemInfoDto(double CpuUsage, long MemoryUsage, string OperatingSystem, TimeSpan Uptime, string VersionName, bool IsUpToDate); \ No newline at end of file diff --git a/Moonlight.Shared/Moonlight.Shared.csproj b/Moonlight.Shared/Moonlight.Shared.csproj index 7910329d..c5f2f9f3 100644 --- a/Moonlight.Shared/Moonlight.Shared.csproj +++ b/Moonlight.Shared/Moonlight.Shared.csproj @@ -17,5 +17,9 @@ https://git.battlestati.one/Moonlight-Panel/Moonlight git - + + + + + \ No newline at end of file diff --git a/Moonlight.Shared/Permissions.cs b/Moonlight.Shared/Permissions.cs index 304b87e8..9befa627 100644 --- a/Moonlight.Shared/Permissions.cs +++ b/Moonlight.Shared/Permissions.cs @@ -4,53 +4,53 @@ public static class Permissions { public const string Prefix = "Permissions:"; public const string ClaimType = "Permissions"; - + public static class Users { private const string Section = "Users"; - + public const string View = $"{Prefix}{Section}.{nameof(View)}"; public const string Edit = $"{Prefix}{Section}.{nameof(Edit)}"; public const string Create = $"{Prefix}{Section}.{nameof(Create)}"; public const string Delete = $"{Prefix}{Section}.{nameof(Delete)}"; public const string Logout = $"{Prefix}{Section}.{nameof(Logout)}"; } - + public static class ApiKeys { private const string Section = "ApiKeys"; - + public const string View = $"{Prefix}{Section}.{nameof(View)}"; public const string Edit = $"{Prefix}{Section}.{nameof(Edit)}"; public const string Create = $"{Prefix}{Section}.{nameof(Create)}"; public const string Delete = $"{Prefix}{Section}.{nameof(Delete)}"; } - + public static class Roles { private const string Section = "Roles"; - + public const string View = $"{Prefix}{Section}.{nameof(View)}"; public const string Edit = $"{Prefix}{Section}.{nameof(Edit)}"; public const string Create = $"{Prefix}{Section}.{nameof(Create)}"; public const string Delete = $"{Prefix}{Section}.{nameof(Delete)}"; public const string Members = $"{Prefix}{Section}.{nameof(Members)}"; } - + public static class Themes { private const string Section = "Themes"; - + public const string View = $"{Prefix}{Section}.{nameof(View)}"; public const string Edit = $"{Prefix}{Section}.{nameof(Edit)}"; public const string Create = $"{Prefix}{Section}.{nameof(Create)}"; public const string Delete = $"{Prefix}{Section}.{nameof(Delete)}"; } - + public static class System { private const string Section = "System"; - + public const string Info = $"{Prefix}{Section}.{nameof(Info)}"; public const string Diagnose = $"{Prefix}{Section}.{nameof(Diagnose)}"; public const string Versions = $"{Prefix}{Section}.{nameof(Versions)}"; diff --git a/Moonlight.Shared/Http/SerializationContext.cs b/Moonlight.Shared/SerializationContext.cs similarity index 67% rename from Moonlight.Shared/Http/SerializationContext.cs rename to Moonlight.Shared/SerializationContext.cs index 85ec9019..422813c7 100644 --- a/Moonlight.Shared/Http/SerializationContext.cs +++ b/Moonlight.Shared/SerializationContext.cs @@ -1,21 +1,18 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Moonlight.Shared.Http.Events; -using Moonlight.Shared.Http.Requests.Admin.ApiKeys; -using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; -using Moonlight.Shared.Http.Requests.Admin.Roles; -using Moonlight.Shared.Http.Requests.Admin.Settings; -using Moonlight.Shared.Http.Requests.Admin.Themes; -using Moonlight.Shared.Http.Requests.Admin.Users; -using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Admin; -using Moonlight.Shared.Http.Responses.Admin.ApiKeys; -using Moonlight.Shared.Http.Responses.Admin.Auth; -using Moonlight.Shared.Http.Responses.Admin.Settings; -using Moonlight.Shared.Http.Responses.Admin.Themes; -using Moonlight.Shared.Http.Responses.Admin.Users; +using Moonlight.Shared.Admin.Sys; +using Moonlight.Shared.Admin.Sys.ApiKeys; +using Moonlight.Shared.Admin.Sys.ContainerHelper; +using Moonlight.Shared.Admin.Sys.Diagnose; +using Moonlight.Shared.Admin.Sys.Settings; +using Moonlight.Shared.Admin.Sys.Themes; +using Moonlight.Shared.Admin.Sys.Versions; +using Moonlight.Shared.Admin.Users.Roles; +using Moonlight.Shared.Admin.Users.Users; +using Moonlight.Shared.Shared; +using Moonlight.Shared.Shared.Auth; -namespace Moonlight.Shared.Http; +namespace Moonlight.Shared; // Users [JsonSerializable(typeof(CreateUserDto))] @@ -64,9 +61,7 @@ namespace Moonlight.Shared.Http; // Settings - White Labeling [JsonSerializable(typeof(WhiteLabelingDto))] [JsonSerializable(typeof(SetWhiteLabelingDto))] - [JsonSourceGenerationOptions(JsonSerializerDefaults.Web)] public partial class SerializationContext : JsonSerializerContext { - } \ No newline at end of file diff --git a/Moonlight.Shared/Shared/Auth/ClaimDto.cs b/Moonlight.Shared/Shared/Auth/ClaimDto.cs new file mode 100644 index 00000000..7109612e --- /dev/null +++ b/Moonlight.Shared/Shared/Auth/ClaimDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Shared.Shared.Auth; + +public record ClaimDto(string Type, string Value); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Auth/SchemeDto.cs b/Moonlight.Shared/Shared/Auth/SchemeDto.cs similarity index 50% rename from Moonlight.Shared/Http/Responses/Admin/Auth/SchemeDto.cs rename to Moonlight.Shared/Shared/Auth/SchemeDto.cs index 4c2218bf..e12197ff 100644 --- a/Moonlight.Shared/Http/Responses/Admin/Auth/SchemeDto.cs +++ b/Moonlight.Shared/Shared/Auth/SchemeDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Admin.Auth; +namespace Moonlight.Shared.Shared.Auth; public record SchemeDto(string Name, string DisplayName); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/FilterOptions.cs b/Moonlight.Shared/Shared/FilterOptions.cs similarity index 91% rename from Moonlight.Shared/Http/Requests/FilterOptions.cs rename to Moonlight.Shared/Shared/FilterOptions.cs index a12790d1..982aede5 100644 --- a/Moonlight.Shared/Http/Requests/FilterOptions.cs +++ b/Moonlight.Shared/Shared/FilterOptions.cs @@ -1,14 +1,12 @@ using System.Diagnostics.CodeAnalysis; -namespace Moonlight.Shared.Http.Requests; +namespace Moonlight.Shared.Shared; public class FilterOptions : IParsable { - public Dictionary Filters { get; set; } - public FilterOptions() { - Filters = new(); + Filters = new Dictionary(); } public FilterOptions(Dictionary filters) @@ -16,6 +14,8 @@ public class FilterOptions : IParsable Filters = filters; } + public Dictionary Filters { get; set; } + public static FilterOptions Parse(string s, IFormatProvider? provider) { if (!TryParse(s, provider, out var result)) @@ -30,7 +30,7 @@ public class FilterOptions : IParsable [MaybeNullWhen(false)] out FilterOptions result ) { - result = new(); + result = new FilterOptions(); if (string.IsNullOrEmpty(input)) return true; diff --git a/Moonlight.Shared/Http/Responses/Admin/Frontend/FrontendConfigDto.cs b/Moonlight.Shared/Shared/Frontend/FrontendConfigDto.cs similarity index 52% rename from Moonlight.Shared/Http/Responses/Admin/Frontend/FrontendConfigDto.cs rename to Moonlight.Shared/Shared/Frontend/FrontendConfigDto.cs index f1c7dd5a..c365ccbb 100644 --- a/Moonlight.Shared/Http/Responses/Admin/Frontend/FrontendConfigDto.cs +++ b/Moonlight.Shared/Shared/Frontend/FrontendConfigDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Admin.Frontend; +namespace Moonlight.Shared.Shared.Frontend; public record FrontendConfigDto(string Name, string? ThemeCss); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/PagedData.cs b/Moonlight.Shared/Shared/PagedData.cs similarity index 54% rename from Moonlight.Shared/Http/Responses/PagedData.cs rename to Moonlight.Shared/Shared/PagedData.cs index 1a1c7ed1..cf23eb61 100644 --- a/Moonlight.Shared/Http/Responses/PagedData.cs +++ b/Moonlight.Shared/Shared/PagedData.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses; +namespace Moonlight.Shared.Shared; public record PagedData(T[] Data, int TotalLength); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/ProblemDetails.cs b/Moonlight.Shared/Shared/ProblemDetails.cs similarity index 84% rename from Moonlight.Shared/Http/Responses/ProblemDetails.cs rename to Moonlight.Shared/Shared/ProblemDetails.cs index 0af3bc50..0362cccb 100644 --- a/Moonlight.Shared/Http/Responses/ProblemDetails.cs +++ b/Moonlight.Shared/Shared/ProblemDetails.cs @@ -1,4 +1,4 @@ -namespace Moonlight.Shared.Http.Responses; +namespace Moonlight.Shared.Shared; public class ProblemDetails { diff --git a/Moonlight.slnx b/Moonlight.slnx index 9ad99ce2..707486a1 100644 --- a/Moonlight.slnx +++ b/Moonlight.slnx @@ -1,9 +1,9 @@ - - - - - - - + + + + + + +