Improved server share permission handling and share ui

This commit is contained in:
2025-07-24 20:19:49 +02:00
parent 1f94752c54
commit 431cdcb260
19 changed files with 270 additions and 151 deletions

View File

@@ -1,3 +1,4 @@
using System.Text.Json;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using MoonCore.Extended.SingleDb; using MoonCore.Extended.SingleDb;
using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Configuration;
@@ -40,12 +41,15 @@ public class ServersDataContext : DatabaseContext
#region Shares #region Shares
modelBuilder.Ignore<ServerShareContent>(); modelBuilder.Ignore<ServerShareContent>();
modelBuilder.Ignore<ServerShareContent.SharePermission>();
modelBuilder.Entity<ServerShare>(builder => modelBuilder.Entity<ServerShare>(builder =>
{ {
builder.OwnsOne(x => x.Content, navigationBuilder => builder.OwnsOne(x => x.Content, navigationBuilder =>
{ {
navigationBuilder.ToJson(); navigationBuilder.ToJson();
navigationBuilder.OwnsMany(x => x.Permissions);
}); });
}); });

View File

@@ -9,6 +9,7 @@ using MoonCore.Models;
using Moonlight.ApiServer.Database.Entities; using Moonlight.ApiServer.Database.Entities;
using MoonlightServers.ApiServer.Database.Entities; using MoonlightServers.ApiServer.Database.Entities;
using MoonlightServers.ApiServer.Extensions; using MoonlightServers.ApiServer.Extensions;
using MoonlightServers.ApiServer.Mappers;
using MoonlightServers.ApiServer.Models; using MoonlightServers.ApiServer.Models;
using MoonlightServers.ApiServer.Services; using MoonlightServers.ApiServer.Services;
using MoonlightServers.Shared.Constants; using MoonlightServers.Shared.Constants;
@@ -153,7 +154,7 @@ public class ServersController : Controller
Share = new() Share = new()
{ {
SharedBy = owners.First(y => y.Id == x.Server.OwnerId).Username, SharedBy = owners.First(y => y.Id == x.Server.OwnerId).Username,
Permissions = x.Content.Permissions Permissions = ShareMapper.MapToPermissionLevels(x.Content)
} }
}).ToArray(); }).ToArray();
@@ -223,7 +224,7 @@ public class ServersController : Controller
response.Share = new() response.Share = new()
{ {
SharedBy = owner.Username, SharedBy = owner.Username,
Permissions = authorizationResult.Share.Content.Permissions Permissions = ShareMapper.MapToPermissionLevels(authorizationResult.Share.Content)
}; };
} }

View File

