diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b210976 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "external/EAVFW.Extensions.CommandLine"] + path = external/EAVFW.Extensions.CommandLine + url = https://github.com/EAVFW/EAVFW.Extensions.CommandLine.git +[submodule "external/EAVFramework"] + path = external/EAVFramework + url = https://github.com/EAVFW/EAVFramework.git diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..7925b0d --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,10 @@ + + + 9.0 + 4.0.2 + true + $(MSBuildThisFileDirectory)/external/EAVFramework + $(MSBuildThisFileDirectory)/external + $(MSBuildThisFileDirectory) + + \ No newline at end of file diff --git a/EAVFW.Extensions.Manifest.ManifestEnricherTool.sln b/EAVFW.Extensions.Manifest.ManifestEnricherTool.sln index 2fab67a..17168f8 100644 --- a/EAVFW.Extensions.Manifest.ManifestEnricherTool.sln +++ b/EAVFW.Extensions.Manifest.ManifestEnricherTool.sln @@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5250CA28-EB3D-4DF8-8B5B-68D520CADDEE}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore + Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection EndProject @@ -29,30 +30,26 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".config", ".config", "{4AFE .config\dotnet-tools.json = .config\dotnet-tools.json EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eavfw", "eavfw", "{99FD28D4-904E-4601-8B15-BAE281F48576}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFW.Extensions.Manifest.SDK", "src\EAVFW.Extensions.Manifest.SDK\EAVFW.Extensions.Manifest.SDK.csproj", "{A69F8562-BDDF-4DE9-8768-E51B1FFFD368}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFramework", "..\EAVFramework\src\EAVFramework.csproj", "{B8E00220-CF68-4B02-831C-15E16D61E996}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0343EA18-1645-4DFB-9A9C-2D10BBA2A2CB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFW.Extensions.Manifest.ManifestEnricherTool", "src\EAVFW.Extensions.Manifest.ManifestEnricherTool\EAVFW.Extensions.Manifest.ManifestEnricherTool.csproj", "{C472564C-38FE-4465-BC62-FDCF45339C36}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFW.Extensions.Manifest.Tests", "tests\EAVFW.Extensions.Manifest.Tests\EAVFW.Extensions.Manifest.Tests.csproj", "{856357CE-BB26-4E6C-BAA2-B74FF8DC5734}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "external", "external", "{CAE8FBC9-BDC3-4F45-81E1-57506D609011}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFW.Extensions.CommandLine", "external\EAVFW.Extensions.CommandLine\src\EAVFW.Extensions.CommandLine\EAVFW.Extensions.CommandLine.csproj", "{79505337-2855-4CC7-8FD3-D5AF31B18278}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFramework", "external\EAVFramework\src\EAVFramework.csproj", "{2F30C24A-421A-4309-9F07-99668EA70C25}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EAVFW.Extensions.Manifest.SDK", "external\EAVFramework\sdk\EAVFW.Extensions.Manifest.SDK.csproj", "{3BEF0769-ABD1-4D34-8004-C98DE9FB0339}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A69F8562-BDDF-4DE9-8768-E51B1FFFD368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A69F8562-BDDF-4DE9-8768-E51B1FFFD368}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A69F8562-BDDF-4DE9-8768-E51B1FFFD368}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A69F8562-BDDF-4DE9-8768-E51B1FFFD368}.Release|Any CPU.Build.0 = Release|Any CPU - {B8E00220-CF68-4B02-831C-15E16D61E996}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B8E00220-CF68-4B02-831C-15E16D61E996}.Release|Any CPU.ActiveCfg = Debug|Any CPU {C472564C-38FE-4465-BC62-FDCF45339C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C472564C-38FE-4465-BC62-FDCF45339C36}.Debug|Any CPU.Build.0 = Debug|Any CPU {C472564C-38FE-4465-BC62-FDCF45339C36}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -61,16 +58,29 @@ Global {856357CE-BB26-4E6C-BAA2-B74FF8DC5734}.Debug|Any CPU.Build.0 = Debug|Any CPU {856357CE-BB26-4E6C-BAA2-B74FF8DC5734}.Release|Any CPU.ActiveCfg = Release|Any CPU {856357CE-BB26-4E6C-BAA2-B74FF8DC5734}.Release|Any CPU.Build.0 = Release|Any CPU + {79505337-2855-4CC7-8FD3-D5AF31B18278}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79505337-2855-4CC7-8FD3-D5AF31B18278}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79505337-2855-4CC7-8FD3-D5AF31B18278}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79505337-2855-4CC7-8FD3-D5AF31B18278}.Release|Any CPU.Build.0 = Release|Any CPU + {2F30C24A-421A-4309-9F07-99668EA70C25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F30C24A-421A-4309-9F07-99668EA70C25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F30C24A-421A-4309-9F07-99668EA70C25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F30C24A-421A-4309-9F07-99668EA70C25}.Release|Any CPU.Build.0 = Release|Any CPU + {3BEF0769-ABD1-4D34-8004-C98DE9FB0339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3BEF0769-ABD1-4D34-8004-C98DE9FB0339}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3BEF0769-ABD1-4D34-8004-C98DE9FB0339}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3BEF0769-ABD1-4D34-8004-C98DE9FB0339}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {E8050101-10D8-4B0E-B081-8A45BA2E4A61} = {C88FCAB5-AE8A-44CD-9195-2B085A6CD560} - {A69F8562-BDDF-4DE9-8768-E51B1FFFD368} = {0D61C87C-0809-4CD7-9200-D78AD11A1E22} - {B8E00220-CF68-4B02-831C-15E16D61E996} = {99FD28D4-904E-4601-8B15-BAE281F48576} {C472564C-38FE-4465-BC62-FDCF45339C36} = {0D61C87C-0809-4CD7-9200-D78AD11A1E22} {856357CE-BB26-4E6C-BAA2-B74FF8DC5734} = {0343EA18-1645-4DFB-9A9C-2D10BBA2A2CB} + {79505337-2855-4CC7-8FD3-D5AF31B18278} = {CAE8FBC9-BDC3-4F45-81E1-57506D609011} + {2F30C24A-421A-4309-9F07-99668EA70C25} = {CAE8FBC9-BDC3-4F45-81E1-57506D609011} + {3BEF0769-ABD1-4D34-8004-C98DE9FB0339} = {CAE8FBC9-BDC3-4F45-81E1-57506D609011} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {036D5D82-DDA4-4600-B190-739D512F1062} diff --git a/external/EAVFW.Extensions.CommandLine b/external/EAVFW.Extensions.CommandLine new file mode 160000 index 0000000..e4ebadf --- /dev/null +++ b/external/EAVFW.Extensions.CommandLine @@ -0,0 +1 @@ +Subproject commit e4ebadf936ae756a474263b04cf367a5bc41c194 diff --git a/external/EAVFramework b/external/EAVFramework new file mode 160000 index 0000000..65e40e2 --- /dev/null +++ b/external/EAVFramework @@ -0,0 +1 @@ +Subproject commit 65e40e29208c746d0580ee123845df11f209d3b1 diff --git a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/GPT/GPTCommand.cs b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/GPT/GPTCommand.cs new file mode 100644 index 0000000..4c582e2 --- /dev/null +++ b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/GPT/GPTCommand.cs @@ -0,0 +1,143 @@ +using LibGit2Sharp; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.CommandLine; +using System.CommandLine.Parsing; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace EAVFW.Extensions.Manifest.ManifestEnricherTool.Commands.GPT +{ + public class GPTReviewPrCommand : Command + { + + [Alias("--project")] + [Description("The project path to EAV Model Project")] + public string Project { get; set; } + + [Alias("--pr")] + [Description("The project path to EAV Model Project")] + public string PR { get; set; } + + + public GPTReviewPrCommand() : base("pr", "Review a PR with Chat GPT") + { + Handler = COmmandExtensions.Create(this, new Command[0], Run); + } + private async Task Run(ParseResult parseResult, IConsole console) + { + var name = Path.GetFileNameWithoutExtension(Project); + var folder = Path.GetTempPath() + name; + console.WriteLine(folder); + if (Directory.Exists(folder)) + { + setAttributesNormal(new DirectoryInfo(folder)); + Directory.Delete(folder, true); + + + } + Directory.CreateDirectory(folder); + var repoPath = LibGit2Sharp.Repository.Clone(Project, folder, new CloneOptions { Checkout = true, FetchOptions = new FetchOptions { } }); + try + { + console.WriteLine(repoPath); + console.WriteLine(Project); + + using var repo = new Repository(repoPath); + + console.WriteLine("worktrees:"); + console.WriteLine(string.Join("\n", repo.Worktrees.Select(c => c.Name))); + + console.WriteLine("Refs:"); + console.WriteLine(string.Join("\n", repo.Refs.Select(c => c.CanonicalName))); + console.WriteLine("Branches:"); + console.WriteLine(string.Join("\n", repo.Branches.Select(c => c.CanonicalName))); + + string mergeIntoReleaseBranch = "refs/remotes/origin/master"; + string branchToBeMerged = "refs/remotes/origin/tst/job-status"; + TreeChanges treeChanges = repo.Diff.Compare(repo.Branches[mergeIntoReleaseBranch].Tip.Tree, repo.Branches[branchToBeMerged].Tip.Tree); + + console.WriteLine("Changes:"); + + Console.WriteLine(treeChanges.Count()); + console.WriteLine(string.Join("\n", treeChanges.Select(c => $"{c.Status.ToString()} {c.Path}\n{c.Mode}\n"))); + } + finally{ + setAttributesNormal(new DirectoryInfo(folder)); + Directory.Delete(folder, true); + } + + + + void setAttributesNormal(DirectoryInfo dir) + { + foreach (var subDir in dir.GetDirectories()) + setAttributesNormal(subDir); + foreach (var file in dir.GetFiles()) + { + file.Attributes = FileAttributes.Normal; + } + } + + return 0; + } + } + + public class GPTReviewCommand : Command + { + public GPTReviewCommand(GPTReviewPrCommand review) : base("review", "Chat GPT EAVFW Reviewer") + { + Handler = COmmandExtensions.Create(this, new[] + { + review + }, Run); + + } + private async Task Run(ParseResult parseResult, IConsole console) + { + return 0; + } + } + public class GPTCommand : Command + { + public GPTCommand(GPTReviewCommand review) : base("gpt", "ChatGPT EAVFW Developer") + { + Handler = COmmandExtensions.Create(this, new[] + { + review + }, Run); + } + private async Task Run(ParseResult parseResult, IConsole console) + { + return 0; + } + + } + public static class GPTExtensions + { + public static IServiceCollection AddGPT(this IServiceCollection services) + { + services.AddSingleton(); + + AddCommands(typeof(GPTCommand)); + + void AddCommands(Type type) + { + foreach (var parameter in type.GetConstructors().First().GetParameters()) + { + var parameterType = parameter.ParameterType; + if (typeof(Command).IsAssignableFrom(parameterType)) + { + services.AddSingleton(parameterType); + + AddCommands(parameterType); + } + } + } + + return services; + } + } +} diff --git a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/SQLCommand.cs b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/SQLCommand.cs index fedc26b..17f7611 100644 --- a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/SQLCommand.cs +++ b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Commands/SQLCommand.cs @@ -100,7 +100,7 @@ private async Task Run(ParseResult parseResult, IConsole console) Directory.CreateDirectory(outputDirectory); await File.WriteAllTextAsync(outputFile, sql); console.WriteLine("Written: " + Path.GetFullPath( outputFile)); - + if(parseResult.GetValueForOption(ShouldGeneratePermissions)) await InitializeSystemAdministrator(parseResult, outputDirectory,model); } diff --git a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/EAVFW.Extensions.Manifest.ManifestEnricherTool.csproj b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/EAVFW.Extensions.Manifest.ManifestEnricherTool.csproj index f7b28a3..1c799f6 100644 --- a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/EAVFW.Extensions.Manifest.ManifestEnricherTool.csproj +++ b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/EAVFW.Extensions.Manifest.ManifestEnricherTool.csproj @@ -10,15 +10,15 @@ A tool to enrich and transform manifest.json to manifest.g.json README.md https://github.com/EAVFW/EAVFW.Extensions.Manifest.ManifestEnricherTool - true - ..\..\..\EAVFramework + + - + @@ -35,13 +35,15 @@ 6.0.11 - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Program.cs b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Program.cs index 0d2df57..8931999 100644 --- a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Program.cs +++ b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Program.cs @@ -3,6 +3,7 @@ // See https://aka.ms/new-console-template for more information using EAVFW.Extensions.Manifest.ManifestEnricherTool.Commands; +using EAVFW.Extensions.Manifest.ManifestEnricherTool.Commands.GPT; using EAVFW.Extensions.Manifest.SDK; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -15,7 +16,7 @@ namespace EAVFW.Extensions.Manifest.ManifestEnricherTool public static class Program { - static ServiceCollection ConfigureServices(ServiceCollection serviceCollection) + static IServiceCollection ConfigureServices(IServiceCollection serviceCollection) { serviceCollection .AddLogging(configure => @@ -31,6 +32,9 @@ static ServiceCollection ConfigureServices(ServiceCollection serviceCollection) serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddGPT(); + + serviceCollection.AddHttpClient(); return serviceCollection; } diff --git a/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Properties/launchSettings.json b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Properties/launchSettings.json new file mode 100644 index 0000000..68c72eb --- /dev/null +++ b/src/EAVFW.Extensions.Manifest.ManifestEnricherTool/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "profiles": { + "EAVFW.Extensions.Manifest.ManifestEnricherTool": { + "commandName": "Project", + "workingDirectory": "C:\\dev\\hafnia\\loi", + //"workingDirectory": "C:\\dev\\kfst_vanddata", + //"commandLineArgs": "--path c:\\dev\\kfst_vanddata\\apps\\KFST.Vanddata.ManagementPortal\\manifest.json --customizationprefix kfst", + //"commandLineArgs": "install EAVFW.Extensions.SecurityModel", + //"commandLineArgs": "sql C:/dev/eavfwdemo/src/EAVApp.Models" + + //"commandLineArgs": "sql C:/dev/kfst_vanddata/apps/KFST.Vanddata.ManagementPortal/" + + //"commandLineArgs": "manifest fix-migration --project-path c:\\dev\\kfst_vanddata\\apps\\KFST.Vanddata.ManagementPortal -v 1.0.45 --schema KFST --prefix KFST --database VandData2" + + // "commandLineArgs": "--path C:\\dev\\MedlemsCentralen\\src\\MC.Models\\manifest.json --customizationprefix MC" + + // "commandLineArgs": "sql ./src/Hafnia.Models", + "commandLineArgs": "gpt review pr --project https://github.com/delegateas/WorkflowEngine.git --pr 15" + // "commandLineArgs": "sql ./apps/KFST.Vanddata.ManagementPortal" + //"commandLineArgs": "--path C:\\dev\\hafnia\\loi\\src\\Hafnia.Models\\manifest.json --customizationprefix hafnia" + } + } +} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/DefaultManifestPathExtracter.cs b/src/EAVFW.Extensions.Manifest.SDK/DefaultManifestPathExtracter.cs deleted file mode 100644 index a21b377..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/DefaultManifestPathExtracter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Linq; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public class DefaultManifestPathExtracter : IManifestPathExtracter - { - public string ExtractPath(JToken token, string part) - { - string partPath; - if (token.Path.Contains(part) && !token.Path.EndsWith(part)) - { - - var idx = token.Path.IndexOf(part) + part.Length + 1; - - partPath = new string(token.Path.TakeWhile((c, i) => i < idx || !(c == '.' || c == ']')).ToArray()); - - if (partPath.EndsWith('\'')) - partPath += ']'; - - } - else - { - partPath = string.Empty; - - } - if (partPath.EndsWith("[merge()]")) - { - partPath = partPath.Replace("[merge()]", ""); - } - return string.IsNullOrEmpty(partPath) ? null : partPath; - } - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/DefaultManifestReplacementRunner.cs b/src/EAVFW.Extensions.Manifest.SDK/DefaultManifestReplacementRunner.cs deleted file mode 100644 index 2df0862..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/DefaultManifestReplacementRunner.cs +++ /dev/null @@ -1,295 +0,0 @@ -using DotNETDevOps.JsonFunctions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public class DefaultManifestReplacementRunner : IManifestReplacmentRunner - { - private readonly ManifestEnricherOptions options; - private readonly ISchemaNameManager schemaNameManager; - private readonly IManifestPathExtracter manifestPathExtracter; - - public DefaultManifestReplacementRunner(IOptions options,ISchemaNameManager schemaNameManager, IManifestPathExtracter manifestPathExtracter) - { - this.options = options?.Value ?? throw new ArgumentNullException(nameof(options)); - this.schemaNameManager = schemaNameManager ?? throw new ArgumentNullException(nameof(schemaNameManager)); - this.manifestPathExtracter = manifestPathExtracter ?? throw new ArgumentNullException(nameof(manifestPathExtracter)); - } - - public virtual bool ShouldEvaluate(string str) - { - return str.StartsWith("[") && str.EndsWith("]") && !str.StartsWith("[["); - } - - public virtual async Task EvaluateAsync(ExpressionParser expressionParser, string str) - { - try - { - var nToken = await expressionParser.EvaluateAsync(str); - - if (nToken == null) - { - return nToken; - } - - - - if (nToken.Type == JTokenType.Object) - { - var q = new Queue(); - q.Enqueue(nToken); - while (q.Count > 0) - { - var c = q.Dequeue(); - if (c is JObject o) - { - foreach (var p in o.Properties()) - q.Enqueue(p); - - } - else if (c is JProperty p) - { - if (p.Name.StartsWith("[[")) - { - var nprop = new JProperty(p.Name.Substring(1, p.Name.Length - 2), p.Value); - p.Replace(nprop); - q.Enqueue(nprop); - } - else - { - q.Enqueue(p.Value); - } - } - else if (c is JArray a) - { - foreach (var e in a) - q.Enqueue(e); - } - else if (c.Type == JTokenType.String && c.ToString().StartsWith("[[")) - { - // var ch = await expressionParser.EvaluateAsync(c.ToString().Substring(1, c.ToString().Length - 2)); - // c.Replace(ch); - // q.Enqueue(ch); - var child = c.ToString().Substring(1, c.ToString().Length - 2); - // var childToken = await EvaluateAsync(expressionParser, child); - c.Replace(child); - } - } - } - - - - while (nToken.Type == JTokenType.String && ShouldEvaluate(nToken.ToString().Substring(1, nToken.ToString().Length - 2))) - { - nToken = await expressionParser.EvaluateAsync(nToken.ToString().Substring(1, nToken.ToString().Length - 2)); - } - - - - return nToken; - } - catch (Exception ex) - { - Console.WriteLine("EvaluateAsync: " + ex.ToString()); - throw; - } - } - - - - public async Task RunReplacements(JToken jsonraw, string customizationprefix, ILogger logger, JToken elementToRunReplacementFor = null) - { - var entityPath = string.Empty; - var attributePath = string.Empty; - JToken currentElement = null; - JToken localelement = null; - JToken[] localarguments = null; - - var q = new Queue(new[] { elementToRunReplacementFor ?? jsonraw }); - - - var expressionParser = new ExpressionParser( - Options.Create(new ExpressionParserOptions() { Document = jsonraw, ThrowOnError = true }), logger, - new DefaultExpressionFunctionFactory() - { - Functions = - { - ["data"] = (parser,Document,arguments) => {Console.WriteLine(arguments[0]); var child=JToken.Parse(File.ReadAllText(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(options.Path) ,arguments[0]?.ToString())));// q.Enqueue(child); - return Task.FromResult(child); }, - ["customizationprefix"] =(parser,Document,arguments) => Task.FromResult(customizationprefix), - ["propertyNames"] = (parser,document,arguments) => Task.FromResult((arguments[0] is JObject obj ? JToken.FromObject( obj.Properties().Select(k=>k.Name)):new JArray())), - ["indexOf"] =(parser,document,arguments) => Task.FromResult(Array.IndexOf( arguments[0].ToArray(),arguments[1])), - ["default"] = (parser,document,arguments) => Task.FromResult(arguments[0] == null || arguments[0].Type == JTokenType.Null ? arguments[1]:arguments[0]), - ["unfoldsource"] = (parser,document,arguments)=> Task.FromResult(document.SelectToken(arguments[0]["__unroll__path"].ToString())), - ["if"] = (parser,document,arguments) => Task.FromResult(arguments[0].ToObject() ? arguments[1]:arguments[2]), - ["condition"] = (parser,document,arguments) => Task.FromResult(arguments[0].ToObject() ? arguments[1]:arguments[2]), - ["in"] =(parser,document,arguments) => Task.FromResult(JToken.FromObject( arguments[1] != null && ( arguments[1] is JObject obj ? obj.ContainsKey(arguments[0].ToString()) : arguments[1].Any(a=>arguments[0].Equals(a))) )), - ["variables"] = (parser,document,arguments)=> { localarguments= arguments; return Task.FromResult(jsonraw.SelectToken($"$.variables.{arguments.First()}")?.DeepClone()); }, - ["concat"] = (parser,document,arguments)=>Task.FromResult(string.Join("",arguments.Select(k=>k.ToString())) ), - ["entity"] = (parser, document, arguments) => - { - var entity = document.SelectToken(entityPath); - - return Task.FromResult(entity); - }, - ["toLogicalName"] = (parser,document,arguments) => Task.FromResult(schemaNameManager.ToSchemaName(arguments[0].ToString()).ToLower()), - ["attribute"] = (parser, document, arguments) => Task.FromResult(document.SelectToken(attributePath)), - ["attributes"] = (parser, document, arguments) => Task.FromResult(document.SelectToken(entityPath+".attributes")), - ["select"] = (parser, document, arguments) => Task.FromResult(arguments.FirstOrDefault(a=>!(a== null || a.Type == JTokenType.Null))), - ["propertyName"] = (parser, document, arguments) => Task.FromResult( arguments[0].Parent is JProperty prop ? prop.Name : null), - ["parent"] =(parser, document, arguments) => Task.FromResult( arguments.Any() ? (arguments[0].Parent is JProperty prop ? prop.Parent:arguments[0].Parent) : (currentElement.Parent is JProperty prop1 ? prop1.Parent:currentElement.Parent)), - ["element"]=(parser,document,arguments)=>Task.FromResult(localelement ?? currentElement), - ["map"] =async (parser, document, arguments) =>{ - - return JToken.FromObject( await Task.WhenAll( arguments[0].Select(a=>{ - - localelement = a; - - return parser.EvaluateAsync(arguments[1].ToString()); - - - }))); - - } - - - } - }); - - while (q.Count > 0) - { - - var a = q.Dequeue(); - if (a == null) - continue; - - entityPath = manifestPathExtracter.ExtractPath(a, "entities"); - attributePath = manifestPathExtracter.ExtractPath(a, "attributes") ?? manifestPathExtracter.ExtractPath(a, "columns"); - - try - { - if (a is JProperty prop) - { - var value = prop.Value; - var str = prop.Name; - - if (ShouldEvaluate(str)) - { - - if (str == "[merge()]") - { - var parentObj = prop.Parent as JObject; - var obj = prop.Value; - - if (obj.Type == JTokenType.String && ShouldEvaluate(obj.ToString())) - { - currentElement = obj; - obj = await EvaluateAsync(expressionParser, obj.ToString()); - } - - foreach (var childProp in (obj as JObject).Properties().ToArray()) - { - - childProp.Remove(); - - if (parentObj.ContainsKey(childProp.Name) && childProp.Value is JObject source && parentObj[childProp.Name] is JObject target) - { - target.Merge(source); - q.Enqueue(parentObj.Property(childProp.Name)); - // parentObj[childProp.Name] - } - else if (parentObj.ContainsKey(childProp.Name) && JToken.DeepEquals(childProp.Value, parentObj[childProp.Name])) - { - q.Enqueue(parentObj.Property(childProp.Name)); - } - else - { - try - { - parentObj.Add(childProp); - q.Enqueue(childProp); - }catch(Exception ex) - { - throw; - } - } - - // parentObj.Add(childProp.Name, childProp.Value); - - } - - prop.Remove(); - continue; - } - currentElement = prop.Value; - var nToken = await EvaluateAsync(expressionParser, str); - - - - if (nToken.Type == JTokenType.Null || nToken.Type == JTokenType.Undefined) - { - prop.Remove(); - continue; - } - - - - var nProp = new JProperty(nToken.ToString(), value); - prop.Replace(nProp); - q.Enqueue(nProp); - } - else - { - - - q.Enqueue(value); - } - } - else if (a is JObject obj) - { - foreach (var p in obj.Properties()) - { - - q.Enqueue(p); - - - } - - } - else if (a is JArray array) - { - foreach (var element in array) - q.Enqueue(element); - - } - else if (a.Type == JTokenType.String) - { - var str = a.ToString(); - - if (ShouldEvaluate(str)) - { - currentElement = a; - var t = await EvaluateAsync(expressionParser, str); - - a.Replace(t); - q.Enqueue(t); - } - } - - } - catch (Exception ex) - { - Console.WriteLine($"{entityPath}| {attributePath}"); - throw; - } - } - } - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/DefaultSchemaNameManager.cs b/src/EAVFW.Extensions.Manifest.SDK/DefaultSchemaNameManager.cs deleted file mode 100644 index b8ca7a2..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/DefaultSchemaNameManager.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EAVFW.Extensions.Manifest.SDK -{ - public class DefaultSchemaNameManager : ISchemaNameManager - { - public string ToSchemaName(string displayName) - { - return displayName?.Replace(" ", "").Replace(":", "_").Replace("/", "or").Replace("-", "").Replace("(", "").Replace(")", "").Replace(".",""); ; - } - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/EAVFW.Extensions.Manifest.SDK.csproj b/src/EAVFW.Extensions.Manifest.SDK/EAVFW.Extensions.Manifest.SDK.csproj deleted file mode 100644 index 02ec93b..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/EAVFW.Extensions.Manifest.SDK.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - - netcoreapp3.1;net6.0 - disable - disable - - EAVFW.Extensions.Manifest.SDK - Poul Kjeldager - SDK for EAVFW Manifest - README.md - https://github.com/EAVFW/EAVFW.Extensions.Manifest.ManifestEnricherTool - MIT - - - - - - - - - - - - - - - - - - - - - diff --git a/src/EAVFW.Extensions.Manifest.SDK/IManifestEnricher.cs b/src/EAVFW.Extensions.Manifest.SDK/IManifestEnricher.cs deleted file mode 100644 index 902efcc..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/IManifestEnricher.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Linq; -using System.Text.Json; -using System.Threading.Tasks; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public interface IManifestEnricher - { - Task LoadJsonDocumentAsync(JToken jsonraw, string customizationprefix, ILogger logger); - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/IManifestPathExtracter.cs b/src/EAVFW.Extensions.Manifest.SDK/IManifestPathExtracter.cs deleted file mode 100644 index 1fc58af..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/IManifestPathExtracter.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Newtonsoft.Json.Linq; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public interface IManifestPathExtracter - { - string ExtractPath(JToken token, string part); - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/IManifestReplacmentRunner.cs b/src/EAVFW.Extensions.Manifest.SDK/IManifestReplacmentRunner.cs deleted file mode 100644 index 4d9c3c6..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/IManifestReplacmentRunner.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Microsoft.Extensions.Logging; -using Newtonsoft.Json.Linq; -using System.Threading.Tasks; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public interface IManifestReplacmentRunner - { - Task RunReplacements(JToken jsonraw, string customizationprefix, ILogger logger, JToken elementToRunReplacementFor = null); - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/ISchemaNameManager.cs b/src/EAVFW.Extensions.Manifest.SDK/ISchemaNameManager.cs deleted file mode 100644 index e4e660f..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/ISchemaNameManager.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EAVFW.Extensions.Manifest.SDK -{ - public interface ISchemaNameManager - { - string ToSchemaName(string value); - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/ManifestEnricher.cs b/src/EAVFW.Extensions.Manifest.SDK/ManifestEnricher.cs deleted file mode 100644 index a33b354..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/ManifestEnricher.cs +++ /dev/null @@ -1,879 +0,0 @@ -using DotNETDevOps.JsonFunctions; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; - -namespace EAVFW.Extensions.Manifest.SDK -{ - - public interface IManifestPermissionGenerator - { - - Task CreateInitializationScript(JToken model, string systemUserEntity); - - } - public interface IParameterGenerator - { - string GetParameter(string name, bool escape=true); - } - public class SQLClientParameterGenerator : IParameterGenerator - { - public string GetParameter(string name, bool escape) - { - if(escape) - return $"'$({name})'"; - return $"$({name})"; - } - } - public class DataClientParameterGenerator : IParameterGenerator - { - public string GetParameter(string name, bool escape) - { - return $"@{name}"; - } - } - public class ManifestPermissionGenerator : IManifestPermissionGenerator - { - private readonly IParameterGenerator parameterGenerator; - - public ManifestPermissionGenerator(IParameterGenerator parameterGenerator) - { - this.parameterGenerator = parameterGenerator ?? throw new ArgumentNullException(nameof(parameterGenerator)); - } - public async Task CreateInitializationScript(JToken model, string systemUserEntity) - { - - var sb = new StringBuilder(); - var adminSGId = parameterGenerator.GetParameter("SystemAdminSecurityGroupId");// "$(SystemAdminSecurityGroupId)"; - - sb.AppendLine("DECLARE @adminSRId uniqueidentifier"); - sb.AppendLine("DECLARE @permissionId uniqueidentifier"); - sb.AppendLine($"SET @adminSRId = ISNULL((SELECT s.Id FROM [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityRoles] s WHERE s.Name = 'System Administrator'),'{Guid.NewGuid()}')"); - sb.AppendLine($"IF NOT EXISTS(SELECT * FROM [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[Identities] WHERE [Id] = {adminSGId})"); - sb.AppendLine("BEGIN"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[Identities] (Id, Name, ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES({adminSGId}, 'System Administrator Group', CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityGroups] (Id) VALUES({adminSGId})"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[Identities] (Id, Name,ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES ({parameterGenerator.GetParameter("UserGuid")}, {parameterGenerator.GetParameter("UserName")}, CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[{systemUserEntity}] (Id,Email) VALUES ({parameterGenerator.GetParameter("UserGuid")}, {parameterGenerator.GetParameter("UserEmail")});"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityRoles] (Name, Description, Id,ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES('System Administrator', 'Access to all permissions', @adminSRId, CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityRoleAssignments] (IdentityId, SecurityRoleId, Id,ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES({adminSGId}, @adminSRId, '{Guid.NewGuid()}',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityGroupMembers] (IdentityId, SecurityGroupId, Id,ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES({parameterGenerator.GetParameter("UserGuid")}, {adminSGId}, '{Guid.NewGuid()}',CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine("END;"); - foreach (var entitiy in model.SelectToken("$.entities").OfType()) - { - WritePermissionStatement(sb, entitiy, "ReadGlobal", "Global Read", adminSGId,true); - WritePermissionStatement(sb, entitiy, "Read", "Read", adminSGId); - WritePermissionStatement(sb, entitiy, "UpdateGlobal", "Global Update", adminSGId, true); - WritePermissionStatement(sb, entitiy, "Update", "Update", adminSGId); - WritePermissionStatement(sb, entitiy, "CreateGlobal", "Global Create", adminSGId, true); - WritePermissionStatement(sb, entitiy, "Create", "Create", adminSGId); - WritePermissionStatement(sb, entitiy, "DeleteGlobal", "Global Delete", adminSGId, true); - WritePermissionStatement(sb, entitiy, "Delete", "Delete", adminSGId); - WritePermissionStatement(sb, entitiy, "ShareGlobal", "Global Share", adminSGId, true); - WritePermissionStatement(sb, entitiy, "Share", "Share", adminSGId); - WritePermissionStatement(sb, entitiy, "AssignGlobal", "Global Assign", adminSGId, true); - WritePermissionStatement(sb, entitiy, "Assign", "Assign", adminSGId); - } - - return sb.ToString(); - } - private void WritePermissionStatement(StringBuilder sb, JProperty entitiy, string permission, string permissionName, string adminSGId, bool adminSRId1 = false) - { - sb.AppendLine($"SET @permissionId = ISNULL((SELECT s.Id FROM [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[Permissions] s WHERE s.Name = '{entitiy.Value.SelectToken("$.collectionSchemaName")}{permission}'),'{Guid.NewGuid()}')"); - sb.AppendLine($"IF NOT EXISTS(SELECT * FROM [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[Permissions] WHERE [Name] = '{entitiy.Value.SelectToken("$.collectionSchemaName")}{permission}')"); - sb.AppendLine("BEGIN"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[Permissions] (Name, Description, Id, ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES('{entitiy.Value.SelectToken("$.collectionSchemaName")}{permission}', '{permissionName} access to {entitiy.Value.SelectToken("$.pluralName")}', @permissionId, CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine("END"); - if (adminSRId1) - { - sb.AppendLine($"IF NOT EXISTS(SELECT * FROM [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityRolePermissions] WHERE [Name] = 'System Administrator - {entitiy.Value.SelectToken("$.collectionSchemaName")} - {permission}')"); - sb.AppendLine("BEGIN"); - sb.AppendLine($"INSERT INTO [{parameterGenerator.GetParameter("DBName",false)}].[{parameterGenerator.GetParameter("DBSchema",false)}].[SecurityRolePermissions] (Name, PermissionId, SecurityRoleId, Id,ModifiedOn,CreatedOn,CreatedById,ModifiedById,OwnerId) VALUES('System Administrator - {entitiy.Value.SelectToken("$.collectionSchemaName")} - {permission}', @permissionId, @adminSRId, '{Guid.NewGuid()}', CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,{adminSGId},{adminSGId},{adminSGId})"); - sb.AppendLine("END"); - } - } - } - public class ManifestEnricher : IManifestEnricher - { - private readonly ISchemaNameManager schemaName; - private readonly IManifestReplacmentRunner manifestReplacmentRunner; - - public ManifestEnricher(ISchemaNameManager schemaName, IManifestReplacmentRunner manifestReplacmentRunner) - { - this.schemaName = schemaName ?? throw new System.ArgumentNullException(nameof(schemaName)); - this.manifestReplacmentRunner = manifestReplacmentRunner ?? throw new ArgumentNullException(nameof(manifestReplacmentRunner)); - } - - protected virtual JObject Merge(JObject jToken, object obj) - { - - jToken = (JObject)jToken.DeepClone(); - - - var jobj = JToken.FromObject(obj) as JObject; - - foreach (var p in jobj.Properties()) - { - if (!(p.Value.Type == JTokenType.Null || p.Value.Type == JTokenType.Undefined)) - jToken[p.Name] = p.Value; - } - - if (!jToken.ContainsKey("schemaName")) - jToken["schemaName"] = schemaName.ToSchemaName(jToken.SelectToken("$.displayName")?.ToString()); - if (!jToken.ContainsKey("logicalName")) - jToken["logicalName"] = jToken.SelectToken("$.schemaName")?.ToString().ToLower(); - - return jToken as JObject; - } - private object[] CreateOptions(params string[] args) - { - return args.Select((o, i) => new { label = o, value = i + 1 }).ToArray(); - } - private JObject CreateAttribute(JObject attr, string displayName, object type, string? schemaName = null, object? additionalProps = null) - { - if (additionalProps != null) - return Merge(Merge(attr, new { displayName, type, schemaName }), additionalProps); - return Merge(attr, new { displayName, type, schemaName }); - } - private string TrimId(string v) - { - if (string.IsNullOrEmpty(v)) - return v; - - if (v.EndsWith("id", StringComparison.OrdinalIgnoreCase)) - return v.Substring(0, v.Length - 2); - - return v; - } - public async Task LoadJsonDocumentAsync(JToken jsonraw, string customizationprefix, ILogger logger) - { - - - var entities = jsonraw.SelectToken("$.entities") as JObject; - var insertMerges = jsonraw.SelectToken("$.variables.options.insertMergeLayoutVariable")?.ToObject(); - - - foreach (var entitieP in (entities)?.Properties() ?? Enumerable.Empty()) - { - var entity = (JObject)entitieP.Value; - - SetRequiredProps(entity, entitieP.Name); - - await EnrichEntity(jsonraw, customizationprefix, logger, insertMerges, entity); - - } - - - foreach (var entitieP in (entities)?.Properties().ToArray() ?? Enumerable.Empty()) - { - foreach (var polyLookup in entitieP.Value.SelectToken("$.attributes").OfType().Where(c => c.Value.SelectToken("$.type.type")?.ToString().ToLower() == "polylookup").ToArray()) - { - var name = polyLookup.Value.SelectToken("$.type.name")?.ToString() ?? $"{entitieP.Name} {polyLookup.Name}"; - var Key = name + " Reference"; - var pluralName = name + " References"; //$"{entitieP.Value.SelectToken("$.displayName")} {polyLookup.Value.SelectToken("$.displayName")} References"; - var reverse = polyLookup.Value.SelectToken("$.type.reverse")?.ToObject() ?? false; - var inline = polyLookup.Value.SelectToken("$.type.inline")?.ToObject() ?? false; - if (!entities.ContainsKey(Key)) - { - var attributes = polyLookup.Value.SelectToken("$.type.referenceTypes").ToObject() - .ToDictionary(k => k, v => JToken.FromObject(new { type = new { type = "lookup", referenceType = v } })); - - if (inline) - { - foreach (var attribute in attributes) - { - entitieP.Value["attributes"][attribute.Key] = attribute.Value; - - } - polyLookup.Value["type"]["type"] = "polylookup"; - // polyLookup.Remove(); - } - else - { - - - // attributes["Id"] = JToken.FromObject(new { isPrimaryKey = true }); - attributes["Name"] = JToken.FromObject(new { isPrimaryField = true }); - - - - entities[Key] = JToken.FromObject(new - { - pluralName = pluralName, - attributes = attributes - }); - - - SetRequiredProps(entities[Key] as JObject, Key); - } - } - - - - if (!inline) - { - var entity = entities[Key] as JObject; - polyLookup.Value["type"]["foreignKey"] = JToken.FromObject(new - { - principalTable = entity["logicalName"].ToString(), - principalColumn = "id", - principalNameColumn = "name", - name = TrimId(polyLookup.Value.SelectToken("$.logicalName")?.ToString()) // jsonraw.SelectToken($"$.entities['{ attr["type"]["referenceType"] }'].logicalName").ToString().Replace(" ", ""), - }); - polyLookup.Value["type"]["referenceType"] = Key; - - if (reverse) - { - entities[Key]["attributes"][polyLookup.Name] = JToken.FromObject(new - { - type = new - { - type = "lookup", - referenceType = entitieP.Name - } - }); - - // polyLookup.Remove(); - } - - - // polyLookup.Value["type"]["type"] = "lookup"; - - await EnrichEntity(jsonraw, customizationprefix, logger, insertMerges, entity); - } - else - { - - await EnrichEntity(jsonraw, customizationprefix, logger, insertMerges, entitieP.Value as JObject); - } - } - } - - - await manifestReplacmentRunner.RunReplacements(jsonraw, customizationprefix, logger); - - - foreach (var entitieP in (jsonraw.SelectToken("$.entities") as JObject)?.Properties() ?? Enumerable.Empty()) - { - var attributes = entitieP.Value.SelectToken("$.attributes") as JObject; - - foreach (var attributeDefinition in attributes.Properties()) - { - var attr = attributeDefinition.Value; - - switch (attr.SelectToken("$.type.type")?.ToString()?.ToLower()) - { - case "lookup" when string.IsNullOrEmpty(jsonraw.SelectToken($"$.entities['{attr["type"]["referenceType"]}'].logicalName")?.ToString()): - throw new KeyNotFoundException($"The lookup entity does not exists: '{attr["type"]["referenceType"]}'"); - case "lookup": - - - var columns = jsonraw.SelectToken($"$.entities['{attr["type"]["referenceType"]}'].attributes").OfType() - .Concat(jsonraw.SelectToken($"$.entities['{attr["type"]["referenceType"]}'].TPT") == null ? Enumerable.Empty() : jsonraw.SelectToken($"$.entities['{jsonraw.SelectToken($"$.entities['{attr["type"]["referenceType"]}'].TPT")}'].attributes").OfType()) - .GroupBy(k => k.Name).Select(g => g.First()) - .ToArray(); - - var principalTable = jsonraw.SelectToken($"$.entities['{attr["type"]["referenceType"]}'].logicalName").ToString(); - var principalColumn = columns - .FirstOrDefault(a => a.Value.SelectToken("$.isPrimaryKey")?.ToObject() ?? false) - ?.Value.SelectToken("$.logicalName").ToString() - ?? throw new InvalidOperationException($"Cant find principalColumn for lookup {entitieP.Name}.{attributeDefinition.Name}"); ; - - var principalNameColumn = columns - .FirstOrDefault(a => a.Value.SelectToken("$.isPrimaryField")?.ToObject() ?? false) - ?.Value.SelectToken("$.logicalName").ToString() - ?? throw new InvalidOperationException($"Cant find principalNameColumn for lookup {entitieP.Name}.{attributeDefinition.Name}"); - - attr["type"]["foreignKey"] = JToken.FromObject(new - { - principalTable = principalTable, - principalColumn = principalColumn, - principalNameColumn = principalNameColumn, - name = TrimId(attr.SelectToken("$.logicalName")?.ToString()) // jsonraw.SelectToken($"$.entities['{ attr["type"]["referenceType"] }'].logicalName").ToString().Replace(" ", ""), - }); - - - break; - case "float": - case "decimal": - if (attr.SelectToken("$.type.sql") == null) - { - attr["type"]["sql"] = JToken.FromObject(new { precision = 18, scale = 4 }); - } - if (attr.SelectToken("$.type.sql.precision") == null) - { - attr["type"]["sql"]["precision"] = 18; - } - if (attr.SelectToken("$.type.sql.scale") == null) - { - attr["type"]["sql"]["scale"] = 4; - } - break; - - } - - - } - } - - - - var defaultControls = jsonraw.SelectToken("$.controls"); - if (defaultControls != null) - { - logger.LogInformation("Replacing default Controls"); - - foreach (var defaultControl in defaultControls.OfType()) - { - logger.LogInformation("Replacing default Controls : {Type}", defaultControl.Name); - - foreach (var entity in jsonraw.SelectToken("$.entities")?.OfType() ?? Enumerable.Empty()) - { - foreach (var attribute in entity.Value.SelectToken("$.attributes")?.OfType() ?? Enumerable.Empty()) - { - var attributeType = (attribute.Value.SelectToken("$.type.type") ?? attribute.Value.SelectToken("$.type")).ToString(); - - if (string.Equals(attributeType, defaultControl.Name, StringComparison.OrdinalIgnoreCase)) - { - logger.LogInformation("Replacing default Controls for {entity} {attribute} : {type}", entity.Name, attribute.Name, defaultControl.Name); - - var formFields = (entity.Value.SelectToken($"$.forms")?.OfType() ?? Enumerable.Empty()) - .Select(c => c.Value.SelectToken($"$.columns['{attribute.Name}']")).Where(c => c != null).ToArray(); - - { - - foreach (var formField in formFields) - { - var control = formField.SelectToken("$.control"); - - if (control == null) - { - var replacement = defaultControl.Value.DeepClone(); ; - formField["control"] = replacement; - var q = new Queue(new[] { replacement }); - while (q.Any()) - { - var e = q.Dequeue(); - if (e is JObject obj) - { - foreach (var prop in e.OfType()) - { - q.Enqueue(prop); - } - } - else if (e is JProperty prop) - { - q.Enqueue(prop.Value); - } - else if (e is JArray array) - { - foreach (var ee in array) - { - q.Enqueue(ee); - } - } - else if (e.Type == JTokenType.String) - { - var str = e.ToString(); - if (str.StartsWith("[[") && str.EndsWith("]]")) - { - e.Replace(str.Substring(1, str.Length - 2)); - } - - } - } - - - logger.LogInformation("Replacing default Controls for {entity} {attribute} {formname}: {type}", entity.Name, attribute.Name, (formField.Parent.Parent.Parent as JProperty)?.Name, defaultControl.Name); - } - } - } - } - } - } - } - } - - await manifestReplacmentRunner.RunReplacements(jsonraw, customizationprefix, logger); - - - foreach (var (entityDefinition, attributeDefinition2) in jsonraw.SelectToken("$.entities").OfType() - .SelectMany(e => e.Value.SelectToken("$.attributes").OfType().Select(p => (e, p))) - .Where(a => a.p.Value.SelectToken("$.type.type")?.ToString().ToLower() == "choices") - .ToArray()) - { - - - - - var nentity = $"{attributeDefinition2.Value.SelectToken("$.type.name")}"; - - - jsonraw["entities"][nentity] = JToken.FromObject( - new - { - pluralName = $"{attributeDefinition2.Value.SelectToken("$.type.pluralName")}", - displayName = nentity, - logicalName = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", "").ToLower(), - schemaName = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", ""), - collectionSchemaName = $"{attributeDefinition2.Value.SelectToken("$.type.pluralName")}".Replace(" ", ""), - keys = new Dictionary - { - [$"IX_{entityDefinition.Name}Value"] = new[] { entityDefinition.Name, nentity + " Value" } - }, - attributes = new Dictionary - { - ["Id"] = new - { - displayName = "Id", - logicalName = "id", - schemaName = "Id", - type = new { type = "guid" }, - isPrimaryKey = true, - }, - [entityDefinition.Name] = new - { - displayName = entityDefinition.Value.SelectToken("$.displayName"), - logicalName = entityDefinition.Value.SelectToken("$.logicalName") + "id", - schemaName = entityDefinition.Value.SelectToken("$.schemaName") + "Id", - type = new - { - type = "lookup", - referenceType = entityDefinition.Name, - }, - }, - [nentity + " Value"] = new - { - - displayName = nentity + " Value", - logicalName = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", "").ToLower(), - schemaName = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", "") + "Value", - // isPrimaryKey = true, - type = new - { - type = "choice", - name = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", "") + "Value", - options = attributeDefinition2.Value.SelectToken("$.type.options") - } - } - } - }); - //attributeDefinition2.Value.SelectToken("$.type").Replace(JToken.FromObject( - // new - // { - // type = "lookup", - // referenceType = $"{attributeDefinition2.Value.SelectToken("$.type.name")}" - // } - // )); - - attributeDefinition2.Value["type"]["logicalName"] = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", "").ToLower(); - attributeDefinition2.Value["type"]["schemaName"] = $"{attributeDefinition2.Value.SelectToken("$.type.name")}".Replace(" ", ""); - attributeDefinition2.Value["type"]["collectionSchemaName"] = $"{attributeDefinition2.Value.SelectToken("$.type.pluralName")}".Replace(" ", ""); - attributeDefinition2.Value["type"]["principalColumn"] = entityDefinition.Value.SelectToken("$.logicalName") + "id"; - // attributeDefinition2.Remove(); - - } - - - //Lets sort them according to TPT - var qque = new Queue(jsonraw.SelectToken("$.entities").OfType()); - - while (qque.Count > 0) - { - var entity = qque.Dequeue(); - - var tpt = entity.Value.SelectToken("$.TPT")?.ToString(); - if (!string.IsNullOrEmpty(tpt)) - { - var baseentity = jsonraw.SelectToken($"$.entities['{tpt}']").Parent as JProperty; - entity.Remove(); - baseentity.AddAfterSelf(entity); - - - } - } - - - var json = JsonDocument.Parse(jsonraw.ToString(), new JsonDocumentOptions - { - CommentHandling = JsonCommentHandling.Skip - }); - Directory.CreateDirectory("obj"); - File.WriteAllText("obj/manifest.g.json", jsonraw.ToString(Newtonsoft.Json.Formatting.Indented)); - - - ///For loop over jsonraw.selectToken("$.entities") - ///write a file to obj/specs/.spec.g.json - ///containing a json schema file for the entity attributes. Sadly there is no strict type map of possible types. - ///Types can be anything random that i later maps to something in dynamics. (use tolower) - /// Currently from AttributeTypeCodeConverter - currency,customer,datetime,multilinetext,memo,int,integer,timezone,phone,float,guid,string,text,boolean,bool, - /// and type.type can be autonumber,choice,picklist,choices,state,status,lookup,string,text - - bool ConvertToSchemaType(JToken attrType, out JToken type) - { - type = null; - - var inp = attrType?.ToString(); - if (!(attrType.Type == JTokenType.String)) - { - inp = attrType.SelectToken("$.type")?.ToString(); - } - - switch (inp.ToLower()) - { - case "point": - type = JToken.FromObject(new - { - type = "object", - properties=new - { - - } - }); - return true; - case "binary": - type = JToken.FromObject(new - { - type = "string", - contentEncoding = "base64" - }); - return true; - case "datetime": - type = "datetime"; - return true; - case "time": - type = "time"; - return true; - - case "customer": - case "polylookup": - return false; - case "string": - case "text": - case "multilinetext": - type = "string"; - return true; - case "integer": - type = "integer"; - return true; - case "decimal": - type = "number"; - return true; - case "boolean": - type = "boolean"; - return true; - case "lookup": - - - var foreignTable = jsonraw.SelectToken($"$.entities['{attrType.SelectToken("$.referenceType")}']"); - var fatAttributes = foreignTable.SelectToken("$.attributes"); - var fat = fatAttributes.OfType().Where(c => c.Value.SelectToken("$.isPrimaryKey")?.ToObject() ?? false) - .Select(a => a.Value.SelectToken("$.type")).Single(); - if (fat.Type == JTokenType.Object) - fat = fat.SelectToken("$.type"); - - ConvertToSchemaType(fat?.ToString(), out type); - - type["x-foreign-key"] = JToken.FromObject(new - { - table = new - { - logicalName = foreignTable.SelectToken("$.logicalName"), - schemaName = foreignTable.SelectToken("$.schemaName"), - pluralName = foreignTable.SelectToken("$.pluralName"), - }, - columns = fatAttributes.OfType().Where(c => c.Value.SelectToken("$.isPrimaryKey")?.ToObject() ?? false) - .Select(a => new - { - logicalName = a.SelectToken("$.logicalName"), - schemaName = a.SelectToken("$.schemaName"), - - }) - }); - - return true; - - case "guid": - type = JToken.FromObject(new - { - type = "string", - format = "uuid" - }); - return true; - case "choices": - - type = JToken.FromObject(new - { - type = "array", - items = new - { - type = "integer", - @enum = attrType.SelectToken("$.options").OfType().Select(c => c.Value.ToObject()) - } - }); - return true; - case "choice": - type = JToken.FromObject(new - { - type = "integer", - @enum = attrType.SelectToken("$.options").OfType().Select(c => c.Value.Type == JTokenType.Object ? c.Value.SelectToken("$.value") : c.Value).Select(v => v.ToObject()) - }); - return true; - default: - throw new NotImplementedException(inp); - } - - - } - - Directory.CreateDirectory("obj/models"); - foreach (var entity in (jsonraw.SelectToken("$.entities") as JObject)?.Properties() ?? Enumerable.Empty()) - { - try - { - var entityValue = entity.Value as JObject; - var schema = new JObject - { - ["title"] = entity.Name, - ["$schema"] = "http://json-schema.org/draft-07/schema#", - ["type"] = "object", - }; - var properties = new JObject(); - - foreach (var attr in (entityValue.SelectToken("$.attributes") as JObject)?.Properties() ?? Enumerable.Empty()) - { - var attrValue = attr.Value as JObject; - var attrType = attrValue.SelectToken("$.type"); - - - - if (!ConvertToSchemaType(attrType, out var type)) continue; - - var propValues = new JObject(); - var logicalName = attrValue.SelectToken("$.logicalName").ToString(); - var displayName = attrValue.SelectToken("$.displayName").ToString(); - propValues["title"] = displayName; - propValues["type"] = type; - properties[logicalName] = propValues; - } - - schema["properties"] = properties; - - var filePath = $"obj/models/{entityValue["logicalName"]}.spec.g.json"; - File.WriteAllText(filePath, schema.ToString(Newtonsoft.Json.Formatting.Indented)); - } - catch (Exception ex) - { - Console.WriteLine($"Warning: Failed to generate jsonschema for {entity.Name}"); - Console.Write(ex); - } - } - - return json; - } - - private async Task EnrichEntity(JToken jsonraw, string customizationprefix, ILogger logger, string insertMerges, JObject entity) - { - JObject SetDefault(JToken obj, JObject localeEnglish) - { - var value = new JObject(new JProperty("1033", localeEnglish)); - obj["locale"] = value; - return value; - } - var entityLocaleEnglish = new JObject(new JProperty("displayName", entity["displayName"]), new JProperty("pluralName", entity["pluralName"])); - var entityLocale = entity.SelectToken("$.locale") as JObject ?? SetDefault(entity, entityLocaleEnglish); - if (!entityLocale.ContainsKey("1033")) - entityLocale["1033"] = entityLocaleEnglish; - - - var attributes = entity.SelectToken("$.attributes") as JObject; - - if (attributes == null) - { - entity["attributes"] = attributes = new JObject(); - } - - if (attributes != null) - { - if (!attributes.Properties().Any(p => p.Value.SelectToken("$.isPrimaryKey")?.ToObject() ?? false)) - { - attributes["Id"] = JToken.FromObject(new { isPrimaryKey = true, type = new { type = "guid" } }); - } - - - //Replace string attributes - foreach (var attr in attributes.Properties().ToArray()) - { - if (attr.Name == "[merge()]") - { - await manifestReplacmentRunner.RunReplacements(jsonraw, customizationprefix, logger, attr); - } - else if (attr.Value.Type == JTokenType.String) - { - await manifestReplacmentRunner.RunReplacements(jsonraw, customizationprefix, logger, attr.Value); - } - } - - var queue = new Queue(attributes.Properties().Select(c => c.Value as JObject)); - - foreach (var attribute in attributes.Properties()) - { - if (!string.IsNullOrEmpty(insertMerges)) - { - var value = attribute.Value as JObject; - if (!value?.ContainsKey("[merge()]") ?? false) - value.Add(new JProperty("[merge()]", $"[variables('{insertMerges}')]")); - queue.Enqueue(value); - } - } - - - while (queue.Count > 0) - { - var attr = queue.Dequeue(); - - - - if (!attr.ContainsKey("displayName")) - attr["displayName"] = (attr.Parent as JProperty)?.Name; - - if (attr["type"]?.ToString() == "address") - { - - var displayName = attr.SelectToken("$.displayName")?.ToString(); - - attr["__unroll__path"] = attr.Path; - - var unrolls = new[] { - Merge(attr,new { displayName=$"{displayName}: Address Type", type=new { type ="picklist", - isGlobal=false, - name=$"{displayName}: Address Type", - options=CreateOptions("Bill To","Ship To","Primary","Other") - } }), - Merge(attr,new { displayName=$"{displayName}: City", type="string"}), - Merge(attr,new { displayName=$"{displayName}: Country", type="string", schemaName=schemaName.ToSchemaName( $"{displayName}: Country")}), - Merge(attr,new { displayName=$"{displayName}: County", type="string"}), - Merge(attr,new { displayName=$"{displayName}: Fax", type="string"}), - Merge(attr,new { displayName=$"{displayName}: Freight Terms", schemaName=schemaName.ToSchemaName( $"{displayName}: Freight Terms Code"), type=new { type="picklist", - isGlobal=false, - name=$"{displayName}: Freight Terms", - options=CreateOptions("FOB","No Charge") - } }), - // Merge(attr,new { displayName=$"{displayName}: Id",schemaName=ToSchemaName( $"{displayName}: AddressId"),type ="guid"}), - CreateAttribute(attr,$"{displayName}: Latitude","float"), - CreateAttribute(attr,$"{displayName}: Longitude","float"), - CreateAttribute(attr,$"{displayName}: Name","string",null, new { isPrimaryField = !attributes.Properties().Any(p=>p.Value.SelectToken("$.isPrimaryField") != null) }), - CreateAttribute(attr,$"{displayName}: Phone","phone", schemaName.ToSchemaName( $"{displayName}: Telephone 1")), - CreateAttribute(attr,$"{displayName}: Telephone 2","phone", schemaName.ToSchemaName( $"{displayName}: Telephone 2")), - CreateAttribute(attr,$"{displayName}: Telephone 3","phone", schemaName.ToSchemaName( $"{displayName}: Telephone 3")), - CreateAttribute(attr,$"{displayName}: Post Office Box","string"), - CreateAttribute(attr,$"{displayName}: Primary Contact Name","string"), - CreateAttribute(attr,$"{displayName}: Shipping Method",new { type="picklist", - isGlobal=false, - name=$"{displayName}: Shipping Method", - options=CreateOptions("Airborne","DHL","FedEx","UPS","Postal Mail","Full Load","Will Call"), - }, schemaName.ToSchemaName( $"{displayName}: Shipping Method Code")), - CreateAttribute(attr,$"{displayName}: State/Province","string"), - CreateAttribute(attr,$"{displayName}: Street 1","string",schemaName.ToSchemaName( $"{displayName}: line1")), - CreateAttribute(attr,$"{displayName}: Street 2","string",schemaName.ToSchemaName( $"{displayName}: line2")), - CreateAttribute(attr,$"{displayName}: Street 3","string",schemaName.ToSchemaName( $"{displayName}: line3")), - CreateAttribute(attr,$"{displayName}: UPS Zone","string"), - CreateAttribute(attr,$"{displayName}: UTC Offset","timezone"), - CreateAttribute(attr,$"{displayName}: ZIP/Postal Code","string",schemaName.ToSchemaName( $"{displayName}: Postal Code")), - CreateAttribute(attr,$"{displayName}: State/Province","string"), - - }; - - attr["schemaName"] = displayName.Replace(" ", "").Replace(":", "_") + "_Composite"; - attr["type"] = "MultilineText"; - - - foreach (var unroll in unrolls) - { - queue.Enqueue(unroll); - } - - //if(!attributes.Properties().Any(p=>p.Value.SelectToken("$.isPrimaryField") != null)) - //{ - // attr["type"] = JObject.FromObject(new { type = "string", maxLength = 1024 }); - // attr["isPrimaryField"] = true; - //} - - } - - - if (!attr.ContainsKey("schemaName")) - { - - attr["schemaName"] = schemaName.ToSchemaName(attr.SelectToken("$.displayName").ToString()); - - await manifestReplacmentRunner.RunReplacements(jsonraw, customizationprefix, logger, attr); - - switch (attr.SelectToken("$.type.type")?.ToString()?.ToLower()) - { - case "lookup": - case "polylookup": - case "customer": - if (!attr["schemaName"].ToString().EndsWith("Id")) - attr["schemaName"] = $"{schemaName.ToSchemaName(attr.SelectToken("$.displayName").ToString())}Id"; - - - - break; - - } - } - - - if (!attr.ContainsKey("logicalName")) - attr["logicalName"] = attr.SelectToken("$.schemaName").ToString().ToLower(); - - if (!attr.ContainsKey("type")) - attr["type"] = "string"; - - if (attr.Parent == null && !(attributes.ContainsKey(attr["logicalName"].ToString()) || attributes.ContainsKey(attr["schemaName"].ToString()) || attributes.ContainsKey(attr["displayName"].ToString()))) - attributes[attr["logicalName"].ToString()] = attr; - - if (attr.SelectToken("$.type").Type == JTokenType.String) - { - attr["type"] = JToken.FromObject(new { type = attr.SelectToken("$.type") }); - } - - - - } - - foreach (var attr in attributes.Properties()) - { - var attributeLocaleEnglish = new JObject(new JProperty("displayName", attr.Value["displayName"])); - var attributeLocale = attr.Value.SelectToken("$.locale") as JObject ?? SetDefault(attr.Value, attributeLocaleEnglish); - if (!attributeLocale.ContainsKey("1033")) - attributeLocale["1033"] = attributeLocaleEnglish; - } - - - } - } - - private void SetRequiredProps(JObject entity, string key) - { - if (!entity.ContainsKey("displayName")) - entity["displayName"] = key; - if (!entity.ContainsKey("schemaName")) - entity["schemaName"] = entity.SelectToken("$.displayName")?.ToString().Replace(" ", ""); - if (!entity.ContainsKey("logicalName")) - entity["logicalName"] = entity.SelectToken("$.schemaName")?.ToString().ToLower(); - - if (!entity.ContainsKey("collectionSchemaName")) - entity["collectionSchemaName"] = schemaName.ToSchemaName(entity["pluralName"]?.ToString()); - } - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/ManifestEnricherOptions.cs b/src/EAVFW.Extensions.Manifest.SDK/ManifestEnricherOptions.cs deleted file mode 100644 index 9a8d76b..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/ManifestEnricherOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.IO; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public class ManifestEnricherOptions - { - public string Path { get; set; } = Directory.GetCurrentDirectory(); - } -} \ No newline at end of file diff --git a/src/EAVFW.Extensions.Manifest.SDK/ServiceRegistrationExtension.cs b/src/EAVFW.Extensions.Manifest.SDK/ServiceRegistrationExtension.cs deleted file mode 100644 index 179a005..0000000 --- a/src/EAVFW.Extensions.Manifest.SDK/ServiceRegistrationExtension.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace EAVFW.Extensions.Manifest.SDK -{ - public static class ServiceRegistrationExtension - { - public static IServiceCollection AddManifestSDK(this IServiceCollection services) where TParameterGenerator : class,IParameterGenerator - { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddSingleton(); - services.AddOptions(); - - return services; - } - } -} \ No newline at end of file diff --git a/tests/EAVFW.Extensions.Manifest.Tests/EAVFW.Extensions.Manifest.Tests.csproj b/tests/EAVFW.Extensions.Manifest.Tests/EAVFW.Extensions.Manifest.Tests.csproj index 3fa4c1d..0fae815 100644 --- a/tests/EAVFW.Extensions.Manifest.Tests/EAVFW.Extensions.Manifest.Tests.csproj +++ b/tests/EAVFW.Extensions.Manifest.Tests/EAVFW.Extensions.Manifest.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -20,7 +20,7 @@ - +