using System; using System.Collections.Generic; using Microsoft.Dynamics.AX.Metadata.Core.MetaModel; namespace D365MetadataBridge.Services { /// /// Text form of an AccessGrant — AxTable.SubscriberAccessLevel, "Subscriber access /// level" in Visual Studio. Six permissions, each Unset/Allow/Deny; the serializer /// writes only the set ones, as child elements. AccessGrant is a STRUCT: change a /// copy and assign it back, or the change is lost. /// internal static class AccessGrantText { private static readonly string[] Permissions = { "Correct", "Create", "Delete", "Invoke", "Read", "Update" }; /// "Create=Deny, Read=Allow" for the set permissions; null when none are. public static string? Describe(AccessGrant grant) { var parts = new List(); foreach (var name in Permissions) { var value = Get(grant, name); if (value != AccessGrantPermission.Unset) parts.Add($"{name}={value}"); } return parts.Count > 0 ? string.Join(", ", parts) : null; } /// /// Parse "Read=Allow,Create=Deny", a bare list "Read,Update" (Allow), or "None". /// Permissions not named are Unset. Throws ArgumentException on anything else. /// public static AccessGrant Parse(string? text) { var grant = new AccessGrant(); var s = (text ?? "").Trim(); if (s.Length == 0 || s.Equals("None", StringComparison.OrdinalIgnoreCase) || s.Equals("Unset", StringComparison.OrdinalIgnoreCase)) return grant; foreach (var raw in s.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)) { var pair = raw.Split(new[] { '=', ':' }, 2); var key = pair[0].Trim(); var name = Array.Find(Permissions, p => p.Equals(key, StringComparison.OrdinalIgnoreCase)) ?? throw new ArgumentException( $"Unknown subscriber permission '{key}'. Permissions: {string.Join(", ", Permissions)}; " + "values: Allow, Deny, Unset. Example: \"Read=Allow,Create=Deny\", or \"None\"."); var valueText = pair.Length > 1 ? pair[1].Trim() : "Allow"; if (!Enum.TryParse(valueText, true, out var value) || !Enum.IsDefined(typeof(AccessGrantPermission), value)) throw new ArgumentException( $"Invalid value '{valueText}' for subscriber permission {name}. Values: Allow, Deny, Unset."); grant = Set(grant, name, value); } return grant; } /// What Visual Studio sets on a new regular table: Read=Allow. public static AccessGrant VisualStudioDefault() => Set(new AccessGrant(), "Read", AccessGrantPermission.Allow); private static AccessGrantPermission Get(AccessGrant g, string name) { switch (name) { case "Correct": return g.Correct; case "Create": return g.Create; case "Delete": return g.Delete; case "Invoke": return g.Invoke; case "Read": return g.Read; default: return g.Update; } } private static AccessGrant Set(AccessGrant g, string name, AccessGrantPermission value) { switch (name) { case "Correct": g.Correct = value; break; case "Create": g.Create = value; break; case "Delete": g.Delete = value; break; case "Invoke": g.Invoke = value; break; case "Read": g.Read = value; break; default: g.Update = value; break; } return g; } } }