@@ -7,6 +7,8 @@ using MoonCore.Extended.Abstractions;
using MoonCore.Models; using MoonCore.Models;
using Moonlight.ApiServer.Database.Entities; using Moonlight.ApiServer.Database.Entities;
using MoonlightServers.ApiServer.Database.Entities; using MoonlightServers.ApiServer.Database.Entities;
using MoonlightServers.ApiServer.Mappers;
using MoonlightServers.ApiServer.Models;
using MoonlightServers.ApiServer.Services; using MoonlightServers.ApiServer.Services;
using MoonlightServers.Shared.Constants; using MoonlightServers.Shared.Constants;
using MoonlightServers.Shared.Enums; using MoonlightServers.Shared.Enums;
@@ -68,7 +70,7 @@ public class SharesController : Controller
{ {
Id = x.Id, Id = x.Id,
Username = users.First(y => y.Id == x.UserId).Username, Username = users.First(y => y.Id == x.UserId).Username,
Permissions = x.Content.Permissions Permissions = ShareMapper.MapToPermissionLevels(x.Content)
}).ToArray(); }).ToArray();
return new PagedData<ServerShareResponse>() return new PagedData<ServerShareResponse>()
@@ -104,13 +106,13 @@ public class SharesController : Controller
{ {
Id = share.Id, Id = share.Id,
Username = user.Username, Username = user.Username,
Permissions = share.Content.Permissions Permissions = ShareMapper.MapToPermissionLevels(share.Content)
}; };
return mappedItem; return mappedItem;
} }
[HttpPost("")] [HttpPost]
public async Task<ServerShareResponse> Create( public async Task<ServerShareResponse> Create(
[FromRoute] int serverId, [FromRoute] int serverId,
[FromBody] CreateShareRequest request [FromBody] CreateShareRequest request
@@ -128,10 +130,7 @@ public class SharesController : Controller
var share = new ServerShare() var share = new ServerShare()
{ {
Server = server, Server = server,
Content = new() Content = ShareMapper.MapToServerShareContent(request.Permissions),
{
Permissions = request.Permissions
},
CreatedAt = DateTime.UtcNow, CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow,
UserId = user.Id UserId = user.Id
@@ -143,7 +142,7 @@ public class SharesController : Controller
{ {
Id = finalShare.Id, Id = finalShare.Id,
Username = user.Username, Username = user.Username,
Permissions = finalShare.Content.Permissions Permissions = ShareMapper.MapToPermissionLevels(finalShare.Content)
}; };
return mappedItem; return mappedItem;
@@ -165,7 +164,8 @@ public class SharesController : Controller
if (share == null) if (share == null)
throw new HttpApiException("A share with that id cannot be found", 404); throw new HttpApiException("A share with that id cannot be found", 404);
share.Content.Permissions = request.Permissions; share.Content = ShareMapper.MapToServerShareContent(request.Permissions);
share.UpdatedAt = DateTime.UtcNow; share.UpdatedAt = DateTime.UtcNow;
await ShareRepository.Update(share); await ShareRepository.Update(share);
@@ -181,7 +181,7 @@ public class SharesController : Controller
{ {
Id = share.Id, Id = share.Id,
Username = user.Username, Username = user.Username,
Permissions = share.Content.Permissions Permissions = ShareMapper.MapToPermissionLevels(share.Content)
}; };
return mappedItem; return mappedItem;

View File

@@ -93,7 +93,7 @@ public class VariablesController : Controller
}; };
} }
[HttpPut("")] [HttpPut]
public async Task<ServerVariableDetailResponse> UpdateSingle( public async Task<ServerVariableDetailResponse> UpdateSingle(
[FromRoute] int serverId, [FromRoute] int serverId,
[FromBody] UpdateServerVariableRequest request [FromBody] UpdateServerVariableRequest request
@@ -123,7 +123,7 @@ public class VariablesController : Controller
}; };
} }
[HttpPatch("")] [HttpPatch]
public async Task<ServerVariableDetailResponse[]> Update( public async Task<ServerVariableDetailResponse[]> Update(
[FromRoute] int serverId, [FromRoute] int serverId,
[FromBody] UpdateServerVariableRangeRequest request [FromBody] UpdateServerVariableRangeRequest request

View File

@@ -45,13 +45,13 @@ public class ShareAuthFilter : IServerAuthorizationFilter
if (string.IsNullOrEmpty(permissionId) || requiredLevel == ServerPermissionLevel.None) if (string.IsNullOrEmpty(permissionId) || requiredLevel == ServerPermissionLevel.None)
return ServerAuthorizationResult.Success(share); return ServerAuthorizationResult.Success(share);
if ( var possiblePermShare = share.Content.Permissions.FirstOrDefault(x => x.Identifier == permissionId);
share.Content.Permissions.TryGetValue(permissionId, out var shareLevel) &&
shareLevel >= requiredLevel if (possiblePermShare == null)
) return null;
{
if (possiblePermShare.Level >= requiredLevel)
return ServerAuthorizationResult.Success(share); return ServerAuthorizationResult.Success(share);
}
return null; return null;
} }

View File

@@ -0,0 +1,27 @@
using MoonlightServers.ApiServer.Models;
using MoonlightServers.Shared.Enums;
using Riok.Mapperly.Abstractions;
namespace MoonlightServers.ApiServer.Mappers;
[Mapper]
public static partial class ShareMapper
{
public static ServerShareContent MapToServerShareContent(Dictionary<string, ServerPermissionLevel> permissionLevels)
{
return new ServerShareContent()
{
Permissions = permissionLevels.Select(x => new ServerShareContent.SharePermission()
{
Identifier = x.Key,
Level = x.Value
}).ToList()
};
}
public static Dictionary<string, ServerPermissionLevel> MapToPermissionLevels(
ServerShareContent content)
{
return content.Permissions.ToDictionary(x => x.Identifier, x => x.Level);
}
}

View File

@@ -2,7 +2,13 @@ using MoonlightServers.Shared.Enums;
namespace MoonlightServers.ApiServer.Models; namespace MoonlightServers.ApiServer.Models;
public class ServerShareContent public record ServerShareContent
{ {
public Dictionary<string, ServerPermissionLevel> Permissions { get; set; } = new(); public List<SharePermission> Permissions { get; set; } = new();
public record SharePermission
{
public string Identifier { get; set; }
public ServerPermissionLevel Level { get; set; }
}
} }

