Skip to content
38 changes: 29 additions & 9 deletions LabApi/Features/Permissions/PermissionsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using LabApi.Features.Wrappers;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace LabApi.Features.Permissions;
Expand Down Expand Up @@ -31,13 +32,7 @@ public static void RegisterProvider<T>()
return;
}

if (Activator.CreateInstance<T>() is not IPermissionsProvider provider)
{
Logger.Error($"{LoggerPrefix} Failed to create an instance of the permission provider of type {typeof(T).FullName}.");
return;
}

PermissionProviders.Add(typeof(T), provider);
PermissionProviders.Add(typeof(T), new T());
}

/// <summary>
Expand All @@ -62,13 +57,38 @@ public static void UnregisterProvider<T>()
/// <returns>The registered <see cref="IPermissionsProvider"/> of the given type <typeparamref name="T"/>; otherwise, null.</returns>
public static IPermissionsProvider? GetProvider<T>()
where T : IPermissionsProvider, new()
=> GetProvider(typeof(T));

/// <summary>
/// Retrieves the registered <see cref="IPermissionsProvider"/> of the given type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of the permission provider to retrieve.</typeparam>
/// <returns>The registered <see cref="IPermissionsProvider"/> of the given type <typeparamref name="T"/>; otherwise, null.</returns>
public static bool TryGetProvider<T>([NotNullWhen(true)] out T? provider)
where T : class, IPermissionsProvider, new()
{
if (PermissionProviders.TryGetValue(typeof(T), out IPermissionsProvider provider))
provider = GetProvider(typeof(T)) as T;
return provider != null;
}

