From 854d2463fcf34471d60694cf80ff01f0d46c559d Mon Sep 17 00:00:00 2001 From: YevhenPetlovanyi Date: Fri, 15 Mar 2024 16:17:24 +0200 Subject: [PATCH 1/5] #758 The AddIndexesButton was added --- .../Buttons/AddIndexesButton.cs | 57 +++++++++++++++++++ src/SIM.Tool.Windows/MainWindowData.cs | 6 ++ src/SIM.Tool.Windows/SIM.Tool.Windows.csproj | 1 + .../ButtonsConfiguration.json | 1 + 4 files changed, 65 insertions(+) create mode 100644 src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs diff --git a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs new file mode 100644 index 00000000..46e3819f --- /dev/null +++ b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs @@ -0,0 +1,57 @@ +using SIM.Core; +using SIM.Instances; +using SIM.Tool.Base.Wizards; +using Sitecore.Diagnostics.Base; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Xml; + +namespace SIM.Tool.Windows.MainWindowComponents.Buttons +{ + public class AddIndexesButton : InstanceOnlyButton + { + public override void OnClick(Window mainWindow, Instance instance) + { + if (instance != null) + { + XmlDocument sitecoreWebResultConfig = instance.GetWebResultConfig(); + XmlNodeList solrIndexes = GetSolrIndexNodesFrom(sitecoreWebResultConfig); + + foreach (XmlElement node in solrIndexes) + { + string coreName = GetCoreName(node); + } + + string solrUrl = GetUrlFrom(sitecoreWebResultConfig); + } + } + + private static string GetCoreName(XmlElement node) + { + var coreElement = node.SelectSingleNode("param[@desc='core']") as XmlElement; + string id = node.Attributes["id"].InnerText; + coreElement = Assert.IsNotNull(coreElement, "param[@desc='core'] not found in Solr configuration file"); + string coreName = coreElement.InnerText.Replace("$(id)", id); + return coreName; + } + + private static XmlNodeList GetSolrIndexNodesFrom(XmlDocument sitecoreConfig) + { + return sitecoreConfig.SelectNodes( + "//sitecore/contentSearch/configuration/indexes/index[@type='Sitecore.ContentSearch.SolrProvider.SolrSearchIndex, Sitecore.ContentSearch.SolrProvider']"); + } + + private static string GetUrlFrom(XmlDocument sitecoreConfig) + { + string connectionStringName = "solr.search"; + XmlNode connectionStringNode = sitecoreConfig.SelectSingleNode("//connectionStrings/add[@name='" + connectionStringName + "']"); + Assert.IsNotNull(connectionStringNode, "ConnectionString with name '" + connectionStringName + "' not found."); + return connectionStringNode.Attributes["connectionString"].Value; + } + } +} diff --git a/src/SIM.Tool.Windows/MainWindowData.cs b/src/SIM.Tool.Windows/MainWindowData.cs index 4c28f768..521f4a42 100644 --- a/src/SIM.Tool.Windows/MainWindowData.cs +++ b/src/SIM.Tool.Windows/MainWindowData.cs @@ -691,6 +691,12 @@ private static ButtonDefinition GetPatchButton() Image = "/Images/$lg/install.png, SIM.Tool.Windows", Handler = new InstallModulesForSitecore9AndLaterButton() }, + new ButtonDefinition + { + Label = "Add Indexes", + Image = "/Images/$lg/install.png, SIM.Tool.Windows", + Handler = new AddIndexesButton() + }, } }, GetManageGroupDefinition(), diff --git a/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj b/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj index e95f1659..353aa160 100644 --- a/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj +++ b/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj @@ -156,6 +156,7 @@ + diff --git a/src/SIM.Tool/ButtonsConfiguration/ButtonsConfiguration.json b/src/SIM.Tool/ButtonsConfiguration/ButtonsConfiguration.json index 3423402f..adc827f5 100644 --- a/src/SIM.Tool/ButtonsConfiguration/ButtonsConfiguration.json +++ b/src/SIM.Tool/ButtonsConfiguration/ButtonsConfiguration.json @@ -95,6 +95,7 @@ "ManagedArgsTracerButton" ], "Sitecore9AndLaterButtons": [ + "AddIndexesButton", "InstallModulesForSitecore9AndLaterButton", "RefreshButton", "InstallInstanceButton", From caa0c4ea2791694b8d9b08622c72b60a32ccf05f Mon Sep 17 00:00:00 2001 From: YevhenPetlovanyi Date: Tue, 19 Mar 2024 08:50:23 +0200 Subject: [PATCH 2/5] #758 Added logic for retrieving all cores from Solr and checking for matches with indexes from Sitecore --- .../Buttons/AddIndexesButton.cs | 101 +++++++++++++++++- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs index 46e3819f..61febe63 100644 --- a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs +++ b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs @@ -1,15 +1,24 @@ -using SIM.Core; +using Newtonsoft.Json.Linq; +using SIM.Core; using SIM.Instances; +using SIM.Pipelines.Install.Modules; using SIM.Tool.Base.Wizards; using Sitecore.Diagnostics.Base; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Xml; +using Newtonsoft.Json; +using System.Data.SqlTypes; +using System.Net.Http; +using System.Net.NetworkInformation; + namespace SIM.Tool.Windows.MainWindowComponents.Buttons { @@ -21,16 +30,50 @@ public override void OnClick(Window mainWindow, Instance instance) { XmlDocument sitecoreWebResultConfig = instance.GetWebResultConfig(); XmlNodeList solrIndexes = GetSolrIndexNodesFrom(sitecoreWebResultConfig); + string solrUrl = GetUrlFrom(sitecoreWebResultConfig); + string home = GetSolrHome(solrUrl); + XmlNodeList existingSolrCores = GetExistingCoresFromSolr(solrUrl); foreach (XmlElement node in solrIndexes) { string coreName = GetCoreName(node); - } + bool itemMatched = false; - string solrUrl = GetUrlFrom(sitecoreWebResultConfig); + foreach (XmlElement existingSolrnode in existingSolrCores) + { + string existingCoreName = existingSolrnode["name"].InnerText; + if (coreName == existingCoreName) + { + itemMatched = true; + break; + } + } + + if (!itemMatched) + { + CreateSolrCore(solrUrl, coreName); + } + } } } + private void CreateSolrCore(string solrUrl, string coreName) + { + string test = coreName; + } + + private XmlNodeList GetExistingCoresFromSolr(string solrUrl) + { + var solrInfoUrl = $"{solrUrl}/admin/cores?action=STATUS&wt=json"; + //Stream response = RequestAndGetResponseStream(url); + //string responseAsString = GetStringFromStream(response); + //string xmlString = ReturnXml(responseAsString); + //var doc = XmlDocumentEx.LoadXml(xmlString); + var doc = GetXmlDocumenFromSolrResponse(solrInfoUrl); + XmlNodeList solrIndexes = doc.SelectNodes("//status/*"); + return solrIndexes; + } + private static string GetCoreName(XmlElement node) { var coreElement = node.SelectSingleNode("param[@desc='core']") as XmlElement; @@ -53,5 +96,57 @@ private static string GetUrlFrom(XmlDocument sitecoreConfig) Assert.IsNotNull(connectionStringNode, "ConnectionString with name '" + connectionStringName + "' not found."); return connectionStringNode.Attributes["connectionString"].Value; } + + private string GetSolrHome(string url) + { + string solrInfoUrl = $"{url}/admin/info/system"; + var doc = GetXmlDocumenFromSolrResponse(solrInfoUrl); + return ReturnSolrHome(doc); + } + + private XmlDocumentEx GetXmlDocumenFromSolrResponse(string solrInfoUrl) + { + Stream response = RequestAndGetResponseStream(solrInfoUrl); + string responseAsString = GetStringFromStream(response); + string xmlString = ReturnXml(responseAsString); + var doc = XmlDocumentEx.LoadXml(xmlString); + return doc; + } + + private string ReturnSolrHome(XmlDocumentEx xml) + { + XmlNode solrHomeNode = xml.SelectSingleNode("/response/solr_home"); + Assert.IsNotNull(solrHomeNode, "solr_home element should not be null"); + string solrHomeValue = solrHomeNode.InnerText; + return solrHomeValue.Replace("\\\\", "\\"); + } + + private Stream RequestAndGetResponseStream(string url) + { + return WebRequestHelper.RequestAndGetResponse(url).GetResponseStream(); + } + + private string GetStringFromStream(Stream stream) + { + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + + private string NormalizeXml(XmlDocumentEx xml) + { + string outerXml = xml.OuterXml; + string formatted = XmlDocumentEx.Normalize(outerXml); + Regex r = new Regex(@"^<\?.*\?>"); + string corrected = r.Replace(formatted, @""); //Solr requires UTF-8. + return corrected; + } + + private string ReturnXml(string jsonObject) + { + string xmlString = JsonConvert.DeserializeXmlNode(jsonObject, "response").OuterXml; + return xmlString; + } } } From 0c1448c2c20a06e89f05c7ad3232d3aaf832139a Mon Sep 17 00:00:00 2001 From: YevhenPetlovanyi Date: Wed, 20 Mar 2024 12:10:09 +0200 Subject: [PATCH 3/5] #758 Move getiing Auth logic to separate class --- ...nstallModulesForSitecore9AndLaterButton.cs | 171 ++--------------- .../Helpers/ButtonAuthenticationHelper.cs | 177 ++++++++++++++++++ src/SIM.Tool.Windows/SIM.Tool.Windows.csproj | 1 + 3 files changed, 190 insertions(+), 159 deletions(-) create mode 100644 src/SIM.Tool.Windows/MainWindowComponents/Helpers/ButtonAuthenticationHelper.cs diff --git a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/InstallModulesForSitecore9AndLaterButton.cs b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/InstallModulesForSitecore9AndLaterButton.cs index 06fa88cb..18a17451 100644 --- a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/InstallModulesForSitecore9AndLaterButton.cs +++ b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/InstallModulesForSitecore9AndLaterButton.cs @@ -1,16 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; +using System.Collections.Generic; using System.Windows; using JetBrains.Annotations; -using SIM.Core; using SIM.Instances; -using SIM.Tool.Base; using SIM.Tool.Base.Pipelines; using SIM.Tool.Base.Wizards; -using SIM.Tool.Windows.Dialogs; -using SIM.Tool.Windows.UserControls.SitecoreAuthentication; +using SIM.Tool.Windows.MainWindowComponents.Helpers; namespace SIM.Tool.Windows.MainWindowComponents.Buttons { @@ -22,176 +16,35 @@ public override void OnClick(Window mainWindow, Instance instance) if (instance != null) { Dictionary headers = null; - string authCookieOrIdServerAuthToken = null; + string authCookie = null; int.TryParse(instance.Product.ShortVersion, out int sitecoreVersion); + ButtonAuthenticationHelper buttonAuthenticationHelper = new ButtonAuthenticationHelper(); + if (sitecoreVersion >= 91) { - string sitecoreIdServerUri = "https://" + instance.SitecoreEnvironment.Name + "Id.local"; - authCookieOrIdServerAuthToken = this.GetAuthToken(sitecoreIdServerUri, CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); - authCookieOrIdServerAuthToken = this.ValidateAuthToken(authCookieOrIdServerAuthToken, sitecoreIdServerUri, - CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); + headers = buttonAuthenticationHelper.GetIdServerAuthToken(mainWindow, instance); - if (string.IsNullOrEmpty(authCookieOrIdServerAuthToken)) + if (headers == null) { return; - } - - headers = new Dictionary { { "Authorization", authCookieOrIdServerAuthToken } }; + } } else if (sitecoreVersion == 90) { string instanceUri = instance.GetUrl(); - if (!this.IsInstanceUriValid(instanceUri)) - { - return; - } - - authCookieOrIdServerAuthToken = this.GetAuthCookie(instanceUri, CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); - authCookieOrIdServerAuthToken = this.ValidateAuthCookie(authCookieOrIdServerAuthToken, instanceUri, - CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); + authCookie = buttonAuthenticationHelper.GetAuthCookie(mainWindow, instance); - if (string.IsNullOrEmpty(authCookieOrIdServerAuthToken)) + if (string.IsNullOrEmpty(authCookie)) { return; } } var id = MainWindowHelper.GetListItemID(instance.ID); - WizardPipelineManager.Start("installmodules", mainWindow, null, null, ignore => MainWindowHelper.MakeInstanceSelected(id), () => new InstallModulesWizardArgs(instance, authCookieOrIdServerAuthToken, headers)); - } - } - - private string GetAuthToken(string sitecoreIdServerUri, string userName, string password, Window mainWindow) - { - string idServerAuthToken = null; - - WindowHelper.LongRunningTask(() => - { - var task = Task.Run(async () => { - idServerAuthToken = await - SitecoreIdServerAuth.GetToken(sitecoreIdServerUri, userName, password); - }); - task?.Wait(); - }, "Get authentication token", mainWindow, "Getting authentication token", "", true); - - return idServerAuthToken; - } - - private string ValidateAuthToken(string idServerAuthToken, string sitecoreIdServerUri, string userName, string password, Window mainWindow) - { - if (SitecoreIdServerAuth.CurrentHttpStatusCode == HttpStatusCode.InternalServerError) - { - WindowHelper.HandleError("Unable to get authentication token using the following Sitecore Identity Server URI:\n\n" + - sitecoreIdServerUri, true); - return null; - } - else if (SitecoreIdServerAuth.CurrentHttpStatusCode != HttpStatusCode.OK && SitecoreIdServerAuth.CurrentHttpStatusCode != HttpStatusCode.BadRequest) - { - WindowHelper.ShowMessage( - "Unable to get authentication token using the following Sitecore Identity Server URI:\n\n" + - sitecoreIdServerUri + - "\n\nThe '" + SitecoreIdServerAuth.CurrentHttpStatusCode + "' status code has been returned." + - "\n\nPlease make sure that this Sitecore Identity Server is running.", - MessageBoxButton.OK, - MessageBoxImage.Warning); - return null; - } - - if (SitecoreIdServerAuth.CurrentHttpStatusCode == HttpStatusCode.BadRequest) - { - if (WindowHelper.ShowMessage( - "Unable to get authentication token using the following data:\n\nIdentity Server URI: " + sitecoreIdServerUri + - "\nUser name: " + userName + "\nPassword: " + password + "\n\nWould you like to try to continue installation using other URI and credentials?", - MessageBoxButton.YesNo, - MessageBoxImage.Warning) == MessageBoxResult.Yes) - { - CredentialsContext credentialsContext = - WindowHelper.ShowDialog(new CredentialsContext(userName, password, sitecoreIdServerUri), null) as CredentialsContext; - if (credentialsContext != null) - { - idServerAuthToken = this.GetAuthToken(credentialsContext.Uri, credentialsContext.UserName, credentialsContext.Password, mainWindow); - this.ValidateAuthToken(idServerAuthToken, credentialsContext.Uri, credentialsContext.UserName, credentialsContext.Password, mainWindow); - } - } + WizardPipelineManager.Start("installmodules", mainWindow, null, null, ignore => MainWindowHelper.MakeInstanceSelected(id), () => new InstallModulesWizardArgs(instance, authCookie, headers)); } - - return idServerAuthToken; - } - - private string GetAuthCookie(string instanceUri, string userName, string password, Window mainWindow) - { - string authCookie = null; - - WindowHelper.LongRunningTask(() => - { - var task = Task.Run(async () => { - authCookie = await - SitecoreServicesClientAuth.GetCookie(instanceUri, userName, password); - }); - task?.Wait(); - }, "Get authentication cookie", mainWindow, "Getting authentication cookie", "", true); - - return authCookie; - } - - private string ValidateAuthCookie(string authCookie, string instanceUri, string userName, string password, Window mainWindow) - { - if (SitecoreServicesClientAuth.CurrentHttpStatusCode == HttpStatusCode.InternalServerError) - { - WindowHelper.HandleError("Unable to get authentication cookie using the following Sitecore instance URI:\n\n" + - instanceUri + - "\n\nPlease make sure that a valid certificate is used for the SSL binding of your Sitecore site.", true); - return null; - } - else if (SitecoreServicesClientAuth.CurrentHttpStatusCode != HttpStatusCode.OK && SitecoreServicesClientAuth.CurrentHttpStatusCode != HttpStatusCode.Forbidden) - { - WindowHelper.ShowMessage( - "Unable to get authentication cookie using the following Sitecore instance URI:\n\n" + - instanceUri + - "\n\nThe '" + SitecoreServicesClientAuth.CurrentHttpStatusCode + "' status code has been returned." + - "\n\nPlease make sure that this Sitecore site is running.", - MessageBoxButton.OK, - MessageBoxImage.Warning); - return null; - } - - if (SitecoreServicesClientAuth.CurrentHttpStatusCode == HttpStatusCode.Forbidden) - { - if (WindowHelper.ShowMessage( - "Unable to get authentication cookie using the following credentials:\n\n" + - "User name: " + userName + "\nPassword: " + password + "\n\nWould you like to try to continue installation using other credentials?", - MessageBoxButton.YesNo, - MessageBoxImage.Warning) == MessageBoxResult.Yes) - { - CredentialsContext credentialsContext = - WindowHelper.ShowDialog(new CredentialsContext(userName, password), null) as CredentialsContext; - if (credentialsContext != null) - { - authCookie = this.GetAuthCookie(instanceUri, credentialsContext.UserName, credentialsContext.Password, mainWindow); - this.ValidateAuthCookie(authCookie, instanceUri, credentialsContext.UserName, credentialsContext.Password, mainWindow); - } - } - } - - return authCookie; - } - - private bool IsInstanceUriValid(string instanceUri) - { - if (!instanceUri.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) - { - WindowHelper.ShowMessage( - "The selected Sitecore instance does not use SSL/TLS connection according to the following URI:\n\n" + - instanceUri + - "\n\nThe SSC Auth services that are needed for package installation require an SSL/TLS connection, so you need to set up a valid certificate and SSL binding for your Sitecore site.", - MessageBoxButton.OK, - MessageBoxImage.Warning); - return false; - } - - return true; - } + } } } \ No newline at end of file diff --git a/src/SIM.Tool.Windows/MainWindowComponents/Helpers/ButtonAuthenticationHelper.cs b/src/SIM.Tool.Windows/MainWindowComponents/Helpers/ButtonAuthenticationHelper.cs new file mode 100644 index 00000000..56b513fd --- /dev/null +++ b/src/SIM.Tool.Windows/MainWindowComponents/Helpers/ButtonAuthenticationHelper.cs @@ -0,0 +1,177 @@ +using SIM.Core; +using SIM.Instances; +using SIM.Tool.Base; +using SIM.Tool.Windows.Dialogs; +using SIM.Tool.Windows.UserControls.SitecoreAuthentication; +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using System.Windows; + +namespace SIM.Tool.Windows.MainWindowComponents.Helpers +{ + public class ButtonAuthenticationHelper + { + public Dictionary GetIdServerAuthToken(Window mainWindow, Instance instance) + { + string sitecoreIdServerUri = "https://" + instance.SitecoreEnvironment.Name + "Id.local"; + string idServerAuthToken = GetAuthToken(sitecoreIdServerUri, CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); + idServerAuthToken = ValidateAuthToken(idServerAuthToken, sitecoreIdServerUri, + CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); + + if (string.IsNullOrEmpty(idServerAuthToken)) + { + return null; + } + return new Dictionary { { "Authorization", idServerAuthToken } }; ; + } + + public string GetAuthCookie(Window mainWindow, Instance instance) + { + string instanceUri = instance.GetUrl(); + + if (!IsInstanceUriValid(instanceUri)) + { + return null; + } + + string authCookie = GetAuthClientCookie(instanceUri, CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); + authCookie = ValidateAuthCookie(authCookie, instanceUri, + CoreAppSettings.AppLoginAsAdminUserName.Value, CoreAppSettings.AppLoginAsAdminNewPassword.Value, mainWindow); + + return authCookie; + } + + private string GetAuthToken(string sitecoreIdServerUri, string userName, string password, Window mainWindow) + { + string idServerAuthToken = null; + + WindowHelper.LongRunningTask(() => + { + var task = Task.Run(async () => { + idServerAuthToken = await + SitecoreIdServerAuth.GetToken(sitecoreIdServerUri, userName, password); + }); + task?.Wait(); + }, "Get authentication token", mainWindow, "Getting authentication token", "", true); + + return idServerAuthToken; + } + + private string ValidateAuthToken(string idServerAuthToken, string sitecoreIdServerUri, string userName, string password, Window mainWindow) + { + if (SitecoreIdServerAuth.CurrentHttpStatusCode == HttpStatusCode.InternalServerError) + { + WindowHelper.HandleError("Unable to get authentication token using the following Sitecore Identity Server URI:\n\n" + + sitecoreIdServerUri, true); + return null; + } + else if (SitecoreIdServerAuth.CurrentHttpStatusCode != HttpStatusCode.OK && SitecoreIdServerAuth.CurrentHttpStatusCode != HttpStatusCode.BadRequest) + { + WindowHelper.ShowMessage( + "Unable to get authentication token using the following Sitecore Identity Server URI:\n\n" + + sitecoreIdServerUri + + "\n\nThe '" + SitecoreIdServerAuth.CurrentHttpStatusCode + "' status code has been returned." + + "\n\nPlease make sure that this Sitecore Identity Server is running.", + MessageBoxButton.OK, + MessageBoxImage.Warning); + return null; + } + + if (SitecoreIdServerAuth.CurrentHttpStatusCode == HttpStatusCode.BadRequest) + { + if (WindowHelper.ShowMessage( + "Unable to get authentication token using the following data:\n\nIdentity Server URI: " + sitecoreIdServerUri + + "\nUser name: " + userName + "\nPassword: " + password + "\n\nWould you like to try to continue installation using other URI and credentials?", + MessageBoxButton.YesNo, + MessageBoxImage.Warning) == MessageBoxResult.Yes) + { + CredentialsContext credentialsContext = + WindowHelper.ShowDialog(new CredentialsContext(userName, password, sitecoreIdServerUri), null) as CredentialsContext; + if (credentialsContext != null) + { + idServerAuthToken = this.GetAuthToken(credentialsContext.Uri, credentialsContext.UserName, credentialsContext.Password, mainWindow); + this.ValidateAuthToken(idServerAuthToken, credentialsContext.Uri, credentialsContext.UserName, credentialsContext.Password, mainWindow); + } + } + } + + return idServerAuthToken; + } + + private string GetAuthClientCookie(string instanceUri, string userName, string password, Window mainWindow) + { + string authCookie = null; + + WindowHelper.LongRunningTask(() => + { + var task = Task.Run(async () => { + authCookie = await + SitecoreServicesClientAuth.GetCookie(instanceUri, userName, password); + }); + task?.Wait(); + }, "Get authentication cookie", mainWindow, "Getting authentication cookie", "", true); + + return authCookie; + } + + private string ValidateAuthCookie(string authCookie, string instanceUri, string userName, string password, Window mainWindow) + { + if (SitecoreServicesClientAuth.CurrentHttpStatusCode == HttpStatusCode.InternalServerError) + { + WindowHelper.HandleError("Unable to get authentication cookie using the following Sitecore instance URI:\n\n" + + instanceUri + + "\n\nPlease make sure that a valid certificate is used for the SSL binding of your Sitecore site.", true); + return null; + } + else if (SitecoreServicesClientAuth.CurrentHttpStatusCode != HttpStatusCode.OK && SitecoreServicesClientAuth.CurrentHttpStatusCode != HttpStatusCode.Forbidden) + { + WindowHelper.ShowMessage( + "Unable to get authentication cookie using the following Sitecore instance URI:\n\n" + + instanceUri + + "\n\nThe '" + SitecoreServicesClientAuth.CurrentHttpStatusCode + "' status code has been returned." + + "\n\nPlease make sure that this Sitecore site is running.", + MessageBoxButton.OK, + MessageBoxImage.Warning); + return null; + } + + if (SitecoreServicesClientAuth.CurrentHttpStatusCode == HttpStatusCode.Forbidden) + { + if (WindowHelper.ShowMessage( + "Unable to get authentication cookie using the following credentials:\n\n" + + "User name: " + userName + "\nPassword: " + password + "\n\nWould you like to try to continue installation using other credentials?", + MessageBoxButton.YesNo, + MessageBoxImage.Warning) == MessageBoxResult.Yes) + { + CredentialsContext credentialsContext = + WindowHelper.ShowDialog(new CredentialsContext(userName, password), null) as CredentialsContext; + if (credentialsContext != null) + { + authCookie = this.GetAuthClientCookie(instanceUri, credentialsContext.UserName, credentialsContext.Password, mainWindow); + this.ValidateAuthCookie(authCookie, instanceUri, credentialsContext.UserName, credentialsContext.Password, mainWindow); + } + } + } + + return authCookie; + } + + private bool IsInstanceUriValid(string instanceUri) + { + if (!instanceUri.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) + { + WindowHelper.ShowMessage( + "The selected Sitecore instance does not use SSL/TLS connection according to the following URI:\n\n" + + instanceUri + + "\n\nThe SSC Auth services that are needed for package installation require an SSL/TLS connection, so you need to set up a valid certificate and SSL binding for your Sitecore site.", + MessageBoxButton.OK, + MessageBoxImage.Warning); + return false; + } + + return true; + } + } +} diff --git a/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj b/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj index 353aa160..298b0ed8 100644 --- a/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj +++ b/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj @@ -230,6 +230,7 @@ + From 2dbcbfa9f1f7f60638f21c0478f5cd1f86ffa862 Mon Sep 17 00:00:00 2001 From: YevhenPetlovanyi Date: Wed, 20 Mar 2024 12:11:27 +0200 Subject: [PATCH 4/5] #758 A new GetSeparateSolrAttribute method was added --- src/SIM.Base/SolrStateResolver.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/SIM.Base/SolrStateResolver.cs b/src/SIM.Base/SolrStateResolver.cs index 67687f5d..04e76bea 100644 --- a/src/SIM.Base/SolrStateResolver.cs +++ b/src/SIM.Base/SolrStateResolver.cs @@ -76,6 +76,27 @@ public virtual string GetVersion(string solrUrl) return string.Empty; } + + public virtual string GetSeparateSolrAttribute(string solrUrl, string attributName) + { + HttpClient client = new HttpClient(); + + using (Stream stream = client.GetStreamAsync($"{solrUrl}/admin/info/system?wt=json").Result) + using (StreamReader streamReader = new StreamReader(stream)) + using (JsonReader reader = new JsonTextReader(streamReader)) + { + while (reader.Read()) + { + if (string.Equals(reader.Path, attributName, StringComparison.OrdinalIgnoreCase) + && !string.Equals((string)reader.Value, attributName, StringComparison.OrdinalIgnoreCase)) + { + return (string)reader.Value; + } + } + } + + return string.Empty; + } } public class ServiceControllerWrapper From 43157a7055fdcc86a801171178bdce71b36bc224 Mon Sep 17 00:00:00 2001 From: YevhenPetlovanyi Date: Wed, 10 Apr 2024 13:06:56 +0300 Subject: [PATCH 5/5] #758 Add wizard that allows to install Solr cores --- src/SIM.Base/SolrStateResolver.cs | 17 ++ .../CreateIndexDirectoryAction.cs | 47 +++++ .../CreateSolrCoreAction.cs | 36 ++++ .../InstallSearchIndexesArgs.cs | 49 +++++ .../InstallSearchIndexesProcessor.cs | 46 +++++ .../PopulateNewIndexAction.cs | 60 +++++++ .../UpdateManagedSchemaAction.cs | 49 +++++ src/SIM.Pipelines/PipelinesConfig.cs | 6 + src/SIM.Pipelines/SIM.Pipelines.csproj | 6 + .../InstallSearchIndexesWizardArgs.cs | 82 +++++++++ src/SIM.Tool.Base/SIM.Tool.Base.csproj | 1 + .../Images/16/search_index.png | Bin 0 -> 899 bytes .../Images/24/search_index.png | Bin 0 -> 1678 bytes .../Images/32/search_index.png | Bin 0 -> 2466 bytes .../Images/48/search_index.png | Bin 0 -> 4355 bytes .../Buttons/AddIndexesButton.cs | 152 ---------------- .../Buttons/AddSolrCoresButton.cs | 170 ++++++++++++++++++ src/SIM.Tool.Windows/MainWindowData.cs | 7 +- src/SIM.Tool.Windows/SIM.Tool.Windows.csproj | 13 +- .../SearchIndexes/AvailableSearchIndexes.xaml | 18 ++ .../AvailableSearchIndexes.xaml.cs | 68 +++++++ src/SIM.Tool.Windows/WizardPipelinesConfig.cs | 12 +- .../ButtonsConfiguration.json | 2 +- 23 files changed, 683 insertions(+), 158 deletions(-) create mode 100644 src/SIM.Pipelines/InstallSearchIndexes/CreateIndexDirectoryAction.cs create mode 100644 src/SIM.Pipelines/InstallSearchIndexes/CreateSolrCoreAction.cs create mode 100644 src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesArgs.cs create mode 100644 src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesProcessor.cs create mode 100644 src/SIM.Pipelines/InstallSearchIndexes/PopulateNewIndexAction.cs create mode 100644 src/SIM.Pipelines/InstallSearchIndexes/UpdateManagedSchemaAction.cs create mode 100644 src/SIM.Tool.Base/Pipelines/InstallSearchIndexesWizardArgs.cs create mode 100644 src/SIM.Tool.Windows/Images/16/search_index.png create mode 100644 src/SIM.Tool.Windows/Images/24/search_index.png create mode 100644 src/SIM.Tool.Windows/Images/32/search_index.png create mode 100644 src/SIM.Tool.Windows/Images/48/search_index.png delete mode 100644 src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs create mode 100644 src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddSolrCoresButton.cs create mode 100644 src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml create mode 100644 src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml.cs diff --git a/src/SIM.Base/SolrStateResolver.cs b/src/SIM.Base/SolrStateResolver.cs index 04e76bea..616d415e 100644 --- a/src/SIM.Base/SolrStateResolver.cs +++ b/src/SIM.Base/SolrStateResolver.cs @@ -10,6 +10,23 @@ namespace SIM { public class SolrStateResolver { + public virtual bool IsSolrAvailable(string solrUrl) + { + try + { + var request = WebRequest.Create(solrUrl) as HttpWebRequest; + request.Method = "HEAD"; + using (var response = request.GetResponse() as HttpWebResponse) + { + return response.StatusCode == HttpStatusCode.OK; + } + } + catch (WebException) + { + return false; + } + } + public virtual SolrState.CurrentState GetServiceState(ServiceControllerWrapper service) { if (service != null) diff --git a/src/SIM.Pipelines/InstallSearchIndexes/CreateIndexDirectoryAction.cs b/src/SIM.Pipelines/InstallSearchIndexes/CreateIndexDirectoryAction.cs new file mode 100644 index 00000000..042d03d1 --- /dev/null +++ b/src/SIM.Pipelines/InstallSearchIndexes/CreateIndexDirectoryAction.cs @@ -0,0 +1,47 @@ +using JetBrains.Annotations; +using SIM.Extensions; +using Sitecore.Diagnostics.Base; + +namespace SIM.Pipelines.InstallSearchIndexes +{ + public class CreateIndexDirectoryAction : InstallSearchIndexesProcessor + { + protected override void Process([NotNull] InstallSearchIndexesArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + foreach (var index in args._AvailableSearchIndexesDictionary) + { + string newCorePath = args.SolrFolder.EnsureEnd(@"\") + index.Value; + CreateIndexDirectory(args.SolrVersion, args.SolrFolder, newCorePath); + } + } + + private void CreateIndexDirectory(string solrVersion, string solrFolder, string newCorePath) + { + string sourcePath = GetSourceConfPath(solrVersion, solrFolder); + FileSystem.FileSystem.Local.Directory.Copy(sourcePath, newCorePath, recursive: true); + } + + private string GetSourceConfPath(string solrVersion, string solrFolder) + { + string confPath = string.Empty; + + if (!string.IsNullOrEmpty(solrVersion) && char.IsDigit(solrVersion[0])) + { + int firstDigit = int.Parse(solrVersion[0].ToString()); + + if (firstDigit >= 7) + { + confPath = solrFolder.EnsureEnd(@"\") + @"\configsets\_default"; + } + else + { + confPath = solrFolder.EnsureEnd(@"\") + @"\configsets\data_driven_schema_configs"; + } + } + + return confPath; + } + } +} diff --git a/src/SIM.Pipelines/InstallSearchIndexes/CreateSolrCoreAction.cs b/src/SIM.Pipelines/InstallSearchIndexes/CreateSolrCoreAction.cs new file mode 100644 index 00000000..950bc691 --- /dev/null +++ b/src/SIM.Pipelines/InstallSearchIndexes/CreateSolrCoreAction.cs @@ -0,0 +1,36 @@ +using JetBrains.Annotations; +using SIM.Extensions; +using Sitecore.Diagnostics.Base; +using System.IO; + +namespace SIM.Pipelines.InstallSearchIndexes +{ + public class CreateSolrCoreAction : InstallSearchIndexesProcessor + { + protected override void Process([NotNull] InstallSearchIndexesArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + foreach (var index in args._AvailableSearchIndexesDictionary) + { + string newCorePath = args.SolrFolder.EnsureEnd(@"\") + index.Value; + + RequestAndGetResponseStream($"{args.SolrUrl}/admin/cores?action=CREATE&name={index.Value}&instanceDir={newCorePath}&config=solrconfig.xml&schema=schema.xml&dataDir=data"); + UpdateCorePropertiesFile(index.Value, newCorePath); + } + } + + private Stream RequestAndGetResponseStream(string url) + { + return WebRequestHelper.RequestAndGetResponse(url).GetResponseStream(); + } + + private void UpdateCorePropertiesFile(string coreName, string newCorePath) + { + string filePath = string.Format(newCorePath.EnsureEnd(@"\") + @"core.properties"); + string newText = @"update.autoCreateFields=false" + "\r\n" + "name=" + coreName; + FileSystem.FileSystem.Local.File.Delete(filePath); + FileSystem.FileSystem.Local.File.WriteAllText(filePath, newText); + } + } +} diff --git a/src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesArgs.cs b/src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesArgs.cs new file mode 100644 index 00000000..6e299a21 --- /dev/null +++ b/src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesArgs.cs @@ -0,0 +1,49 @@ +using JetBrains.Annotations; +using SIM.Instances; +using SIM.Pipelines.Processors; +using Sitecore.Diagnostics.Base; +using System.Collections.Generic; + +namespace SIM.Pipelines.InstallSearchIndexes +{ + public class InstallSearchIndexesArgs : ProcessorArgs + { + [UsedImplicitly] + public string InstanceName + { + get + { + return Instance != null ? Instance.Name : string.Empty; + } + } + + public Dictionary _AvailableSearchIndexesDictionary; + + public string SolrUrl; + + public string SolrVersion; + + public string SolrFolder; + public Instance Instance { get; } + + public string AuthCookies { get; } + + public IDictionary Headers { get; } + + public InstallSearchIndexesArgs([NotNull] Instance instance, [CanBeNull] Dictionary availableSearchIndexesDictionary, [NotNull] string solrUrl, [NotNull] string solrVersion, [NotNull] string solrFolder, [CanBeNull] IDictionary headers = null, [CanBeNull] string cookies = null) + { + Assert.ArgumentNotNull(instance, nameof(instance)); + Assert.ArgumentNotNull(solrUrl, nameof(solrUrl)); + Assert.ArgumentNotNull(solrVersion, nameof(solrVersion)); + Assert.ArgumentNotNull(solrFolder, nameof(solrFolder)); + + SolrUrl = solrUrl; + SolrVersion = solrVersion; + SolrFolder = solrFolder; + _AvailableSearchIndexesDictionary = availableSearchIndexesDictionary; + Instance = instance; + AuthCookies = cookies; + Headers = headers; + } + } +} diff --git a/src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesProcessor.cs b/src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesProcessor.cs new file mode 100644 index 00000000..83b0804a --- /dev/null +++ b/src/SIM.Pipelines/InstallSearchIndexes/InstallSearchIndexesProcessor.cs @@ -0,0 +1,46 @@ +using JetBrains.Annotations; +using SIM.Pipelines.Processors; +using Sitecore.Diagnostics.Base; + +namespace SIM.Pipelines.InstallSearchIndexes +{ + public abstract class InstallSearchIndexesProcessor : Processor + { + public override sealed long EvaluateStepsCount(ProcessorArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + return EvaluateStepsCount((InstallSearchIndexesArgs)args); + } + + public override sealed bool IsRequireProcessing(ProcessorArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + return IsRequireProcessing((InstallSearchIndexesArgs)args); + } + + protected virtual long EvaluateStepsCount([NotNull] InstallSearchIndexesArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + return 1; + } + + protected virtual bool IsRequireProcessing([NotNull] InstallSearchIndexesArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + return true; + } + + protected override void Process(ProcessorArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + Process((InstallSearchIndexesArgs)args); + } + + protected abstract void Process([NotNull] InstallSearchIndexesArgs args); + } +} diff --git a/src/SIM.Pipelines/InstallSearchIndexes/PopulateNewIndexAction.cs b/src/SIM.Pipelines/InstallSearchIndexes/PopulateNewIndexAction.cs new file mode 100644 index 00000000..12488f32 --- /dev/null +++ b/src/SIM.Pipelines/InstallSearchIndexes/PopulateNewIndexAction.cs @@ -0,0 +1,60 @@ +using JetBrains.Annotations; +using SIM.Extensions; +using SIM.Instances; +using Sitecore.Diagnostics.Base; +using System; +using System.Collections.Generic; + +namespace SIM.Pipelines.InstallSearchIndexes +{ + public class PopulateNewIndexAction : InstallSearchIndexesProcessor + { + protected override void Process([NotNull] InstallSearchIndexesArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + foreach (var index in args._AvailableSearchIndexesDictionary) + { + string newCorePath = args.SolrFolder.EnsureEnd(@"\") + index.Value; + PopulateNewIndex(index.Key, args.Instance, args.Headers, args.AuthCookies); + } + } + + private void PopulateNewIndex(string coreID, Instance instance, IDictionary headers, string authCookie) + { + var popUrl = instance.GetUrl(@"/sitecore/admin/PopulateManagedSchema.aspx?indexes=" + coreID); + + try + { + int sitecoreVersion; + + int.TryParse(instance.Product.ShortVersion, out sitecoreVersion); + + if (sitecoreVersion >= 91) + { + if (headers == null) + { + return; + } + var result = WebRequestHelper.DownloadString(popUrl, headers: headers).Trim(); + + } + else if (sitecoreVersion == 90) + { + string instanceUri = instance.GetUrl(); + + if (string.IsNullOrEmpty(authCookie)) + { + return; + } + var result = WebRequestHelper.DownloadString(popUrl, cookies: authCookie).Trim(); + } + } + catch (Exception ex) + { + return; + } + } + + } +} diff --git a/src/SIM.Pipelines/InstallSearchIndexes/UpdateManagedSchemaAction.cs b/src/SIM.Pipelines/InstallSearchIndexes/UpdateManagedSchemaAction.cs new file mode 100644 index 00000000..600ea02f --- /dev/null +++ b/src/SIM.Pipelines/InstallSearchIndexes/UpdateManagedSchemaAction.cs @@ -0,0 +1,49 @@ +using JetBrains.Annotations; +using SIM.Extensions; +using Sitecore.Diagnostics.Base; +using System.Xml; + +namespace SIM.Pipelines.InstallSearchIndexes +{ + public class UpdateManagedSchemaAction : InstallSearchIndexesProcessor + { + protected override void Process([NotNull] InstallSearchIndexesArgs args) + { + Assert.ArgumentNotNull(args, nameof(args)); + + foreach (var index in args._AvailableSearchIndexesDictionary) + { + string newCorePath = args.SolrFolder.EnsureEnd(@"\") + index.Value; + + UpdateManagedSchemaFile(newCorePath); + } + } + + private void UpdateManagedSchemaFile(string newCorePath) + { + XmlDocument doc = new XmlDocument(); + doc.Load(newCorePath.EnsureEnd(@"\") + @"conf\managed-schema"); + XmlElement newField = doc.CreateElement("field"); + newField.SetAttribute("name", "_uniqueid"); + newField.SetAttribute("type", "string"); + newField.SetAttribute("indexed", "true"); + newField.SetAttribute("required", "true"); + newField.SetAttribute("stored", "true"); + XmlNode schemaNode = doc.SelectSingleNode("/schema"); + + if (schemaNode != null) + { + schemaNode.AppendChild(newField); + } + + XmlNode uniqueKeyNode = doc.SelectSingleNode("/schema/uniqueKey"); + if (uniqueKeyNode != null) + + { + uniqueKeyNode.InnerText = "_uniqueid"; + } + + doc.Save(newCorePath.EnsureEnd(@"\") + @"conf\managed-schema"); + } + } +} diff --git a/src/SIM.Pipelines/PipelinesConfig.cs b/src/SIM.Pipelines/PipelinesConfig.cs index 7173ae0c..d80be067 100644 --- a/src/SIM.Pipelines/PipelinesConfig.cs +++ b/src/SIM.Pipelines/PipelinesConfig.cs @@ -237,6 +237,12 @@ public static class PipelinesConfig + + + + + + diff --git a/src/SIM.Pipelines/SIM.Pipelines.csproj b/src/SIM.Pipelines/SIM.Pipelines.csproj index 1723277e..cfac5117 100644 --- a/src/SIM.Pipelines/SIM.Pipelines.csproj +++ b/src/SIM.Pipelines/SIM.Pipelines.csproj @@ -108,6 +108,12 @@ + + + + + + diff --git a/src/SIM.Tool.Base/Pipelines/InstallSearchIndexesWizardArgs.cs b/src/SIM.Tool.Base/Pipelines/InstallSearchIndexesWizardArgs.cs new file mode 100644 index 00000000..bfd56fa0 --- /dev/null +++ b/src/SIM.Tool.Base/Pipelines/InstallSearchIndexesWizardArgs.cs @@ -0,0 +1,82 @@ +using JetBrains.Annotations; +using SIM.Extensions; +using SIM.Instances; +using SIM.Pipelines.InstallModules; +using SIM.Pipelines.InstallSearchIndexes; +using SIM.Pipelines.Processors; +using SIM.Tool.Base.Wizards; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace SIM.Tool.Base.Pipelines +{ + [UsedImplicitly] + public class InstallSearchIndexesWizardArgs : WizardArgs + { + [UsedImplicitly] + public string InstanceName + { + get + { + return Instance != null ? Instance.Name : string.Empty; + } + } + + public List _AvailableSearchIndexesList; + + public Dictionary _AvailableSearchIndexesDictionary; + + public Instance Instance { get; } + + public string SolrUrl; + + public string SolrVersion; + + public string SolrFolder; + + public IDictionary Headers { get; } + + public string AuthCookies { get; } + + public InstallSearchIndexesWizardArgs(Instance instance, Dictionary availableSearchIndexesDictionary, string solrUrl, string solrVersion, string solrFolder, IDictionary headers = null, string cookies = null) + { + SolrUrl = solrUrl; + SolrVersion = solrVersion; + SolrFolder = solrFolder; + _AvailableSearchIndexesList = new List(); + + foreach (var availableIndex in availableSearchIndexesDictionary) + { + _AvailableSearchIndexesList.Add(availableIndex.Value); + } + _AvailableSearchIndexesDictionary = availableSearchIndexesDictionary; + Instance = instance; + AuthCookies = cookies; + Headers = headers; + } + + public override ProcessorArgs ToProcessorArgs() + { + Dictionary newAvailableSearchIndexesDictionary = new Dictionary(); + + foreach (var index in _AvailableSearchIndexesDictionary) + { + foreach (var availableSearchIndex in _AvailableSearchIndexesList) + { + if (availableSearchIndex == index.Value) + { + newAvailableSearchIndexesDictionary.Add(index.Key, index.Value); + } + } + } + + return new InstallSearchIndexesArgs(Instance, newAvailableSearchIndexesDictionary, SolrUrl, SolrVersion, SolrFolder, Headers, AuthCookies); + } + + } +} diff --git a/src/SIM.Tool.Base/SIM.Tool.Base.csproj b/src/SIM.Tool.Base/SIM.Tool.Base.csproj index 26fbb9ea..7792dd54 100644 --- a/src/SIM.Tool.Base/SIM.Tool.Base.csproj +++ b/src/SIM.Tool.Base/SIM.Tool.Base.csproj @@ -82,6 +82,7 @@ + diff --git a/src/SIM.Tool.Windows/Images/16/search_index.png b/src/SIM.Tool.Windows/Images/16/search_index.png new file mode 100644 index 0000000000000000000000000000000000000000..1a9fbc79b461a72eeff74d1f468b752d9813c0da GIT binary patch literal 899 zcmV-}1AP36P)Px&JxN4CR5(v%lWj~}WfaGMPg`gUY)CI;umME^lmcU&G9t!^A7(-=$)=$=Toy9t z``GxP;FfGeJ~&;XF_T1{83|d&;*^mtVxlf4nz+Q5F9>6T>qJ)Imfiv_AOo@YntM?v z@gz^qd6IK}`JeosM{qa9;g%P>{SE%++`N3#OgOAv?(e%cHyeAjr>AG-KYbfYq2K&| zzx`wFWO6fY9D1w>ha{0?Ny6dCFcgGBlN1*h3(>Hz;lVdg zy>;!`H@;Mwyq>J2Bn!3o74Xs3>&VIiH-cf_Z`;i`Uw^^ld!H~A*zI3R`o6Sanvw*3oXH6#@bMuQR(HPHpi}~vFPw@GC#tH?_dx_1* zC@n1&!t3=~ySuwrnmVrhQQ*u;)&Xse9^SojgN4OqM#p}mw{s7{TR|jAT33+aKv5Lj zZnrR8IC!Y}^qF_M+MjA7-&tj4Ar!kyjw{kla;_SI|JWy4IEX&-QxJ~ED6Gnd|5}~4^;w}J4 z8yFZ^oSL5E`p5`ovzgp&+sKq8e*Ps$nX80&JkCUDk|T#-VrgmVe*lJuhqdhNY$m5B ziAEKKFrmK-9d_|jAG>yXSX)~IlL=2{CDql{8x$}!G^FL_IjM002ovPDHLkV1o9qv?Krk literal 0 HcmV?d00001 diff --git a/src/SIM.Tool.Windows/Images/24/search_index.png b/src/SIM.Tool.Windows/Images/24/search_index.png new file mode 100644 index 0000000000000000000000000000000000000000..8076119cc639365a02d5e89a4a511e582a77c8cd GIT binary patch literal 1678 zcmV;9266d`P)Px*NJ&INR7gv8l?zZ*RT#(rcOS6t1pxth?9xLUp)!(22Q^a1EX+uul?4NLc{q-x zsDsv;`HCH!v4^6mqb1`)XpV0zZP0Y4hgzYdHD;E&i>)mCfMs{t*S)tncL6oGGxN=P z+ExXN2R8G_dV7tqJ8s!Yt(}e zG@3cN1usqixx8#X)nm8Ae6J7Qfe_M?WJpeogH$TPs&`lRk4#Eh$m0nS3WX3120_#G zL*rmD$n4#_cRv7j7*MP!p0#1!hT}29SS;Lh8ung4QW6yq@Of~$eQ>#bSgOfI$&BaF z(rQBKJS~VifF0f=dw&SMUcbs@GBt95va&KoO-*%Q;>b}bsz1zVW{%@!Kb{PsfDeBl zjKA+XVRL$L<%SjN6e+gWzlO$5MtrblZPdt66a~G$%3v~?8aRNis^ZUvjg3zfEZi4< zC4Y>6e0GM6VSzWN=YY?r@KMY6u(>?wad_~j*$(}zY?Kzh0Ar&OQ>GL^t;$43dO8PV zSr!zk^)G@UPBbC?y2B|UjL>9TmG zOd=EtQ2FXJ;PZejUtL0$TzwvFUp5tv9xFy9#B&bG&a>26T+ie2IR&k) ztqoL(X6~|&H-EZ$=92yN=&WSNXmye_FxF)c>9fKK!*a@di**9AqH-@7k&L+{B^q< zruS#!rwcz|?AWoxyB~rGg+eS?pfemea3GRJEv+VY!i0RxdGDAzJ#_?|nUst>5A6OLsk4suUSfP%+~vh+_r#;+x+QW>|Q=1Gw0E6UR2q!L8f3;q`ft znvxPJH8zq(nHiagiHSi)MTOzep+gY>0BYU(wV{>utN7d7&f&y`yLd7y6=G2gNYOAX z1Fz4I%UA!#fsL;tPASJv7cZc-Z9i7jEqOpeCI^X)jYWBRx#8&1qr(6c6&1xz%%9+V zXYmrMr^k-nM>}!m7Yi4f)C37?i=M^g@nhg{INj4LiOCnge! zP+D4QXm4-740q%-=4;;J9iKchY<(_kvwuFGSbr!r&QwP z=?>`LDu>78;T&46R{Ya#!=(I)n4CWeVzHR~-=YGDv_(dvahucWbzTnI?| ziA5qvq!JuCeiBn(oPvJ0n{#M3n?e3xnQ9dZXTFT`^7+vL6%`dVJ9g~YNt~K3UECeu zaycLQYm&q4IC~C>BjQ1a!%!-fu-R-FpO=Sw-QC!|YgcrDR;#VqvuF3tKp?hbycg|+uJ{U=+Xxu5{tzNd3kx;X_}5<7)C(Tv=D%hWmy5svV3AgCr(im1AwL| zD$L{Yh=nMM3JC;);MJ>F7rR_8+kXLMPO6I-aWwRt2S6}r53bVy!h=R&L^3h5P7cxk YFZJy;PfH)C-v9sr07*qoM6N<$f&}^;;s5{u literal 0 HcmV?d00001 diff --git a/src/SIM.Tool.Windows/Images/32/search_index.png b/src/SIM.Tool.Windows/Images/32/search_index.png new file mode 100644 index 0000000000000000000000000000000000000000..58b1295a80e887593ce13eacdac4454ae747e669 GIT binary patch literal 2466 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 literal 0 HcmV?d00001 diff --git a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs deleted file mode 100644 index 61febe63..00000000 --- a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddIndexesButton.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Newtonsoft.Json.Linq; -using SIM.Core; -using SIM.Instances; -using SIM.Pipelines.Install.Modules; -using SIM.Tool.Base.Wizards; -using Sitecore.Diagnostics.Base; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Xml; -using Newtonsoft.Json; -using System.Data.SqlTypes; -using System.Net.Http; -using System.Net.NetworkInformation; - - -namespace SIM.Tool.Windows.MainWindowComponents.Buttons -{ - public class AddIndexesButton : InstanceOnlyButton - { - public override void OnClick(Window mainWindow, Instance instance) - { - if (instance != null) - { - XmlDocument sitecoreWebResultConfig = instance.GetWebResultConfig(); - XmlNodeList solrIndexes = GetSolrIndexNodesFrom(sitecoreWebResultConfig); - string solrUrl = GetUrlFrom(sitecoreWebResultConfig); - string home = GetSolrHome(solrUrl); - XmlNodeList existingSolrCores = GetExistingCoresFromSolr(solrUrl); - - foreach (XmlElement node in solrIndexes) - { - string coreName = GetCoreName(node); - bool itemMatched = false; - - foreach (XmlElement existingSolrnode in existingSolrCores) - { - string existingCoreName = existingSolrnode["name"].InnerText; - if (coreName == existingCoreName) - { - itemMatched = true; - break; - } - } - - if (!itemMatched) - { - CreateSolrCore(solrUrl, coreName); - } - } - } - } - - private void CreateSolrCore(string solrUrl, string coreName) - { - string test = coreName; - } - - private XmlNodeList GetExistingCoresFromSolr(string solrUrl) - { - var solrInfoUrl = $"{solrUrl}/admin/cores?action=STATUS&wt=json"; - //Stream response = RequestAndGetResponseStream(url); - //string responseAsString = GetStringFromStream(response); - //string xmlString = ReturnXml(responseAsString); - //var doc = XmlDocumentEx.LoadXml(xmlString); - var doc = GetXmlDocumenFromSolrResponse(solrInfoUrl); - XmlNodeList solrIndexes = doc.SelectNodes("//status/*"); - return solrIndexes; - } - - private static string GetCoreName(XmlElement node) - { - var coreElement = node.SelectSingleNode("param[@desc='core']") as XmlElement; - string id = node.Attributes["id"].InnerText; - coreElement = Assert.IsNotNull(coreElement, "param[@desc='core'] not found in Solr configuration file"); - string coreName = coreElement.InnerText.Replace("$(id)", id); - return coreName; - } - - private static XmlNodeList GetSolrIndexNodesFrom(XmlDocument sitecoreConfig) - { - return sitecoreConfig.SelectNodes( - "//sitecore/contentSearch/configuration/indexes/index[@type='Sitecore.ContentSearch.SolrProvider.SolrSearchIndex, Sitecore.ContentSearch.SolrProvider']"); - } - - private static string GetUrlFrom(XmlDocument sitecoreConfig) - { - string connectionStringName = "solr.search"; - XmlNode connectionStringNode = sitecoreConfig.SelectSingleNode("//connectionStrings/add[@name='" + connectionStringName + "']"); - Assert.IsNotNull(connectionStringNode, "ConnectionString with name '" + connectionStringName + "' not found."); - return connectionStringNode.Attributes["connectionString"].Value; - } - - private string GetSolrHome(string url) - { - string solrInfoUrl = $"{url}/admin/info/system"; - var doc = GetXmlDocumenFromSolrResponse(solrInfoUrl); - return ReturnSolrHome(doc); - } - - private XmlDocumentEx GetXmlDocumenFromSolrResponse(string solrInfoUrl) - { - Stream response = RequestAndGetResponseStream(solrInfoUrl); - string responseAsString = GetStringFromStream(response); - string xmlString = ReturnXml(responseAsString); - var doc = XmlDocumentEx.LoadXml(xmlString); - return doc; - } - - private string ReturnSolrHome(XmlDocumentEx xml) - { - XmlNode solrHomeNode = xml.SelectSingleNode("/response/solr_home"); - Assert.IsNotNull(solrHomeNode, "solr_home element should not be null"); - string solrHomeValue = solrHomeNode.InnerText; - return solrHomeValue.Replace("\\\\", "\\"); - } - - private Stream RequestAndGetResponseStream(string url) - { - return WebRequestHelper.RequestAndGetResponse(url).GetResponseStream(); - } - - private string GetStringFromStream(Stream stream) - { - using (var reader = new StreamReader(stream)) - { - return reader.ReadToEnd(); - } - } - - private string NormalizeXml(XmlDocumentEx xml) - { - string outerXml = xml.OuterXml; - string formatted = XmlDocumentEx.Normalize(outerXml); - Regex r = new Regex(@"^<\?.*\?>"); - string corrected = r.Replace(formatted, @""); //Solr requires UTF-8. - return corrected; - } - - private string ReturnXml(string jsonObject) - { - string xmlString = JsonConvert.DeserializeXmlNode(jsonObject, "response").OuterXml; - return xmlString; - } - } -} diff --git a/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddSolrCoresButton.cs b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddSolrCoresButton.cs new file mode 100644 index 00000000..7d5f163b --- /dev/null +++ b/src/SIM.Tool.Windows/MainWindowComponents/Buttons/AddSolrCoresButton.cs @@ -0,0 +1,170 @@ +using SIM.Instances; +using SIM.Tool.Base.Wizards; +using Sitecore.Diagnostics.Base; +using System.Collections.Generic; +using System.IO; +using System.Windows; +using System.Xml; +using Newtonsoft.Json; +using SIM.Tool.Windows.MainWindowComponents.Helpers; +using SIM.Tool.Base.Pipelines; +using SIM.Tool.Base; + +namespace SIM.Tool.Windows.MainWindowComponents.Buttons +{ + public class AddSolrCoresButton : InstanceOnlyButton + { + public override void OnClick(Window mainWindow, Instance instance) + { + if (instance != null) + { + + SolrStateResolver solrStateResolver = new SolrStateResolver(); + ButtonAuthenticationHelper buttonAuthenticationHelper = new ButtonAuthenticationHelper(); + XmlDocument sitecoreWebResultConfig = instance.GetWebResultConfig(); + string solrUrl = GetUrlFrom(sitecoreWebResultConfig); + + if (!solrStateResolver.IsSolrAvailable(solrUrl)) + { + WindowHelper.ShowMessage($"Failed to access Solr at the following URL: {solrUrl}.\r\n Solr is not available.\r\nPlease make sure Solr is running and accessible.", + messageBoxImage: MessageBoxImage.Warning, + messageBoxButton: MessageBoxButton.OK); + + return; + } + + string solrAttribute = "solr_home"; + string solrFolder = solrStateResolver.GetSeparateSolrAttribute(solrUrl, solrAttribute); + string solrVersion = solrStateResolver.GetVersion(solrUrl); + XmlNodeList existingSolrCores = GetExistingCoresFromSolr(solrUrl); + Dictionary indexDataDictionary = GetindexDataListFromConfig(sitecoreWebResultConfig); + Dictionary availableSearchIndexesDictionary = new Dictionary(); + + Dictionary headers = null; + string authCookie = null; + + int.TryParse(instance.Product.ShortVersion, out int sitecoreVersion); + + if (sitecoreVersion >= 91) + { + headers = buttonAuthenticationHelper.GetIdServerAuthToken(mainWindow, instance); + + if (headers == null) + { + return; + } + } + else if (sitecoreVersion == 90) + { + string instanceUri = instance.GetUrl(); + + authCookie = buttonAuthenticationHelper.GetAuthCookie(mainWindow, instance); + + if (string.IsNullOrEmpty(authCookie)) + { + return; + } + } + + foreach (var indexData in indexDataDictionary) + { + string coreName; + string coreID; + + if (!string.IsNullOrEmpty(indexData.Value) && indexData.Value != "$(id)") + { + coreID = indexData.Key; + coreName = indexData.Value; + } + else + { + coreID = indexData.Key; + coreName = indexData.Key; + } + + bool itemMatched = false; + + foreach (XmlElement existingSolrnode in existingSolrCores) + { + string existingCoreName = existingSolrnode["name"].InnerText; + if (coreName == existingCoreName) + { + itemMatched = true; + break; + } + } + + if (!itemMatched) + { + availableSearchIndexesDictionary.Add(coreID, coreName); + } + } + + var id = MainWindowHelper.GetListItemID(instance.ID); + WizardPipelineManager.Start("installSearchIndexes", mainWindow, null, null, ignore => MainWindowHelper.MakeInstanceSelected(id), () => new InstallSearchIndexesWizardArgs(instance, availableSearchIndexesDictionary, solrUrl, solrVersion, solrFolder, headers, authCookie)); + } + } + + private Dictionary GetindexDataListFromConfig(XmlDocument sitecoreConfig) + { + Dictionary indexData = new Dictionary(); + + foreach (XmlNode indexNode in sitecoreConfig.SelectNodes("//sitecore/contentSearch/configuration/indexes/index")) + { + string indexId = indexNode.Attributes["id"]?.Value; + string coreName = indexNode.SelectSingleNode("param[@desc='core']")?.InnerText; + + if (!string.IsNullOrEmpty(indexId) && !string.IsNullOrEmpty(coreName)) + { + indexData.Add(indexId, coreName); + } + } + + return indexData; + } + + private XmlNodeList GetExistingCoresFromSolr(string solrUrl) + { + var solrInfoUrl = $"{solrUrl}/admin/cores?action=STATUS&wt=json"; + var doc = GetXmlDocumenFromSolrResponse(solrInfoUrl); + XmlNodeList solrIndexes = doc.SelectNodes("//status/*"); + return solrIndexes; + } + + private static string GetUrlFrom(XmlDocument sitecoreConfig) + { + string connectionStringName = "solr.search"; + XmlNode connectionStringNode = sitecoreConfig.SelectSingleNode("//connectionStrings/add[@name='" + connectionStringName + "']"); + Assert.IsNotNull(connectionStringNode, "ConnectionString with name '" + connectionStringName + "' not found."); + return connectionStringNode.Attributes["connectionString"].Value; + } + + private XmlDocumentEx GetXmlDocumenFromSolrResponse(string solrInfoUrl) + { + Stream response = RequestAndGetResponseStream(solrInfoUrl); + string responseAsString = GetStringFromStream(response); + string xmlString = ReturnXml(responseAsString); + var doc = XmlDocumentEx.LoadXml(xmlString); + return doc; + } + + private Stream RequestAndGetResponseStream(string url) + { + return WebRequestHelper.RequestAndGetResponse(url).GetResponseStream(); + } + + private string GetStringFromStream(Stream stream) + { + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + + private string ReturnXml(string jsonObject) + { + string xmlString = JsonConvert.DeserializeXmlNode(jsonObject, "response").OuterXml; + return xmlString; + } + } +} diff --git a/src/SIM.Tool.Windows/MainWindowData.cs b/src/SIM.Tool.Windows/MainWindowData.cs index 521f4a42..e4f633c5 100644 --- a/src/SIM.Tool.Windows/MainWindowData.cs +++ b/src/SIM.Tool.Windows/MainWindowData.cs @@ -693,9 +693,9 @@ private static ButtonDefinition GetPatchButton() }, new ButtonDefinition { - Label = "Add Indexes", - Image = "/Images/$lg/install.png, SIM.Tool.Windows", - Handler = new AddIndexesButton() + Label = "Add Solr Cores", + Image = "/Images/$lg/search_index.png, SIM.Tool.Windows", + Handler = new AddSolrCoresButton() }, } }, @@ -1164,6 +1164,7 @@ private static GroupDefinition GetManageGroupDefinition() new ButtonDefinition { Label = "Restore", Image = "/Images/$sm/box_out.png, SIM.Tool.Windows", Handler = new RestoreInstanceButton() }, new ButtonDefinition { Handler = new ExportInstanceButton() }, new ButtonDefinition { Label = "Export", Image = "/Images/$sm/download.png, SIM.Tool.Windows", Handler = new ExportInstanceButton() }, + new ButtonDefinition { Label = "Add Solr cores", Image = "/Images/$sm/search_index.png, SIM.Tool.Windows", Handler = new AddSolrCoresButton() }, new ButtonDefinition { Handler = new InstallModulesButton() }, new ButtonDefinition { Label = "Install packages", Image = "/Images/$sm/install.png, SIM.Tool.Windows", Handler = new InstallModulesButton() }, new ButtonDefinition { Handler = new InstallModulesButton() }, diff --git a/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj b/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj index 298b0ed8..a2816e8a 100644 --- a/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj +++ b/src/SIM.Tool.Windows/SIM.Tool.Windows.csproj @@ -156,7 +156,7 @@ - + @@ -302,6 +302,9 @@ SelectModules.xaml + + AvailableSearchIndexes.xaml + @@ -661,6 +664,10 @@ + + + + SettingsSingleFileGenerator Settings.Designer.cs @@ -751,6 +758,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml b/src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml new file mode 100644 index 00000000..358b9493 --- /dev/null +++ b/src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml @@ -0,0 +1,18 @@ + + + + + + + + + + + diff --git a/src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml.cs b/src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml.cs new file mode 100644 index 00000000..a8d65db6 --- /dev/null +++ b/src/SIM.Tool.Windows/UserControls/Install/SearchIndexes/AvailableSearchIndexes.xaml.cs @@ -0,0 +1,68 @@ +using SIM.Tool.Base.Pipelines; +using SIM.Tool.Base.Wizards; +using SIM.Tool.Windows.UserControls.MultipleDeletion; +using System.Collections.Generic; +using System.Linq; +using System.Windows; + +namespace SIM.Tool.Windows.UserControls.Install.SearchIndexes +{ + public partial class AvailableSearchIndexes : IWizardStep, IFlowControl + { + private List CoreNamesCheckBoxItems; + + public AvailableSearchIndexes() + { + InitializeComponent(); + } + + public void InitializeStep(WizardArgs wizardArgs) + { + var args = (InstallSearchIndexesWizardArgs)wizardArgs; + CoreNamesCheckBoxItems = new List(); + + foreach (var availableSearchIndex in args._AvailableSearchIndexesList) + { + CoreNamesCheckBoxItems.Add(new EnvironmentCheckBox(availableSearchIndex)); + } + + if (args._AvailableSearchIndexesList != null && args._AvailableSearchIndexesList.Count > 0) + { + foreach (string availableIndexes in args._AvailableSearchIndexesList) + { + CoreNamesCheckBoxItems.Where(item => item.Name == availableIndexes).FirstOrDefault().IsChecked = true; + } + } + + SearchIndexesListBox.DataContext = CoreNamesCheckBoxItems; + } + + public bool OnMovingBack(WizardArgs wizardArgs) + { + return true; + } + + public bool OnMovingNext(WizardArgs wizardArgs) + { + if (CoreNamesCheckBoxItems != null && CoreNamesCheckBoxItems.Where(item => item.IsChecked).Any()) + { + return true; + } + + MessageBox.Show("You haven't selected any of the Solr cores", "Install Solr cores", MessageBoxButton.OK, MessageBoxImage.Warning); + return false; + } + + public bool SaveChanges(WizardArgs wizardArgs) + { + var args = (InstallSearchIndexesWizardArgs)wizardArgs; + + if (CoreNamesCheckBoxItems != null && CoreNamesCheckBoxItems.Where(item => item.IsChecked).Any()) + { + args._AvailableSearchIndexesList = CoreNamesCheckBoxItems.Where(item => item.IsChecked).Select(item => item.Name).ToList(); + } + + return true; + } + } +} diff --git a/src/SIM.Tool.Windows/WizardPipelinesConfig.cs b/src/SIM.Tool.Windows/WizardPipelinesConfig.cs index b40f7789..120ebdae 100644 --- a/src/SIM.Tool.Windows/WizardPipelinesConfig.cs +++ b/src/SIM.Tool.Windows/WizardPipelinesConfig.cs @@ -325,8 +325,18 @@ Note that due to the large size of each installation package the whole download method=""OpenVisualStudio"" /> - + + + + + + +