Add MasterAuthorities, MasterRoles, and MasterGroups entities

Introduce MasterAuthorities, MasterRoles, and MasterGroups as extensions to centralize authority, role, and group definitions. Added associated attributes for better metadata handling, enabling streamlined retrieval and relationship management.
This commit is contained in:
Christian Werner 2025-06-01 03:25:33 +02:00
parent ba54eb7ec5
commit ec7af67c9d
8 changed files with 264 additions and 0 deletions

View File

@ -0,0 +1,18 @@
namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
[AttributeUsage(AttributeTargets.Field)]
public class HasMasterAuthoritiesAttribute : Attribute
{
public IReadOnlyList<string> Authorities { get; init; } = [];
public bool AllAuthorities { get; init; }
public HasMasterAuthoritiesAttribute(params string[] authorities)
{
Authorities = authorities;
}
public HasMasterAuthoritiesAttribute(bool allAuthorities)
{
AllAuthorities = allAuthorities;
}
}

View File

@ -0,0 +1,18 @@
namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
[AttributeUsage(AttributeTargets.Field)]
public class HasMasterRolesAttribute : Attribute
{
public IReadOnlyList<string> Roles { get; init; } = [];
public bool AllRoles { get; init; }
public HasMasterRolesAttribute(params string[] roles)
{
Roles = roles;
}
public HasMasterRolesAttribute(bool allRoles)
{
AllRoles = allRoles;
}
}

View File

@ -0,0 +1,14 @@
namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
[AttributeUsage(AttributeTargets.Field)]
public class MasterAuthorityAttribute : Attribute
{
public string? OldKey { get; init; }
public MasterAuthorityAttribute() {}
public MasterAuthorityAttribute(string? oldKey)
{
OldKey = oldKey;
}
}

View File

@ -0,0 +1,14 @@
namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
[AttributeUsage(AttributeTargets.Field)]
public class MasterGroupAttribute : Attribute
{
public string? OldKey { get; init; }
public MasterGroupAttribute() {}
public MasterGroupAttribute(string? oldKey)
{
OldKey = oldKey;
}
}

View File

@ -0,0 +1,14 @@
namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
[AttributeUsage(AttributeTargets.Field)]
public class MasterRoleAttribute : Attribute
{
public string? OldKey { get; init; }
public MasterRoleAttribute() {}
public MasterRoleAttribute(string? oldKey)
{
OldKey = oldKey;
}
}

View File

@ -0,0 +1,59 @@
using System.ComponentModel;
using System.Reflection;
using Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
namespace Suspectus.Gandalf.Palantir.Data.MasterData;
public static class MasterAuthorities
{
public static class Profile
{
[MasterAuthority] [Description("Allows to view any profile.")]
public const string Read = "g.profile.read";
[MasterAuthority] [Description("Allows to edit any profile.")]
public const string Write = "g.profile.write";
public static class Self
{
[MasterAuthority] [Description("Allows to view your own profile.")]
public const string Read = "g.profile.self.read";
[MasterAuthority] [Description("Allows to edit your own profile.")]
public const string Write = "g.profile.self.write";
}
}
public static List<MasterAuthorityData> GetAllAuthorities()
{
var authorities = new List<FieldInfo>();
CollectFields(typeof(MasterAuthorities));
return authorities
.Select(x => new MasterAuthorityData
{
Name = (string)x.GetValue(null)!,
OldName = x.GetCustomAttribute<MasterAuthorityAttribute>()!.OldKey,
Description = x.GetCustomAttribute<DescriptionAttribute>()?.Description ?? null
}).ToList();
void CollectFields(Type type)
{
var fields = type
.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(f => f.FieldType == typeof(string) && Attribute.IsDefined(f, typeof(MasterAuthorityAttribute)));
authorities.AddRange(fields);
foreach (var nested in type.GetNestedTypes())
CollectFields(nested);
}
}
public class MasterAuthorityData
{
public string Name { get; set; } = null!;
public string? OldName { get; set; }
public string? Description { get; set; }
}
}

