From ec7af67c9dd8a0eaa04f6ce3cbb7af5f99a8582d Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 1 Jun 2025 03:25:33 +0200 Subject: [PATCH] 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. --- .../HasMasterAuthoritiesAttribute.cs | 18 +++++ .../Atttibutes/HasMasterRolesAttribute.cs | 18 +++++ .../Atttibutes/MasterAuthorityAttribute.cs | 14 ++++ .../Atttibutes/MasterGroupAttribute.cs | 14 ++++ .../Atttibutes/MasterRoleAttribute.cs | 14 ++++ .../MasterData/MasterAuthorities.cs | 59 +++++++++++++++++ .../MasterData/MasterGroups.cs | 61 +++++++++++++++++ .../MasterData/MasterRoles.cs | 66 +++++++++++++++++++ 8 files changed, 264 insertions(+) create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterAuthoritiesAttribute.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterRolesAttribute.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterAuthorityAttribute.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterGroupAttribute.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterRoleAttribute.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterAuthorities.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterGroups.cs create mode 100644 src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterRoles.cs diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterAuthoritiesAttribute.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterAuthoritiesAttribute.cs new file mode 100644 index 0000000..7203b0b --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterAuthoritiesAttribute.cs @@ -0,0 +1,18 @@ +namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes; + +[AttributeUsage(AttributeTargets.Field)] +public class HasMasterAuthoritiesAttribute : Attribute +{ + public IReadOnlyList Authorities { get; init; } = []; + public bool AllAuthorities { get; init; } + + public HasMasterAuthoritiesAttribute(params string[] authorities) + { + Authorities = authorities; + } + + public HasMasterAuthoritiesAttribute(bool allAuthorities) + { + AllAuthorities = allAuthorities; + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterRolesAttribute.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterRolesAttribute.cs new file mode 100644 index 0000000..15013fa --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/HasMasterRolesAttribute.cs @@ -0,0 +1,18 @@ +namespace Suspectus.Gandalf.Palantir.Data.MasterData.Atttibutes; + +[AttributeUsage(AttributeTargets.Field)] +public class HasMasterRolesAttribute : Attribute +{ + public IReadOnlyList Roles { get; init; } = []; + public bool AllRoles { get; init; } + + public HasMasterRolesAttribute(params string[] roles) + { + Roles = roles; + } + + public HasMasterRolesAttribute(bool allRoles) + { + AllRoles = allRoles; + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterAuthorityAttribute.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterAuthorityAttribute.cs new file mode 100644 index 0000000..007cea5 --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterAuthorityAttribute.cs @@ -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; + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterGroupAttribute.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterGroupAttribute.cs new file mode 100644 index 0000000..234d0a3 --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterGroupAttribute.cs @@ -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; + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterRoleAttribute.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterRoleAttribute.cs new file mode 100644 index 0000000..777286e --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/Atttibutes/MasterRoleAttribute.cs @@ -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; + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterAuthorities.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterAuthorities.cs new file mode 100644 index 0000000..7bad799 --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterAuthorities.cs @@ -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 GetAllAuthorities() + { + var authorities = new List(); + CollectFields(typeof(MasterAuthorities)); + + return authorities + .Select(x => new MasterAuthorityData + { + Name = (string)x.GetValue(null)!, + OldName = x.GetCustomAttribute()!.OldKey, + Description = x.GetCustomAttribute()?.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; } + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterGroups.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterGroups.cs new file mode 100644 index 0000000..b3e4a41 --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterGroups.cs @@ -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 GetAllGroups() + { + var groups = new List(); + CollectFields(typeof(MasterGroups)); + + return groups + .Select(x => new MasterGroupData + { + Name = (string)x.GetValue(null)!, + OldName = x.GetCustomAttribute()!.OldKey, + Description = x.GetCustomAttribute()?.Description ?? null, + Roles = GetRoles(x) + }).ToList(); + + IReadOnlyList GetRoles(FieldInfo field) + { + var hasMasterRolesAttribute = field.GetCustomAttribute(); + + 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 Roles { get; set; } = []; + } +} \ No newline at end of file diff --git a/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterRoles.cs b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterRoles.cs new file mode 100644 index 0000000..abc390e --- /dev/null +++ b/src/dotnet/Suspectus.Gandalf.Palantir.Data/MasterData/MasterRoles.cs @@ -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 GetAllRoles() + { + var roles = new List(); + CollectFields(typeof(MasterRoles)); + + return roles + .Select(x => new MasterRoleData + { + Name = (string)x.GetValue(null)!, + OldName = x.GetCustomAttribute()!.OldKey, + Description = x.GetCustomAttribute()?.Description ?? null, + Authorities = GetAuthorities(x) + }).ToList(); + + IReadOnlyList GetAuthorities(FieldInfo field) + { + var hasMasterAuthoritiesAttribute = field.GetCustomAttribute(); + + 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 Authorities { get; set; } = []; + } +} \ No newline at end of file