Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
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>
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.
/// </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)
{
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.
/// </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.
/// </summary>
[YamlIgnore]
internal bool IsRuntime { get; set; } = false;

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