View File

@@ -0,0 +1,59 @@
using MoonlightServers.Frontend.Interfaces;
using MoonlightServers.Frontend.Models;
using MoonlightServers.Shared.Constants;
using MoonlightServers.Shared.Http.Responses.Client.Servers;
namespace MoonlightServers.Frontend.Implementations;
public class DefaultPermissionProvider : IServerPermissionProvider
{
public Task<ServerPermission[]> GetPermissions(ServerDetailResponse server)
{
ServerPermission[] permissions = [
new()
{
Identifier = ServerPermissionConstants.Console,
Description = "Allows access to the console",
DisplayName = "Console",
Icon = "icon-square-terminal"
},
new()
{
Identifier = ServerPermissionConstants.Files,
Description = "Allows access to the files",
DisplayName = "Files",
Icon = "icon-folder"
},
new()
{
Identifier = ServerPermissionConstants.Power,
Description = "Allows actions like turning off the server and starting it",
DisplayName = "Power",
Icon = "icon-power"
},
new()
{
Identifier = ServerPermissionConstants.Settings,
Description = "Gives permissions to perform re-installs or change other general settings",
DisplayName = "Settings",
Icon = "icon-settings"
},
new()
{
Identifier = ServerPermissionConstants.Shares,
Description = "Dangerous! This allows control to the available shares and their access level for a server",
DisplayName = "Shares",
Icon = "icon-users"
},
new()
{
Identifier = ServerPermissionConstants.Variables,
Description = "Allows access to the server software specific settings",
DisplayName = "Variables",
Icon = "icon-variable"
}
];
return Task.FromResult(permissions);
}
}

View File