/// <summary>
/// Retrieves the registered <see cref="IPermissionsProvider"/> of the given type <paramref name="providerType"/>.
/// </summary>
/// <param name="providerType">The type of the permission provider to retrieve.</param>
/// <returns>The registered <see cref="IPermissionsProvider"/> of the given type <paramref name="providerType"/>; otherwise, null.</returns>
public static IPermissionsProvider? GetProvider(Type providerType)
{
if (providerType == null)
{
throw new ArgumentNullException(nameof(providerType));
}

if (PermissionProviders.TryGetValue(providerType, out IPermissionsProvider provider))
{
return provider;
}

Logger.Warn($"{LoggerPrefix} The permission provider of type {typeof(T).FullName} is not registered.");
Logger.Warn($"{LoggerPrefix} The permission provider of type {providerType.FullName} is not registered.");
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Serialization;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;

Expand Down Expand Up @@ -110,9 +111,36 @@ public void RemovePermissions(Player player, params string[] permissions)
/// <inheritdoc />
void IPermissionsProvider.ReloadPermissions() => ReloadPermissions();

private PermissionGroup GetPlayerGroup(Player player) => _permissionsDictionary.GetValueOrDefault(player.PermissionsGroupName ?? "default") ?? PermissionGroup.Default;
/// <summary>
/// Gets the <see cref="PermissionGroup"/> the player is a part of.
/// </summary>
/// <param name="player">The player whose <see cref="PermissionGroup"/> to find.</param>
/// <returns>The <see cref="PermissionGroup"/> the player is a part of, otherwise <see cref="PermissionGroup.Default"/>.</returns>
public PermissionGroup GetPlayerGroup(Player player) => GetPermissionGroup(player.PermissionsGroupName ?? "default");

/// <summary>
/// Gets the <see cref="PermissionGroup"/> from a <see cref="UserGroup"/>'s registry name.
/// </summary>
/// <param name="groupName">A <see cref="UserGroup"/>'s registry name to find the <see cref="PermissionGroup"/> of.</param>
/// <returns>The <see cref="PermissionGroup"/> if one is defined, <see cref="PermissionGroup.Default"/> otherwise.</returns>
/// <remarks>The <paramref name="groupName"/> should be a key in <see cref="PermissionsHandler.Groups"/> and not necessarily the <see cref="UserGroup.Name"/> as they can differ.</remarks>
Comment thread
OMEGA3065 marked this conversation as resolved.
Outdated
public PermissionGroup GetPermissionGroup(string groupName) => _permissionsDictionary.GetValueOrDefault(groupName) ?? PermissionGroup.Default;

private string[] GetPermissions(PermissionGroup group)
/// <summary>
/// Tries to get the <see cref="PermissionGroup"/> from a <see cref="UserGroup"/>'s registry name.
/// </summary>
/// <param name="groupName">A <see cref="UserGroup"/>'s registry name to find the <see cref="PermissionGroup"/> of.</param>
/// <param name="permissionGroup">The found <see cref="PermissionGroup"/> when true, null otherwise.</param>
/// <returns>Whether a <see cref="PermissionGroup"/> with the registry name of <paramref name="groupName"/> was found.</returns>
/// <remarks>The <paramref name="groupName"/> should be a key in <see cref="PermissionsHandler.Groups"/> and not necessarily the <see cref="UserGroup.Name"/> as they can differ.</remarks>
Comment thread
OMEGA3065 marked this conversation as resolved.
Outdated
public bool TryGetPermissionGroup(string groupName, [NotNullWhen(true)] out PermissionGroup? permissionGroup) => _permissionsDictionary.TryGetValue(groupName, out permissionGroup);

/// <summary>
/// Gets the <see cref="string"/>[] of permissions a <see cref="PermissionGroup"/> grants.
Comment thread
OMEGA3065 marked this conversation as resolved.
Outdated
/// </summary>
/// <param name="group">The <see cref="PermissionGroup"/>, permissions of which will be returned.</param>
/// <returns>A <see cref="string"/> array of permission to this group grants.</returns>
public string[] GetPermissions(PermissionGroup group)
{
List<string> permissions = ListPool<string>.Shared.Rent();

Expand All @@ -132,6 +160,45 @@ private string[] GetPermissions(PermissionGroup group)
return [.. permissions];
}

/// <summary>
/// Adds a new permission group or overrides an existing permission group.
/// </summary>
/// <param name="groupName">The registry name of a permission group.</param>
/// <param name="group">The group to add.</param>
/// <param name="overrideExisting">Whether to override any existing group.</param>
/// <returns>Whether the group was successfully added, always true if <paramref name="overrideExisting"/> is true.</returns>
/// <remarks>
/// The <paramref name="groupName"/> is used to get permissions of a player using <see cref="Player.PermissionsGroupName"/>.
/// The <paramref name="groupName"/> can also be obtained from a <see cref="UserGroup"/>'s registry name.
/// WARNING: If used to remove a group which wasn't created at runtime it can cause a change to the <see cref="PermissionsFileName"/> file's contents.
/// WARNING: It marks all permission groups as Runtime, and as such when overriding a group it can cause it to be deleted if it was previously obtained from the <see cref="PermissionsFileName"/> file.
/// </remarks>
public bool AddPermissionGroup(string groupName, PermissionGroup group, bool overrideExisting = false)
Comment thread
OMEGA3065 marked this conversation as resolved.
Outdated
{
group.IsRuntime = true;
if (overrideExisting)
{
_permissionsDictionary[groupName] = group;
return true;
}

return _permissionsDictionary.TryAdd(groupName, group);
}

/// <summary>
/// Adds a new permission group or overrides an existing permission group.
/// </summary>
/// <param name="groupName">The registry name of a permission group.</param>
/// <param name="group">The group which was removed or null.</param>
/// <returns>Whether the group was found and removed successfully.</returns>
/// <remarks>
/// The <paramref name="groupName"/> is used to get permissions of a player using <see cref="Player.PermissionsGroupName"/>.
/// The <paramref name="groupName"/> can also be obtained from a <see cref="UserGroup"/>'s registry name.
/// WARNING: If used to remove a group which wasn't created at runtime it can cause a change to the <see cref="PermissionsFileName"/> file's contents.
Comment thread
OMEGA3065 marked this conversation as resolved.
Outdated
/// </remarks>
public bool RemovePermissionGroup(string groupName, [NotNullWhen(true)] out PermissionGroup? group)
=> _permissionsDictionary.Remove(groupName, out group);

private bool HasPermission(PermissionGroup group, string permission)
{
if (group.IsRoot)
Expand Down Expand Up @@ -208,5 +275,5 @@ private void ReloadPermissions()
}
}

private void SavePermissions() => File.WriteAllText(_permissions.FullName, YamlParser.Serializer.Serialize(_permissionsDictionary));
private void SavePermissions() => File.WriteAllText(_permissions.FullName, YamlParser.Serializer.Serialize(_permissionsDictionary.Where(kvp => !kvp.Value.IsRuntime).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)));
}
6 changes: 6 additions & 0 deletions LabApi/Features/Permissions/Providers/PermissionGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public PermissionGroup(string[] inheritedGroups, string[] permissions)
[YamlIgnore]
public bool IsRoot { get; set; } = false;

/// <summary>
/// An internal bool indicating whether the permission was created at runtime and as such should not be saved.
Comment thread
OMEGA3065 marked this conversation as resolved.
Outdated
/// </summary>
[YamlIgnore]
internal bool IsRuntime { get; set; } = false;

/// <summary>
/// An internal dictionary that saves special permissions. (x.*).
/// </summary>
Expand Down