View File

@ -0,0 +1,61 @@
using System.ComponentModel;
using System.Reflection;
using Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
namespace Suspectus.Gandalf.Palantir.Data.MasterData;
public static class MasterGroups
{
[MasterGroup]
[Description("Contains the minimal set of Roles to use the application.")]
[HasMasterRoles(MasterRoles.SelfProfile)]
public const string BasicUser = "Basic User";
public static List<MasterGroupData> GetAllGroups()
{
var groups = new List<FieldInfo>();
CollectFields(typeof(MasterGroups));
return groups
.Select(x => new MasterGroupData
{
Name = (string)x.GetValue(null)!,
OldName = x.GetCustomAttribute<MasterGroupAttribute>()!.OldKey,
Description = x.GetCustomAttribute<DescriptionAttribute>()?.Description ?? null,
Roles = GetRoles(x)
}).ToList();
IReadOnlyList<string> GetRoles(FieldInfo field)
{
var hasMasterRolesAttribute = field.GetCustomAttribute<HasMasterRolesAttribute>();
if (hasMasterRolesAttribute is null)
return [];
if (hasMasterRolesAttribute.AllRoles)
return MasterRoles.GetAllRoles().Select(x => x.Name).ToList();
return hasMasterRolesAttribute.Roles;
}
void CollectFields(Type type)
{
var fields = type
.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(f => f.FieldType == typeof(string) && Attribute.IsDefined(f, typeof(MasterGroupAttribute)));
groups.AddRange(fields);
foreach (var nested in type.GetNestedTypes())
CollectFields(nested);
}
}
public class MasterGroupData
{
public required string Name { get; set; }
public string? OldName { get; set; }
public string? Description { get; set; }
public IReadOnlyList<string> Roles { get; set; } = [];
}
}

View File

@ -0,0 +1,66 @@
using System.ComponentModel;
using System.Reflection;
using Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes;
namespace Suspectus.Gandalf.Palantir.Data.MasterData;
public static class MasterRoles
{
[MasterRole]
[Description("Allows everything.")]
[HasMasterAuthorities(true)]
public const string Housemaster = nameof(Housemaster);
[MasterRole]
[Description("Allows to view your own profile.")]
[HasMasterAuthorities(MasterAuthorities.Profile.Self.Read, MasterAuthorities.Profile.Self.Write)]
public const string SelfProfile = "Self Profile";
public static List<MasterRoleData> GetAllRoles()
{
var roles = new List<FieldInfo>();
CollectFields(typeof(MasterRoles));
return roles
.Select(x => new MasterRoleData
{
Name = (string)x.GetValue(null)!,
OldName = x.GetCustomAttribute<MasterRoleAttribute>()!.OldKey,
Description = x.GetCustomAttribute<DescriptionAttribute>()?.Description ?? null,
Authorities = GetAuthorities(x)
}).ToList();
IReadOnlyList<string> GetAuthorities(FieldInfo field)
{
var hasMasterAuthoritiesAttribute = field.GetCustomAttribute<HasMasterAuthoritiesAttribute>();
if (hasMasterAuthoritiesAttribute is null)
return [];
if (hasMasterAuthoritiesAttribute.AllAuthorities)
return MasterAuthorities.GetAllAuthorities().Select(x => x.Name).ToList();
return hasMasterAuthoritiesAttribute.Authorities;
}
void CollectFields(Type type)
{
var fields = type
.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(f => f.FieldType == typeof(string) && Attribute.IsDefined(f, typeof(MasterRoleAttribute)));
roles.AddRange(fields);
foreach (var nested in type.GetNestedTypes())
CollectFields(nested);
}
}
public class MasterRoleData
{
public required string Name { get; set; }
public string? OldName { get; set; }
public string? Description { get; set; }
public IReadOnlyList<string> Authorities { get; set; } = [];
}
}