@@ -1,6 +1,8 @@
using MoonlightServers.Frontend.Interfaces; using MoonlightServers.Frontend.Interfaces;
using MoonlightServers.Frontend.Models; using MoonlightServers.Frontend.Models;
using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs; using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs;
using MoonlightServers.Shared.Constants;
using MoonlightServers.Shared.Enums;
using MoonlightServers.Shared.Http.Responses.Client.Servers; using MoonlightServers.Shared.Http.Responses.Client.Servers;
namespace MoonlightServers.Frontend.Implementations; namespace MoonlightServers.Frontend.Implementations;
@@ -11,11 +13,11 @@ public class DefaultServerTabProvider : IServerTabProvider
{ {
ServerTab[] tabs = ServerTab[] tabs =
[ [
ServerTab.CreateFromComponent<ConsoleTab>("Console", "console", 0, permission => permission.Identifier == "console"), ServerTab.CreateFromComponent<ConsoleTab>("Console", "console", 0, ServerPermissionConstants.Console, ServerPermissionLevel.Read),
ServerTab.CreateFromComponent<FilesTab>("Files", "files", 1, permission => permission.Identifier == "files"), ServerTab.CreateFromComponent<FilesTab>("Files", "files", 1, ServerPermissionConstants.Files, ServerPermissionLevel.Read),
ServerTab.CreateFromComponent<SharesTab>("Shares", "shares", 2, permission => permission.Identifier == "shares"), ServerTab.CreateFromComponent<SharesTab>("Shares", "shares", 2, ServerPermissionConstants.Shares, ServerPermissionLevel.ReadWrite),
ServerTab.CreateFromComponent<VariablesTab>("Variables", "variables", 9, permission => permission.Identifier == "variables"), ServerTab.CreateFromComponent<VariablesTab>("Variables", "variables", 9, ServerPermissionConstants.Variables, ServerPermissionLevel.Read),
ServerTab.CreateFromComponent<SettingsTab>("Settings", "settings", 10, permission => permission.Identifier == "settings"), ServerTab.CreateFromComponent<SettingsTab>("Settings", "settings", 10, ServerPermissionConstants.Settings, ServerPermissionLevel.Read),
]; ];
return Task.FromResult(tabs); return Task.FromResult(tabs);

View File

@@ -0,0 +1,9 @@
using MoonlightServers.Frontend.Models;
using MoonlightServers.Shared.Http.Responses.Client.Servers;
namespace MoonlightServers.Frontend.Interfaces;
public interface IServerPermissionProvider
{
public Task<ServerPermission[]> GetPermissions(ServerDetailResponse server);
}

View File

@@ -0,0 +1,9 @@
namespace MoonlightServers.Frontend.Models;
public record ServerPermission
{
public string Identifier { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public string Icon { get; set; }
}

View File

@@ -112,10 +112,10 @@ public class ServerService
#region Variables #region Variables
public async Task<ServerVariableDetailResponse[]> GetVariables(int serverId) public async Task<PagedData<ServerVariableDetailResponse>> GetVariables(int serverId, int page, int pageSize)
{ {
return await HttpApiClient.GetJson<ServerVariableDetailResponse[]>( return await HttpApiClient.GetJson<PagedData<ServerVariableDetailResponse>>(
$"api/client/servers/{serverId}/variables" $"api/client/servers/{serverId}/variables?page={page}&pageSize={pageSize}"
); );
} }

View File

@@ -14,6 +14,7 @@ public class PluginStartup : IPluginStartup
{ {
builder.Services.AddSingleton<ISidebarItemProvider, SidebarImplementation>(); builder.Services.AddSingleton<ISidebarItemProvider, SidebarImplementation>();
builder.Services.AddSingleton<IServerTabProvider, DefaultServerTabProvider>(); builder.Services.AddSingleton<IServerTabProvider, DefaultServerTabProvider>();
builder.Services.AddSingleton<IServerPermissionProvider, DefaultPermissionProvider>();
builder.Services.AutoAddServices<PluginStartup>(); builder.Services.AutoAddServices<PluginStartup>();

View File

@@ -1,7 +1,7 @@
@using MoonCore.Blazor.FlyonUi.Components @using MoonCore.Blazor.FlyonUi.Components
@using MoonlightServers.Shared.Enums @using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares @using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares
@using MoonlightServers.Shared.Models @using MoonlightServers.Shared.Http.Responses.Client.Servers
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal @inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -14,48 +14,7 @@
<label class="block text-sm font-medium leading-6 text-base-content">Username</label> <label class="block text-sm font-medium leading-6 text-base-content">Username</label>
<input @bind="Request.Username" type="text" class="input w-full"/> <input @bind="Request.Username" type="text" class="input w-full"/>
</div> </div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-y-5 lg:gap-y-3"> <PermissionEditor Server="Server" PermissionLevels="Permissions" />
@foreach (var name in Names)
{
var i = Permissions.TryGetValue(name, out var permission) ? (int)permission : -1;
<div class="col-span-1 flex flex-col justify-center lg:justify-start text-center lg:text-start">
<span>@name</span>
<span class="text-base-content/80 text-sm">This is a long description</span>
</div>
<div class="col-span-1 flex justify-end">
<div class="join drop-shadow">
@if (i == -1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None" checked="checked"/>
}
else
{
<input @onclick="() => Reset(name)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None"/>
}
@if (i == 0)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.Read)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read"/>
}
@if (i == 1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.ReadWrite)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write"/>
}
</div>
</div>
}
</div>
</HandleForm> </HandleForm>
<div class="mt-8 flex space-x-2"> <div class="mt-8 flex space-x-2">
@@ -65,6 +24,7 @@
@code @code
{ {
[Parameter] public ServerDetailResponse Server { get; set; }
[Parameter] public string Username { get; set; } [Parameter] public string Username { get; set; }
[Parameter] public Func<CreateShareRequest, Task> OnSubmit { get; set; } [Parameter] public Func<CreateShareRequest, Task> OnSubmit { get; set; }
@@ -97,22 +57,12 @@
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }
private async Task Reset(string name)
{
Permissions.Remove(name);
await InvokeAsync(StateHasChanged);
}
private async Task Submit() private async Task Submit()
=> await HandleForm.Submit(); => await HandleForm.Submit();
private async Task OnValidSubmit() private async Task OnValidSubmit()
{ {
Request.Permissions = Permissions.Select(x => new GrantedServerPermission() Request.Permissions = Permissions;
{
Identifier = x.Key,
Level = x.Value
}).ToList();
await OnSubmit.Invoke(Request); await OnSubmit.Invoke(Request);
await Hide(); await Hide();

View File

@@ -0,0 +1,95 @@
@using MoonlightServers.Frontend.Interfaces
@using MoonCore.Blazor.FlyonUi.Components
@using MoonlightServers.Frontend.Models
@using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Responses.Client.Servers
@inject IEnumerable<IServerPermissionProvider> PermissionProviders
<LazyLoader Load="Load">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-y-3">
@foreach (var permission in AvailablePermissions)
{
var level = PermissionLevels.GetValueOrDefault(permission.Identifier, ServerPermissionLevel.None);
<div class="col-span-1 flex flex-row items-center justify-start text-base-content">
<i class="text-lg @permission.Icon me-4"></i>
<div class="flex flex-col">
<span>@permission.DisplayName</span>
<span class="text-base-content/60 text-sm">@permission.Description</span>
</div>
</div>
<div class="col-span-1 flex justify-start lg:justify-end mb-5 lg:mb-0">
<div class="join drop-shadow">
@if (level == ServerPermissionLevel.None)
{
<input class="join-item btn btn-soft" type="radio" name="share-@permission.Identifier"
aria-label="None"
checked="checked"/>
}
else
{
<input @onclick="() => Set(permission.Identifier, ServerPermissionLevel.None)"
class="join-item btn btn-soft"
type="radio" name="share-@permission.Identifier" aria-label="None"/>
}
@if (level == ServerPermissionLevel.Read)
{
<input class="join-item btn btn-soft" type="radio" name="share-@permission.Identifier"
aria-label="Read"
checked="checked"/>
}
else
{
<input @onclick="() => Set(permission.Identifier, ServerPermissionLevel.Read)"
class="join-item btn btn-soft"
type="radio" name="share-@permission.Identifier" aria-label="Read"/>
}
@if (level == ServerPermissionLevel.ReadWrite)
{
<input class="join-item btn btn-soft" type="radio" name="share-@permission.Identifier"
aria-label="Read & Write"
checked="checked"/>
}
else
{
<input @onclick="() => Set(permission.Identifier, ServerPermissionLevel.ReadWrite)"
class="join-item btn btn-soft"
type="radio" name="share-@permission.Identifier" aria-label="Read & Write"/>
}
</div>
</div>
}
</div>
</LazyLoader>
@code
{
[Parameter] public ServerDetailResponse Server { get; set; }
[Parameter] public Dictionary<string, ServerPermissionLevel> PermissionLevels { get; set; }
private ServerPermission[] AvailablePermissions;
private async Task Load(LazyLoader _)
{
var permissions = new List<ServerPermission>();
foreach (var provider in PermissionProviders)
{
permissions.AddRange(
await provider.GetPermissions(Server)
);
}
AvailablePermissions = permissions.ToArray();
}
private async Task Set(string name, ServerPermissionLevel level)
{
PermissionLevels[name] = level;
await InvokeAsync(StateHasChanged);
}
}

View File

@@ -75,6 +75,7 @@
await ModalService.Launch<CreateShareModal>(parameters => await ModalService.Launch<CreateShareModal>(parameters =>
{ {
parameters["Username"] = UsernameInput; parameters["Username"] = UsernameInput;
parameters["Server"] = Server;
parameters["OnSubmit"] = SubmitCreate; parameters["OnSubmit"] = SubmitCreate;
}, size: "max-w-2xl"); }, size: "max-w-2xl");
} }
@@ -92,6 +93,7 @@
await ModalService.Launch<UpdateShareModal>(parameters => await ModalService.Launch<UpdateShareModal>(parameters =>
{ {
parameters["Share"] = share; parameters["Share"] = share;
parameters["Server"] = Server;
parameters["OnSubmit"] = (UpdateShareRequest request) => SubmitUpdate(share.Id, request); parameters["OnSubmit"] = (UpdateShareRequest request) => SubmitUpdate(share.Id, request);
}, size: "max-w-2xl"); }, size: "max-w-2xl");
} }

View File

@@ -1,5 +1,6 @@
@using MoonCore.Blazor.FlyonUi.Components @using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts @using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Models
@using MoonlightServers.Frontend.Services @using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Http.Responses.Client.Servers.Variables @using MoonlightServers.Shared.Http.Responses.Client.Servers.Variables
@@ -8,7 +9,7 @@
@inject ServerService ServerService @inject ServerService ServerService
@inject ToastService ToastService @inject ToastService ToastService
<LazyLoader Load="Load"> <LazyLoader @ref="LazyLoader" Load="Load">
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6"> <div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
@foreach (var variable in Variables) @foreach (var variable in Variables)
{ {
@@ -37,10 +38,13 @@
@code @code
{ {
private ServerVariableDetailResponse[] Variables; private ServerVariableDetailResponse[] Variables;
private LazyLoader LazyLoader;
private async Task Load(LazyLoader _) private async Task Load(LazyLoader _)
{ {
Variables = await ServerService.GetVariables(Server.Id); Variables = await PagedData<ServerVariableDetailResponse>.All(async (page, pageSize)
=> await ServerService.GetVariables(Server.Id, page, pageSize)
);
} }
private async Task UpdateVariable(ServerVariableDetailResponse variable, ChangeEventArgs args) private async Task UpdateVariable(ServerVariableDetailResponse variable, ChangeEventArgs args)
@@ -54,8 +58,7 @@
}); });
// Fetch the current data to make sure the user sees the latest data // Fetch the current data to make sure the user sees the latest data
Variables = await ServerService.GetVariables(Server.Id); await LazyLoader.Reload();
await InvokeAsync(StateHasChanged);
await ToastService.Success("Successfully updated variable"); await ToastService.Success("Successfully updated variable");
} }

View File

@@ -1,6 +1,7 @@
@using MoonCore.Blazor.FlyonUi.Components @using MoonCore.Blazor.FlyonUi.Components
@using MoonlightServers.Shared.Enums @using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares @using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares
@using MoonlightServers.Shared.Http.Responses.Client.Servers
@using MoonlightServers.Shared.Http.Responses.Client.Servers.Shares @using MoonlightServers.Shared.Http.Responses.Client.Servers.Shares
@using MoonlightServers.Shared.Models @using MoonlightServers.Shared.Models
@@ -11,48 +12,7 @@
</div> </div>
<HandleForm @ref="HandleForm" Model="Request" OnValidSubmit="OnValidSubmit"> <HandleForm @ref="HandleForm" Model="Request" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-y-5 lg:gap-y-3"> <PermissionEditor Server="Server" PermissionLevels="Permissions" />
@foreach (var name in Names)
{
var i = Permissions.TryGetValue(name, out var permission) ? (int)permission : -1;
<div class="col-span-1 flex flex-col justify-center lg:justify-start text-center lg:text-start">
<span>@name</span>
<span class="text-base-content/80 text-sm">This is a long description</span>
</div>
<div class="col-span-1 flex justify-end">
<div class="join drop-shadow">
@if (i == -1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None" checked="checked"/>
}
else
{
<input @onclick="() => Reset(name)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None"/>
}
@if (i == 0)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.Read)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read"/>
}
@if (i == 1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.ReadWrite)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write"/>
}
</div>
</div>
}
</div>
</HandleForm> </HandleForm>
<div class="mt-8 flex space-x-2"> <div class="mt-8 flex space-x-2">
@@ -62,6 +22,7 @@
@code @code
{ {
[Parameter] public ServerDetailResponse Server { get; set; }
[Parameter] public ServerShareResponse Share { get; set; } [Parameter] public ServerShareResponse Share { get; set; }
[Parameter] public Func<UpdateShareRequest, Task> OnSubmit { get; set; } [Parameter] public Func<UpdateShareRequest, Task> OnSubmit { get; set; }
@@ -84,7 +45,7 @@
{ {
Request = new(); Request = new();
Permissions = Share.Permissions.ToDictionary(x => x.Identifier, x => x.Level); Permissions = Share.Permissions;
} }
private async Task Set(string name, ServerPermissionLevel level) private async Task Set(string name, ServerPermissionLevel level)
@@ -93,22 +54,12 @@
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }
private async Task Reset(string name)
{
Permissions.Remove(name);
await InvokeAsync(StateHasChanged);
}
private async Task Submit() private async Task Submit()
=> await HandleForm.Submit(); => await HandleForm.Submit();
private async Task OnValidSubmit() private async Task OnValidSubmit()
{ {
Request.Permissions = Permissions.Select(x => new GrantedServerPermission() Request.Permissions = Permissions;
{
Identifier = x.Key,
Level = x.Value
}).ToList();
await OnSubmit.Invoke(Request); await OnSubmit.Invoke(Request);
await Hide(); await Hide();

View File

@@ -223,12 +223,12 @@
if (string.IsNullOrEmpty(tab.PermissionId) || tab.PermissionLevel == ServerPermissionLevel.None) if (string.IsNullOrEmpty(tab.PermissionId) || tab.PermissionLevel == ServerPermissionLevel.None)
return false; return false;
// If permission is required but not set, we dont have access to it // If permission is required but not set, we don't have access to it
if (!Server.Share.Permissions.TryGetValue(tab.PermissionId, out var level)) if (!Server.Share.Permissions.TryGetValue(tab.PermissionId, out var level))
return true; return true;
// True if the acquired level is higher or equal than the required permission level for the tba // False if the acquired level is higher or equal than the required permission level for the tab so it won't get removed
return level >= tab.PermissionLevel; return level < tab.PermissionLevel;
}); });
} }