From f8345f261fee2a2c7168d42369938b1b38f3d607 Mon Sep 17 00:00:00 2001 From: flo7842 <55089793+flo7842@users.noreply.github.com> Date: Tue, 20 Jun 2023 09:37:02 +0200 Subject: [PATCH] Dev (#3) --- .gitignore | 4 + README.md | 2 - edc-client-dotnet-test/CommonBase.cs | 67 ++++ .../EdcClientSingletonTest.cs | 102 +++++ edc-client-dotnet-test/Usings.cs | 1 + .../edc-client-dotnet-test.csproj | 23 ++ .../internalImpl/Constants.cs | 7 + .../internalImpl/EdcClientImplTest.cs | 76 ++++ .../internalImpl/http/HttpClientDotnetTest.cs | 22 ++ .../internalImpl/io/HttpReaderImplTest.cs | 58 +++ .../model/ClientConfigurationImplTest.cs | 90 +++++ .../internalImpl/model/I18NContentImplTest.cs | 31 ++ .../util/TranslationUtilImplTest.cs | 90 +++++ .../internalImpl/util/UrlUtilImplTest.cs | 48 +++ edc-client-dotnet.csproj | 15 + edc-client-dotnet.sln | 37 ++ edc-client-dotnet/EdcClientSingleton.cs | 116 ++++++ edc-client-dotnet/IDocumentationManager.cs | 35 ++ edc-client-dotnet/IEdcClient.cs | 128 +++++++ edc-client-dotnet/IInformationManager.cs | 28 ++ edc-client-dotnet/ITranslationManager.cs | 55 +++ edc-client-dotnet/Injection/Startup.cs | 44 +++ LICENSE => edc-client-dotnet/LICENSE | 0 edc-client-dotnet/NLog.config | 22 ++ edc-client-dotnet/README.md | 17 + edc-client-dotnet/edc-client-dotnet.csproj | 29 ++ .../edc-client-dotnet.csproj.user | 4 + .../factory/IContextItemFactory.cs | 9 + .../factory/IDocumentationItemFactory.cs | 9 + edc-client-dotnet/factory/II18NFactory.cs | 9 + .../factory/IInformationFactory.cs | 9 + .../internalImpl/DocumentationManagerImpl.cs | 68 ++++ .../internalImpl/EdcClientImpl.cs | 136 +++++++ .../internalImpl/InformationManagerImpl.cs | 39 ++ .../internalImpl/TranslationConstants.cs | 78 ++++ .../internalImpl/TranslationManagerImpl.cs | 96 +++++ .../factory/ContextItemFactory.cs | 14 + .../factory/DocumentationItemFactory.cs | 14 + .../internalImpl/factory/I18NFactory.cs | 14 + .../factory/InformationFactory.cs | 14 + .../internalImpl/http/Error4xxException.cs | 7 + .../internalImpl/http/HttpClientDotnet.cs | 39 ++ .../internalImpl/io/HttpReaderImpl.cs | 353 ++++++++++++++++++ .../model/ClientConfigurationImpl.cs | 58 +++ .../internalImpl/model/ContextItemImpl.cs | 31 ++ .../model/DocumentationItemImpl.cs | 87 +++++ .../internalImpl/model/I18NContentImpl.cs | 29 ++ .../internalImpl/model/InformationImpl.cs | 25 ++ .../internalImpl/model/ObjectIdImpl.cs | 15 + .../internalImpl/util/KeyUtilImpl.cs | 18 + .../internalImpl/util/TranslationUtilImpl.cs | 40 ++ .../internalImpl/util/UrlUtilImpl.cs | 35 ++ edc-client-dotnet/io/IEdcReader.cs | 34 ++ .../model/DocumentationItemType.cs | 30 ++ edc-client-dotnet/model/I18NTranslation.cs | 55 +++ .../model/IClientConfiguration.cs | 43 +++ edc-client-dotnet/model/IContextItem.cs | 27 ++ edc-client-dotnet/model/IDocumentationItem.cs | 85 +++++ edc-client-dotnet/model/II18NContent.cs | 24 ++ edc-client-dotnet/model/IInformation.cs | 10 + edc-client-dotnet/model/IObjectId.cs | 7 + .../model/InvalidUrlException.cs | 8 + edc-client-dotnet/utils/IKeyUtil.cs | 23 ++ edc-client-dotnet/utils/ITranslationUtil.cs | 30 ++ edc-client-dotnet/utils/IUrlUtil.cs | 41 ++ .../utils/ParseEnumDescription.cs | 22 ++ 66 files changed, 2834 insertions(+), 2 deletions(-) create mode 100644 .gitignore delete mode 100644 README.md create mode 100644 edc-client-dotnet-test/CommonBase.cs create mode 100644 edc-client-dotnet-test/EdcClientSingletonTest.cs create mode 100644 edc-client-dotnet-test/Usings.cs create mode 100644 edc-client-dotnet-test/edc-client-dotnet-test.csproj create mode 100644 edc-client-dotnet-test/internalImpl/Constants.cs create mode 100644 edc-client-dotnet-test/internalImpl/EdcClientImplTest.cs create mode 100644 edc-client-dotnet-test/internalImpl/http/HttpClientDotnetTest.cs create mode 100644 edc-client-dotnet-test/internalImpl/io/HttpReaderImplTest.cs create mode 100644 edc-client-dotnet-test/internalImpl/model/ClientConfigurationImplTest.cs create mode 100644 edc-client-dotnet-test/internalImpl/model/I18NContentImplTest.cs create mode 100644 edc-client-dotnet-test/internalImpl/util/TranslationUtilImplTest.cs create mode 100644 edc-client-dotnet-test/internalImpl/util/UrlUtilImplTest.cs create mode 100644 edc-client-dotnet.csproj create mode 100644 edc-client-dotnet.sln create mode 100644 edc-client-dotnet/EdcClientSingleton.cs create mode 100644 edc-client-dotnet/IDocumentationManager.cs create mode 100644 edc-client-dotnet/IEdcClient.cs create mode 100644 edc-client-dotnet/IInformationManager.cs create mode 100644 edc-client-dotnet/ITranslationManager.cs create mode 100644 edc-client-dotnet/Injection/Startup.cs rename LICENSE => edc-client-dotnet/LICENSE (100%) create mode 100644 edc-client-dotnet/NLog.config create mode 100644 edc-client-dotnet/README.md create mode 100644 edc-client-dotnet/edc-client-dotnet.csproj create mode 100644 edc-client-dotnet/edc-client-dotnet.csproj.user create mode 100644 edc-client-dotnet/factory/IContextItemFactory.cs create mode 100644 edc-client-dotnet/factory/IDocumentationItemFactory.cs create mode 100644 edc-client-dotnet/factory/II18NFactory.cs create mode 100644 edc-client-dotnet/factory/IInformationFactory.cs create mode 100644 edc-client-dotnet/internalImpl/DocumentationManagerImpl.cs create mode 100644 edc-client-dotnet/internalImpl/EdcClientImpl.cs create mode 100644 edc-client-dotnet/internalImpl/InformationManagerImpl.cs create mode 100644 edc-client-dotnet/internalImpl/TranslationConstants.cs create mode 100644 edc-client-dotnet/internalImpl/TranslationManagerImpl.cs create mode 100644 edc-client-dotnet/internalImpl/factory/ContextItemFactory.cs create mode 100644 edc-client-dotnet/internalImpl/factory/DocumentationItemFactory.cs create mode 100644 edc-client-dotnet/internalImpl/factory/I18NFactory.cs create mode 100644 edc-client-dotnet/internalImpl/factory/InformationFactory.cs create mode 100644 edc-client-dotnet/internalImpl/http/Error4xxException.cs create mode 100644 edc-client-dotnet/internalImpl/http/HttpClientDotnet.cs create mode 100644 edc-client-dotnet/internalImpl/io/HttpReaderImpl.cs create mode 100644 edc-client-dotnet/internalImpl/model/ClientConfigurationImpl.cs create mode 100644 edc-client-dotnet/internalImpl/model/ContextItemImpl.cs create mode 100644 edc-client-dotnet/internalImpl/model/DocumentationItemImpl.cs create mode 100644 edc-client-dotnet/internalImpl/model/I18NContentImpl.cs create mode 100644 edc-client-dotnet/internalImpl/model/InformationImpl.cs create mode 100644 edc-client-dotnet/internalImpl/model/ObjectIdImpl.cs create mode 100644 edc-client-dotnet/internalImpl/util/KeyUtilImpl.cs create mode 100644 edc-client-dotnet/internalImpl/util/TranslationUtilImpl.cs create mode 100644 edc-client-dotnet/internalImpl/util/UrlUtilImpl.cs create mode 100644 edc-client-dotnet/io/IEdcReader.cs create mode 100644 edc-client-dotnet/model/DocumentationItemType.cs create mode 100644 edc-client-dotnet/model/I18NTranslation.cs create mode 100644 edc-client-dotnet/model/IClientConfiguration.cs create mode 100644 edc-client-dotnet/model/IContextItem.cs create mode 100644 edc-client-dotnet/model/IDocumentationItem.cs create mode 100644 edc-client-dotnet/model/II18NContent.cs create mode 100644 edc-client-dotnet/model/IInformation.cs create mode 100644 edc-client-dotnet/model/IObjectId.cs create mode 100644 edc-client-dotnet/model/InvalidUrlException.cs create mode 100644 edc-client-dotnet/utils/IKeyUtil.cs create mode 100644 edc-client-dotnet/utils/ITranslationUtil.cs create mode 100644 edc-client-dotnet/utils/IUrlUtil.cs create mode 100644 edc-client-dotnet/utils/ParseEnumDescription.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b0dbcee --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +obj/ +bin/ +.vs/ \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 15e4fbf..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# edc-client-dotnet -The edc client to use the edc HTML5 publication. diff --git a/edc-client-dotnet-test/CommonBase.cs b/edc-client-dotnet-test/CommonBase.cs new file mode 100644 index 0000000..87ec544 --- /dev/null +++ b/edc-client-dotnet-test/CommonBase.cs @@ -0,0 +1,67 @@ +using edcClientDotnet; +using edcClientDotnet.Injection; +using edcClientDotnet.internalImpl; +using edcClientDotnet.internalImpl.http; +using edcClientDotnet.internalImpl.io; +using edcClientDotnet.internalImpl.model; +using edcClientDotnet.internalImpl.util; +using edcClientDotnet.io; +using edcClientDotnet.model; +using edcClientDotnet.utils; +using edcClientDotnetTest.internalImpl; +using edcClientDotnet.internalImpl.factory; +using edcClientDotnet.factory; + +namespace edcClientDotnetTest +{ + public abstract class CommonBase + { + private IEdcReader? _edcReader; + + protected HttpClientDotnet CreateHttpClient() { return new HttpClientDotnet(); } + + protected IClientConfiguration CreateClientConfig() { return new ClientConfigurationImpl(); } + + protected IClientConfiguration CreateClientConfiguration() + { + IClientConfiguration clientConfiguration = new ClientConfigurationImpl(); + clientConfiguration.ServerUrl = Constants.SERVER_URL; + return clientConfiguration; + } + + protected IKeyUtil CreateKeyBuilder() { return new KeyUtilImpl(); } + + protected IEdcReader CreateEdcReader() + { + if (_edcReader != null) + { + return _edcReader; + } + HttpClientDotnet httpClient = CreateHttpClient(); + IClientConfiguration clientConfiguration = CreateClientConfiguration(); + IKeyUtil keyUtil = CreateKeyBuilder(); + Startup.ConfigureServices(); + ContextItemFactory? contextItemFactory = new ContextItemFactory(); + DocumentationItemFactory? documentationItemFactory = new DocumentationItemFactory(); + IInformationFactory? informationFactory = new InformationFactory(); + I18NFactory? i18nFactory = new I18NFactory(); + _edcReader = new HttpReaderImpl(httpClient, clientConfiguration, keyUtil, contextItemFactory, documentationItemFactory, informationFactory, i18nFactory); + + return _edcReader; + } + + protected IUrlUtil CreateUrlBuilder() { return new UrlUtilImpl(CreateClientConfiguration()); } + + protected ITranslationUtil CreateTranslationUtil() { return new TranslationUtilImpl(); } + + protected IDocumentationManager CreateDocumentationManager() { return new DocumentationManagerImpl(CreateEdcReader(), CreateKeyBuilder()); } + + protected IInformationManager CreateInformationManager(){ return new InformationManagerImpl(CreateEdcReader()); } + + protected ITranslationManager CreateTranslationManager() { return new TranslationManagerImpl(CreateEdcReader(), CreateTranslationUtil()); } + + protected I18NContentImpl CreateIi8nContent() { return new I18NContentImpl(); } + + protected IEdcClient CreateEdcClient() { return new EdcClientImpl(CreateClientConfiguration(), CreateDocumentationManager(), CreateUrlBuilder(), CreateTranslationManager(), CreateInformationManager()); } + } +} diff --git a/edc-client-dotnet-test/EdcClientSingletonTest.cs b/edc-client-dotnet-test/EdcClientSingletonTest.cs new file mode 100644 index 0000000..30c3492 --- /dev/null +++ b/edc-client-dotnet-test/EdcClientSingletonTest.cs @@ -0,0 +1,102 @@ +using edcClientDotnet; +using edcClientDotnet.model; +using Newtonsoft.Json; +using edcClientDotnetTest.internalImpl; + +namespace edcClientDotnetTest; + +[TestClass] +public class EdcClientSingletonTest +{ + private static string DEFAULT_URL = "https://demo.easydoccontents.com/help/home"; + + [TestInitialize] + public void Setup() + + { + EdcClientSingleton.GetInstance().SetServerUrl(Constants.SERVER_URL); + try + { + EdcClientSingleton.GetInstance().SetWebHelpContextUrl("help"); + EdcClientSingleton.GetInstance().SetDocumentationContextUrl("doc"); + } + catch (InvalidUrlException e) + { + Console.WriteLine(e.Message); + } + } + + [TestMethod] + public void ShouldGetUrl() + { + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", "en"); + Assert.AreEqual("https://demo.easydoccontents.com/help/context/edchelp/fr.techad.edc/help.center/en/0", url); + } + + [TestMethod] + public void ShouldGetUrlWithForceReload() + { + EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", "en"); + EdcClientSingleton.GetInstance().ForceReload(); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", "en"); + Assert.AreEqual("https://demo.easydoccontents.com/help/context/edchelp/fr.techad.edc/help.center/en/0", url); + } + + [TestMethod] + public void ShouldGetDefaultUrlErrorOnMainKey() + { + EdcClientSingleton.GetInstance().ForceReload(); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl(null, "help.center", "en"); + Assert.AreEqual(DEFAULT_URL, url); + } + + [TestMethod] + public void ShouldGetNullUrlErrorOnSubKey() + { + EdcClientSingleton.GetInstance().ForceReload(); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", null, "en"); + Assert.AreEqual(DEFAULT_URL, url); + } + + [TestMethod] + public void ShouldGetDefaultUrlOnLanguageCode() + { + EdcClientSingleton.GetInstance().ForceReload(); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", null); + Assert.AreEqual(DEFAULT_URL, url); + } + + [TestMethod] + public void ShouldGetUrlWithNewWebHelpContext() + { + EdcClientSingleton.GetInstance().SetWebHelpContextUrl("help"); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", "en"); + Assert.AreEqual("https://demo.easydoccontents.com/help/context/edchelp/fr.techad.edc/help.center/en/0", url); + } + + [TestMethod] + [ExpectedException(typeof(InvalidUrlException), + "The WebHelp context is null")] + public void ShouldThrowsExceptionOnNullWebHelpContext() + { + EdcClientSingleton.GetInstance().SetWebHelpContextUrl(null); + } + + [TestMethod] + [ExpectedException(typeof(IOException))] + public void ShouldThrowsExceptionOnUnknownDocumentationContext() + { + EdcClientSingleton.GetInstance().SetDocumentationContextUrl("my-doc"); + EdcClientSingleton.GetInstance().ForceReload(); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", null); + } + + [TestMethod] + [ExpectedException(typeof(InvalidUrlException))] + public void ShouldThrowsExceptionOnNullServer() + { + EdcClientSingleton.GetInstance().SetServerUrl(null); + EdcClientSingleton.GetInstance().ForceReload(); + String url = EdcClientSingleton.GetInstance().GetContextWebHelpUrl("fr.techad.edc", "help.center", "en"); + } +} \ No newline at end of file diff --git a/edc-client-dotnet-test/Usings.cs b/edc-client-dotnet-test/Usings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/edc-client-dotnet-test/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/edc-client-dotnet-test/edc-client-dotnet-test.csproj b/edc-client-dotnet-test/edc-client-dotnet-test.csproj new file mode 100644 index 0000000..2f716f1 --- /dev/null +++ b/edc-client-dotnet-test/edc-client-dotnet-test.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + edcClientDotnetTest + enable + enable + + false + + + + + + + + + + + + + + diff --git a/edc-client-dotnet-test/internalImpl/Constants.cs b/edc-client-dotnet-test/internalImpl/Constants.cs new file mode 100644 index 0000000..150fb73 --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/Constants.cs @@ -0,0 +1,7 @@ +namespace edcClientDotnetTest.internalImpl +{ + public static class Constants + { + public const string SERVER_URL = "https://demo.easydoccontents.com"; + } +} \ No newline at end of file diff --git a/edc-client-dotnet-test/internalImpl/EdcClientImplTest.cs b/edc-client-dotnet-test/internalImpl/EdcClientImplTest.cs new file mode 100644 index 0000000..5fec986 --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/EdcClientImplTest.cs @@ -0,0 +1,76 @@ +using edcClientDotnet; +using edcClientDotnet.model; + +namespace edcClientDotnetTest.internalImpl +{ + [TestClass] + public class EdcClientImplTest : CommonBase + { + private IEdcClient _edcClient; + + [TestInitialize] + public void Setup() + { + _edcClient = CreateEdcClient(); + } + + [TestMethod] + public void ShouldGetContextUrl() + { + String url = _edcClient.GetContextWebHelpUrl("fr.techad.edc", "help.center", "en"); + Assert.AreEqual("https://demo.easydoccontents.com/help/context/edchelp/fr.techad.edc/help.center/en/0", url); + } + + [TestMethod] + public void ShouldGetContextUrlWithRank() + { + String url = _edcClient.GetContextWebHelpUrl("fr.techad.edc", "help.center", 2, "en"); + Assert.AreEqual("https://demo.easydoccontents.com/help/context/edchelp/fr.techad.edc/help.center/en/2", url); + } + + [TestMethod] + public void ShouldGetLabel() + { + String label = _edcClient.GetLabel("articles", "en", "webmailmain"); + Assert.AreEqual("Need more...", label); + } + + [TestMethod] + public void ShouldGetError() + { + String error = _edcClient.GetError("failedData", "en", "webmailmain"); + Assert.AreEqual("Une erreur est survenue lors de la récupération des données !\nVérifiez les clés de la brique fournies au composant EdcHelp.", error); + } + + [TestMethod] + public void ShouldGetContext() + { + IContextItem contextItem = _edcClient.GetContextItem("fr.techad.edc", "help.center", "en"); + _edcClient.LoadContext(); + Assert.IsNotNull(contextItem); + Assert.AreEqual(1, contextItem.ArticleSize()); + Assert.AreEqual(3, contextItem.LinkSize()); + } + + [TestMethod] + public void ShouldGetDocumentationUrl() + { + String documentationWebHelpUrl = _edcClient.GetDocumentationWebHelpUrl(434L, "ru", "myPluginId"); + Assert.AreEqual("https://demo.easydoccontents.com/help/doc/myPluginId/434/ru", documentationWebHelpUrl); + } + + [TestMethod] + public void ShouldGetDocumentationUrlWithNullLanguage() + { + String documentationWebHelpUrl = _edcClient.GetDocumentationWebHelpUrl(434L, null, "myPluginId"); + Assert.AreEqual("https://demo.easydoccontents.com/help/doc/myPluginId/434", documentationWebHelpUrl); + } + + [TestMethod] + public void ShouldGetDocumentationUrlWithNullPublicationId() + { + String documentationWebHelpUrl = _edcClient.GetDocumentationWebHelpUrl(434L, null, null); + Assert.AreEqual("https://demo.easydoccontents.com/help/doc/434", documentationWebHelpUrl); + } + } +} diff --git a/edc-client-dotnet-test/internalImpl/http/HttpClientDotnetTest.cs b/edc-client-dotnet-test/internalImpl/http/HttpClientDotnetTest.cs new file mode 100644 index 0000000..bd092c5 --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/http/HttpClientDotnetTest.cs @@ -0,0 +1,22 @@ +namespace edcClientDotnetTest.internalImpl.http +{ + [TestClass] + public class HttpClientDotnetTest + { + private HttpClient httpClient; + HttpResponseMessage response; + String result; + + [TestInitialize] + public void Setup() { httpClient = new HttpClient(); } + + [TestMethod] + public void ShouldGetAFile() + { + HttpResponseMessage response = httpClient.GetAsync("https://demo.easydoccontents.com/doc/edchelp/context.json").Result; + Assert.IsNotNull(response); + result = response.Content.ReadAsStringAsync().Result; + Assert.IsFalse(String.IsNullOrEmpty(result)); + } + } +} diff --git a/edc-client-dotnet-test/internalImpl/io/HttpReaderImplTest.cs b/edc-client-dotnet-test/internalImpl/io/HttpReaderImplTest.cs new file mode 100644 index 0000000..ca016d2 --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/io/HttpReaderImplTest.cs @@ -0,0 +1,58 @@ +using edcClientDotnet.internalImpl.util; +using edcClientDotnet.io; +using edcClientDotnet.model; +using edcClientDotnet.utils; +using NLog; + +namespace edcClientDotnetTest.internalImpl.io +{ + [TestClass] + public class HttpReaderImplTest : CommonBase + { + private IEdcReader? _edcReader; + String _languageCode = "en"; + HashSet _languagesCodes = new HashSet(); + private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + [TestInitialize] + public void Setup() + { + _languagesCodes.Add("en"); + _languagesCodes.Add("fr"); + _edcReader = CreateEdcReader(); + } + + [TestMethod] + public void ShouldGetContextJson() + { + IKeyUtil keyUtil = new KeyUtilImpl(); + + Dictionary contextItemDictionary = _edcReader.ReadContext(); + Assert.AreEqual(39, contextItemDictionary.Count); + + IContextItem contextItem = contextItemDictionary.GetValueOrDefault(keyUtil.GetKey("fr.techad.edc", "help.center", "en")); + _languageCode = contextItem.LanguageCode; + Assert.AreEqual("All you need about edc", contextItem.Description); + Assert.AreEqual("About edc", contextItem.Label); + Assert.AreEqual("en", contextItem.LanguageCode); + Assert.AreEqual("edchelp/html/en/1/12523/index.html", contextItem.Url); + Assert.AreEqual(1, contextItem.ArticleSize()); + Assert.AreEqual(3, contextItem.LinkSize()); + } + + + + [TestMethod] + public void ShouldGetErrorValueWithDefinedLanguage() + { + + //String errorLabelEN = _edcReader.ReadLabel(_languagesCodes).GetTranslation("en", "errors", "failedData", "leftmenu.account"); + //Assert.IsFalse(String.IsNullOrEmpty(errorLabelEN)); + //Assert.AreEqual("An error occurred when fetching data !\nCheck the brick keys provided to the EdcHelp component.", errorLabelEN); + + String errorLabelFR = _edcReader.ReadLabel(_languagesCodes).GetTranslation("fr", "errors", "failedData", "webmailmain"); + Assert.IsFalse(String.IsNullOrEmpty(errorLabelFR)); + Assert.AreEqual("Une erreur est survenue lors de la récupération des données !\nVérifiez les clés de la brique fournies au composant EdcHelp.", errorLabelFR); + } + } +} diff --git a/edc-client-dotnet-test/internalImpl/model/ClientConfigurationImplTest.cs b/edc-client-dotnet-test/internalImpl/model/ClientConfigurationImplTest.cs new file mode 100644 index 0000000..3a6fa41 --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/model/ClientConfigurationImplTest.cs @@ -0,0 +1,90 @@ +using edcClientDotnet.model; + +namespace edcClientDotnetTest.internalImpl.model +{ + [TestClass] + public class ClientConfigurationImplTest : CommonBase + { + private IClientConfiguration _clientConfiguration; + + [TestInitialize] + public void Setup() + { + _clientConfiguration = CreateClientConfig(); + } + + [TestMethod] + public void ShouldReturnTheDocumentationUrlAndAddSlash() + { + _clientConfiguration.ServerUrl = "http://localhost"; + _clientConfiguration.DocumentationContext = "mydoc"; + Assert.AreEqual("http://localhost/mydoc", _clientConfiguration.DocumentationUrl); + } + + [TestMethod] + public void ShouldReturnTheDocumentationUrl() + { + _clientConfiguration.ServerUrl = "http://localhost/"; + _clientConfiguration.DocumentationContext = "mydoc"; + Assert.AreEqual("http://localhost/mydoc", _clientConfiguration.DocumentationUrl); + } + + [TestMethod] + public void ShouldReturnTheDocumentationUrlWithDefaultDocumentationContext() + { + _clientConfiguration.ServerUrl = "http://localhost/"; + Assert.AreEqual("http://localhost/doc", _clientConfiguration.DocumentationUrl); + } + + [TestMethod] + public void ShouldReturnTheWebHelpUrlAndAddSlash() + { + _clientConfiguration.ServerUrl = "http://localhost"; + _clientConfiguration.WebHelpContext = "my-help"; + Assert.AreEqual("http://localhost/my-help", _clientConfiguration.WebHelpUrl); + } + + [TestMethod] + public void ShouldReturnTheWebHelpUrl() + { + _clientConfiguration.ServerUrl = "http://localhost/"; + _clientConfiguration.WebHelpContext = "my-help"; + Assert.AreEqual("http://localhost/my-help", _clientConfiguration.WebHelpUrl); + } + + [TestMethod] + public void ShouldReturnTheWebHelpUrlWithDefaultWebHelpContext() + { + _clientConfiguration.ServerUrl = "http://localhost/"; + Assert.AreEqual("http://localhost/help", _clientConfiguration.WebHelpUrl); + } + + [TestMethod] + public void ShouldGetServerUrl() + { + _clientConfiguration.ServerUrl = "http://localhost:8080"; + Assert.AreEqual("http://localhost:8080", _clientConfiguration.ServerUrl); + } + + [TestMethod] + [ExpectedException(typeof(InvalidUrlException), + "The server url is not defined")] + public void ShouldThrowExceptionWhenTheServerUrlIsNull() + { + _clientConfiguration.DocumentationContext = "mydoc"; + Assert.Fail(_clientConfiguration.DocumentationUrl); + } + + [TestMethod] + public void ShouldGetWebHelpContext() + { + Assert.AreEqual("help", _clientConfiguration.WebHelpContext); + } + + [TestMethod] + public void ShouldGetDocumentationContext() + { + Assert.AreEqual("doc", _clientConfiguration.DocumentationContext); + } +} +} diff --git a/edc-client-dotnet-test/internalImpl/model/I18NContentImplTest.cs b/edc-client-dotnet-test/internalImpl/model/I18NContentImplTest.cs new file mode 100644 index 0000000..a964bbf --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/model/I18NContentImplTest.cs @@ -0,0 +1,31 @@ +using edcClientDotnet.model; + +namespace edcClientDotnetTest.internalImpl.model +{ + [TestClass] + public class I18NContentImplTest : CommonBase + { + private II18NContent _i18nContent; + + [TestInitialize] + public void Setup() + { + _i18nContent = CreateIi8nContent(); + } + + + [TestMethod] + public void ShouldAddTranslation() + { + _i18nContent.SetTranslation("en", "labels", "articles", "Need more..."); + } + + [TestMethod] + public void ShouldGetTranslation() + { + _i18nContent.SetTranslation("en", "labels", "articles", "Need more..."); + String test = _i18nContent.GetTranslation("en", "labels", "articles", "webmailmain"); + Assert.AreEqual(test, "Need more..."); + } + } +} diff --git a/edc-client-dotnet-test/internalImpl/util/TranslationUtilImplTest.cs b/edc-client-dotnet-test/internalImpl/util/TranslationUtilImplTest.cs new file mode 100644 index 0000000..3bd527f --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/util/TranslationUtilImplTest.cs @@ -0,0 +1,90 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl.factory; +using edcClientDotnet.model; +using edcClientDotnet.utils; + +namespace edcClientDotnetTest.internalImpl.util +{ + [TestClass] + public class TranslationUtilImplTest : CommonBase + { + [TestMethod] + public void ShouldGetPublicationDefaultLanguages() + { + ITranslationUtil translationUtil = CreateTranslationUtil(); + IInformation information1 = CreateInformation("fr"); + IInformation information2 = CreateInformation("ru"); + + SortedDictionary informationPerPublication = new SortedDictionary(); + informationPerPublication.Add("pub1", information1); + informationPerPublication.Add("pub2", information2); + SortedDictionary defaultLanguages = translationUtil.GetPublicationDefaultLanguages(informationPerPublication); + SortedDictionary infoTest = new SortedDictionary + { + { "pub1", "fr" }, + { "pub2", "ru" } + }; + CollectionAssert.AreEqual(infoTest, defaultLanguages); + } + + [TestMethod] + public void ShouldCheckIfLanguageCodeIsValid() + { + ITranslationUtil translationUtil = CreateTranslationUtil(); + Assert.IsTrue(translationUtil.IsLanguageCodeValid("en")); + Assert.IsTrue(translationUtil.IsLanguageCodeValid("fr")); + Assert.IsFalse(translationUtil.IsLanguageCodeValid("")); + Assert.IsFalse(translationUtil.IsLanguageCodeValid("abc")); + Assert.IsFalse(translationUtil.IsLanguageCodeValid(" fr")); + Assert.IsFalse(translationUtil.IsLanguageCodeValid("fr ")); + Assert.IsFalse(translationUtil.IsLanguageCodeValid(null)); + } + + //[TestMethod] + //public void ShouldCheckValidTranslatedLabels() + //{ + // ITranslationUtil translationUtil = CreateTranslationUtil(); + // Dictionary labelsToCheck = CreateLabels("my articles label", "my links label"); + // Boolean isValid = translationUtil.CheckTranslatedLabels(labelsToCheck); + // Assert.IsTrue(isValid); + //} + + [TestMethod] + public void ShouldCheckInvalidTranslatedLabels() + { + ITranslationUtil translationUtil = CreateTranslationUtil(); + Dictionary labelsToCheck = CreateLabels("my articles label", null); + Boolean isValid = translationUtil.CheckTranslatedLabels(labelsToCheck); + Assert.IsFalse(isValid); + } + + [TestMethod] + public void shouldCheckEmptyTranslatedLabels() + { + ITranslationUtil translationUtil = CreateTranslationUtil(); + Dictionary labelsToCheck = CreateLabels("my articles label", ""); + Boolean isValid = translationUtil.CheckTranslatedLabels(labelsToCheck); + Assert.IsFalse(isValid); + } + + private IInformation CreateInformation(String defaultLanguageCode) + { + IInformationFactory informationFactory = new InformationFactory(); + IInformation information = informationFactory.Create(); + information.DefaultLanguage = defaultLanguageCode; + return information; + } + + public Dictionary CreateLabels(String articlesLabel, String linksLabels) + { + Dictionary labels = new Dictionary(); + if (articlesLabel != null) + labels.Add(ParseEnumDescription.GetDescription(I18NTranslation.ARTICLES_KEY), articlesLabel); + if (linksLabels is not null) + labels.Add(ParseEnumDescription.GetDescription(I18NTranslation.LINKS_KEY), linksLabels); + + return labels; + } + } + +} diff --git a/edc-client-dotnet-test/internalImpl/util/UrlUtilImplTest.cs b/edc-client-dotnet-test/internalImpl/util/UrlUtilImplTest.cs new file mode 100644 index 0000000..23583af --- /dev/null +++ b/edc-client-dotnet-test/internalImpl/util/UrlUtilImplTest.cs @@ -0,0 +1,48 @@ +using edcClientDotnet.utils; + +namespace edcClientDotnetTest.internalImpl.util +{ + [TestClass] + public class UrlUtilImplTest : CommonBase + { + [TestMethod] + public void ShouldGetHomeUrl() + { + IUrlUtil urlUtil = CreateUrlBuilder(); + String url = urlUtil.GetHomeUrl(); + Assert.AreEqual("https://demo.easydoccontents.com/help/home", url); + } + + [TestMethod] + public void ShouldGetErrorUrl() + { + IUrlUtil urlUtil = CreateUrlBuilder(); + String url = urlUtil.GetErrorUrl(); + Assert.AreEqual("https://demo.easydoccontents.com/help/error", url); + } + + [TestMethod] + public void ShouldCreateAContextUrl() + { + IUrlUtil urlUtil = CreateUrlBuilder(); + String url = urlUtil.GetContextUrl("fr.techad.edc.help", "fr.techad.edc", "help.center", "en", 0); + Assert.AreEqual("https://demo.easydoccontents.com/help/context/fr.techad.edc.help/fr.techad.edc/help.center/en/0", url); + } + + [TestMethod] + public void ShouldCreateADocUrl() + { + IUrlUtil urlUtil = CreateUrlBuilder(); + String url = urlUtil.GetDocumentationUrl(12L, "fr", "myPluginId"); + Assert.AreEqual("https://demo.easydoccontents.com/help/doc/myPluginId/12/fr", url); + } + + [TestMethod] + public void ShouldCreateADocUrlWithNullLanguage() + { + IUrlUtil urlUtil = CreateUrlBuilder(); + String url = urlUtil.GetDocumentationUrl(12L, null, "myPluginId"); + Assert.AreEqual("https://demo.easydoccontents.com/help/doc/myPluginId/12", url); + } + } +} diff --git a/edc-client-dotnet.csproj b/edc-client-dotnet.csproj new file mode 100644 index 0000000..edc8977 --- /dev/null +++ b/edc-client-dotnet.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + edc_client_dotnet + enable + enable + + + + + + + diff --git a/edc-client-dotnet.sln b/edc-client-dotnet.sln new file mode 100644 index 0000000..a412d9e --- /dev/null +++ b/edc-client-dotnet.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32526.322 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "edc-client-dotnet", "edc-client-dotnet\edc-client-dotnet.csproj", "{5FACAFF7-0B95-4C41-8E75-B6FB4AD14944}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "edc-client-dotnet-test", "edc-client-dotnet-test\edc-client-dotnet-test.csproj", "{0CC96F78-ADC1-45A7-935E-8A6CCA5CCDC0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleAppClientTest", "ConsoleAppClientTest\ConsoleAppClientTest.csproj", "{554918E7-21EC-4DA7-97CB-13934435A5F2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5FACAFF7-0B95-4C41-8E75-B6FB4AD14944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5FACAFF7-0B95-4C41-8E75-B6FB4AD14944}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5FACAFF7-0B95-4C41-8E75-B6FB4AD14944}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5FACAFF7-0B95-4C41-8E75-B6FB4AD14944}.Release|Any CPU.Build.0 = Release|Any CPU + {0CC96F78-ADC1-45A7-935E-8A6CCA5CCDC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CC96F78-ADC1-45A7-935E-8A6CCA5CCDC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CC96F78-ADC1-45A7-935E-8A6CCA5CCDC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CC96F78-ADC1-45A7-935E-8A6CCA5CCDC0}.Release|Any CPU.Build.0 = Release|Any CPU + {554918E7-21EC-4DA7-97CB-13934435A5F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {554918E7-21EC-4DA7-97CB-13934435A5F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {554918E7-21EC-4DA7-97CB-13934435A5F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {554918E7-21EC-4DA7-97CB-13934435A5F2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5404A94D-DFCB-4785-A6C3-BE134B807883} + EndGlobalSection +EndGlobal diff --git a/edc-client-dotnet/EdcClientSingleton.cs b/edc-client-dotnet/EdcClientSingleton.cs new file mode 100644 index 0000000..5f80b6a --- /dev/null +++ b/edc-client-dotnet/EdcClientSingleton.cs @@ -0,0 +1,116 @@ +using edcClientDotnet.Injection; +using edcClientDotnet.model; +using Microsoft.Extensions.DependencyInjection; +using NLog; + +namespace edcClientDotnet +{ + public class EdcClientSingleton : IEdcClient + { + private static EdcClientSingleton? _instance = null; + private IEdcClient _edcClient; + private readonly static Logger _logger = LogManager.GetCurrentClassLogger(); + + private EdcClientSingleton() : base() { } + + public static EdcClientSingleton GetInstance() + { + if (_instance == null) + { + _instance = new EdcClientSingleton(); + _instance.Init(); + } + return _instance; + } + + private void Init() + { + Startup.ConfigureServices(); + _edcClient = Startup.serviceProvider.GetRequiredService(); + } + + /// + /// + public String GetContextWebHelpUrl(String mainKey, String subKey, String languageCode) + { + return _edcClient.GetContextWebHelpUrl(mainKey, subKey, languageCode); + } + + /// + /// + public String GetContextWebHelpUrl(String mainKey, String subKey, int rank, String languageCode) + { + return _edcClient.GetContextWebHelpUrl(mainKey, subKey, rank, languageCode); + } + + /// + public String GetDocumentationWebHelpUrl(long id, String languageCode, String srcPublicationId) + { + return _edcClient.GetDocumentationWebHelpUrl(id, languageCode, srcPublicationId); + } + + /// + /// + public IContextItem GetContextItem(String? mainKey, String? subKey, String? languageCode) + { + return _edcClient.GetContextItem(mainKey, subKey, languageCode); + } + + /// + /// + public String GetLabel(String labelKey, String languageCode, String publicationId) + { + try + { + return _edcClient.GetLabel(labelKey, languageCode, publicationId); + } + catch (IOException ex) + { + // Handle IOException here + // You can log the exception, display an error message, or take appropriate action + // Example: + _logger.Error("An IOException occurred: " + ex.Message); + } + catch (InvalidUrlException ex) + { + // Handle InvalidUrlException here + // Example: + _logger.Error("An InvalidUrlException occurred: " + ex.Message); + } + + // Return a default value or handle the exceptional case + return string.Empty; + + } + + /// + /// + public String GetError(String errorKey, String languageCode, String publicationId) + { + return _edcClient.GetError(errorKey, languageCode, publicationId); + } + + public void SetServerUrl(String serverUrl) + { + _edcClient.SetServerUrl(serverUrl); + } + + /// + public void SetWebHelpContextUrl(String webHelpContextUrl) + { + _edcClient.SetWebHelpContextUrl(webHelpContextUrl); + } + + /// + public void SetDocumentationContextUrl(String documentationContextUrl) + { + _edcClient.SetDocumentationContextUrl(documentationContextUrl); + } + + /// + /// + public void LoadContext() { _edcClient.LoadContext(); } + + public void ForceReload() { _edcClient.ForceReload(); } + } +} diff --git a/edc-client-dotnet/IDocumentationManager.cs b/edc-client-dotnet/IDocumentationManager.cs new file mode 100644 index 0000000..7c8c573 --- /dev/null +++ b/edc-client-dotnet/IDocumentationManager.cs @@ -0,0 +1,35 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet +{ + /// DocumentationManager manage all content of the documentation. + public interface IDocumentationManager + { + + /// + /// Get the context item according to the keys and the language or the default language if not found. + /// If the context was not found in the requested language, it will find the publication from the given keys + /// and use the default language, identified from the the default languages dictionary + /// + /// the main key + /// the sub key + /// the language code + /// a dictionary containing the publication id as key and default language code as value + /// the context item or null + /// if an error is occurred on reading + /// if the url is malformed + IContextItem? GetContext(String? mainKey, String? subKey, String? languageCode, IReadOnlyDictionary defaultLanguages); + + /// + /// Force the reload of the documentation definition on the next call. + /// + void ForceReload(); + + /// + /// Force the documentation loading. This call is optional. Don't call if you want to use the lazy loading. + /// + /// if an error is occurred on reading + /// if the url is malformed + void LoadContext(); + } +} diff --git a/edc-client-dotnet/IEdcClient.cs b/edc-client-dotnet/IEdcClient.cs new file mode 100644 index 0000000..fd11f40 --- /dev/null +++ b/edc-client-dotnet/IEdcClient.cs @@ -0,0 +1,128 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet +{ + // EdcClient is the utility class to get all information about documentation. + public interface IEdcClient + { + /// + /// Create the url for the context according to the main key, the subkey and the language code. + ///

+ /// The language code is 2 digits in lowercase ie fr, en, ... + ///

+ /// the main key + /// the sub key + /// the language code + /// the url + /// if an error is occurred on reading + /// if the url is malformed + String GetContextWebHelpUrl(String mainKey, String subKey, String languageCode); + + /// + /// Create the url for the context according to the main key, the subkey and the language code. + ///

+ /// The language code is 2 digits in lowercase ie fr, en, ... + ///

+ /// the main key + /// the sub key + /// the rank + /// the language code + /// the url + /// if an error is occurred on reading + /// if the url is malformed + String GetContextWebHelpUrl(String mainKey, String subKey, int rank, String languageCode); + + /// + /// Create the url for the documentation. + ///

+ /// The language code is 2 digits in lowercase ie fr, en, ... + /// If languageCode is not defined or not found, system default will be used instead + /// Url will include the identifier of publication from where the navigation started, if present + ///

+ /// the identifier of the documentation + /// the 2 letters code of the language to use + /// the identifier of the publication where the navigation starts from + /// the url + /// if the url is malformed + String GetDocumentationWebHelpUrl(long id, String languageCode, String srcPublicationId); + + /// + /// Return the context item associated with main and sub keys and the language code. + /// + /// the main key + /// the sub bey + /// the language code + /// the context item + /// if an error is occurred on reading + /// if the url is malformed + IContextItem? GetContextItem(String? mainKey, String? subKey, String? languageCode); + + /// + /// Return the label translation for the given key + /// Will read the translated labels from the the i18n files present in the documentation export + /// (by default in folder doc/i18n/popover/*.json) + /// + /// If label was not found in the requested language, it will try and read in the publication default language + /// (as defined in the info.json file), + /// or in global default labels as a final fallback + /// + /// the label translation key + /// the 2 letters language code + /// default language, to use if content was not found in requested language + /// the translated label + /// if an error is occurred when reading the files + /// if the url is malformed + String GetLabel(String labelKey, String languageCode, String publicationId); + + /// + /// Return the error translation for the given key + /// Will read the translated errors from the the i18n files present in the documentation export + /// (by default in folder doc/i18n/popover/*.json) + /// + /// If error was not found in the requested language, it will try and read in the publication default language + /// (as defined in the info.json file), + /// or in global default errors as a final fallback + /// + /// + /// + /// + /// + /// + /// + String GetError(String errorKey, String languageCode, String publicationId); + + /// + /// Define the server url like http://localhost:8080 + /// + /// the server url + void SetServerUrl(String serverUrl); + + /// + /// Define the context url ie like doc in http://localhost:8080/doc + /// The default value is 'doc'. Do nothing if you don't change the default behavior. + /// + /// the documentation context url + /// if the url is malformed + void SetDocumentationContextUrl(String documentationContextUrl); + + /// + /// Define the context url ie like help in http://localhost:8080/help + /// The default value is 'help'. Do nothing if you don't change the default behavior. + /// + /// the web help context url + /// if the url is malformed + void SetWebHelpContextUrl(String webHelpContextUrl); + + /// + /// Force the manager to reload the documentation definition, publication information and translations. + /// + void ForceReload(); + + /// + /// Force the documentation loading. This call is optional. Don't call if you want to use the lazy loading. + /// + /// if an is occurred on reading information + /// if the url is malformed + void LoadContext(); + } +} \ No newline at end of file diff --git a/edc-client-dotnet/IInformationManager.cs b/edc-client-dotnet/IInformationManager.cs new file mode 100644 index 0000000..aec9cac --- /dev/null +++ b/edc-client-dotnet/IInformationManager.cs @@ -0,0 +1,28 @@ +using edcClientDotnet.model; +using System.Collections.ObjectModel; + +namespace edcClientDotnet +{ + public interface IInformationManager + { + /// + /// Load the information for every publication, from the info.json files + /// + /// if an IO Exception occurred while reading the file + /// if the file url was not valid + void LoadInformation(); + + /// + /// Force the reload of the publications information on the next read + /// + void ForceReload(); + + /// + /// Return the information for each present publication + /// + /// a dictionary with publication id as key and information as value + /// if an error occurred while getting the file + /// if the url was not valid + ReadOnlyDictionary GetPublicationInformation(); + } +} diff --git a/edc-client-dotnet/ITranslationManager.cs b/edc-client-dotnet/ITranslationManager.cs new file mode 100644 index 0000000..d2000b2 --- /dev/null +++ b/edc-client-dotnet/ITranslationManager.cs @@ -0,0 +1,55 @@ +using edcClientDotnet.model; +using System.Collections.ObjectModel; + +namespace edcClientDotnet +{ + public interface ITranslationManager + { + /// + /// Load the translation information and the translation popover labels + /// + /// Information : - load the languages used by all the publications + /// - load the dictionary of default languages by publication + /// Labels: the labels used by the popover (articles, links), + /// These labels are read from the i18n files present in the documentation root folder + /// + /// + /// a Dictionary containing all the publication information for every publication + /// if an IO error occurred + /// if the i18n files urls were not valid + void LoadTranslations(ReadOnlyDictionary publicationInformation); + + /// + /// Force the reload of the translation information and labels on the next read + /// + void ForceReload(); + + /// + /// Return the translated popover label for the requested key + /// If no label was found for the language, will look for the label in the publication default language + /// Finally, system default labels will be used if no valid label was found in default language + /// + /// the label key + /// the requested language + /// the identifier of the publication, to find the default language + /// A string containing the translated label + String GetLabel(String labelKey, String languageCode, String publicationId); + + /// + /// Return the translated popover error for the requested key + /// If no error was found for the language, will look for the error in the publication default language + /// Finally, system default errors will be used if no valid error was found in default language + /// + /// the error key + /// the requested language + /// the identifier of the publication, to find the default language + /// A string containing the translated error + String GetError(String errorKey, String languageCode, String publicationId); + + /// + /// Return a Dictionary with the default language for each publication + /// + /// a Dictionary containing the publication id as key, default language code as value + Dictionary GetDefaultPublicationLanguages(); + } +} diff --git a/edc-client-dotnet/Injection/Startup.cs b/edc-client-dotnet/Injection/Startup.cs new file mode 100644 index 0000000..9a55f07 --- /dev/null +++ b/edc-client-dotnet/Injection/Startup.cs @@ -0,0 +1,44 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl; +using edcClientDotnet.internalImpl.factory; +using edcClientDotnet.internalImpl.http; +using edcClientDotnet.internalImpl.io; +using edcClientDotnet.internalImpl.model; +using edcClientDotnet.internalImpl.util; +using edcClientDotnet.io; +using edcClientDotnet.model; +using edcClientDotnet.utils; +using Microsoft.Extensions.DependencyInjection; + +namespace edcClientDotnet.Injection +{ + public static class Startup + { + public static IServiceProvider? serviceProvider; + public static void ConfigureServices() + { + var services = new ServiceCollection(); + + services.AddSingleton(); + services.AddSingleton().AddSingleton(s => s.GetService()); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + serviceProvider = services.BuildServiceProvider(); + } + + } +} diff --git a/LICENSE b/edc-client-dotnet/LICENSE similarity index 100% rename from LICENSE rename to edc-client-dotnet/LICENSE diff --git a/edc-client-dotnet/NLog.config b/edc-client-dotnet/NLog.config new file mode 100644 index 0000000..936b4b1 --- /dev/null +++ b/edc-client-dotnet/NLog.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/edc-client-dotnet/README.md b/edc-client-dotnet/README.md new file mode 100644 index 0000000..2c8e61b --- /dev/null +++ b/edc-client-dotnet/README.md @@ -0,0 +1,17 @@ +# edc-client-dotnet +The edc client is the dotnet connector to get edc context documentation in HTML5 format. + +This client read informations from defined url. The developer will be able to get contextual documentation content according to the keys and get the help url to display the documentation in the help client. + +## edc Version + +Current release is compatible with edc v3.0+ + +## How can I get the latest release? + +You can pull it from Nuget.org + + +## License + +MIT [TECH'advantage](mailto:contact@tech-advantage.com) \ No newline at end of file diff --git a/edc-client-dotnet/edc-client-dotnet.csproj b/edc-client-dotnet/edc-client-dotnet.csproj new file mode 100644 index 0000000..81f6737 --- /dev/null +++ b/edc-client-dotnet/edc-client-dotnet.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + edcClientDotnet + enable + enable + + + + + + + + + PreserveNewest + + + + + + + + + + + + + diff --git a/edc-client-dotnet/edc-client-dotnet.csproj.user b/edc-client-dotnet/edc-client-dotnet.csproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/edc-client-dotnet/edc-client-dotnet.csproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/edc-client-dotnet/factory/IContextItemFactory.cs b/edc-client-dotnet/factory/IContextItemFactory.cs new file mode 100644 index 0000000..46b87eb --- /dev/null +++ b/edc-client-dotnet/factory/IContextItemFactory.cs @@ -0,0 +1,9 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.factory +{ + public interface IContextItemFactory + { + IContextItem Create(); + } +} diff --git a/edc-client-dotnet/factory/IDocumentationItemFactory.cs b/edc-client-dotnet/factory/IDocumentationItemFactory.cs new file mode 100644 index 0000000..b012220 --- /dev/null +++ b/edc-client-dotnet/factory/IDocumentationItemFactory.cs @@ -0,0 +1,9 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.factory +{ + public interface IDocumentationItemFactory + { + public IDocumentationItem Create(); + } +} diff --git a/edc-client-dotnet/factory/II18NFactory.cs b/edc-client-dotnet/factory/II18NFactory.cs new file mode 100644 index 0000000..3fcb6c2 --- /dev/null +++ b/edc-client-dotnet/factory/II18NFactory.cs @@ -0,0 +1,9 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.factory +{ + public interface II18NFactory + { + public II18NContent Create(); + } +} diff --git a/edc-client-dotnet/factory/IInformationFactory.cs b/edc-client-dotnet/factory/IInformationFactory.cs new file mode 100644 index 0000000..8ab8df5 --- /dev/null +++ b/edc-client-dotnet/factory/IInformationFactory.cs @@ -0,0 +1,9 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.factory +{ + public interface IInformationFactory + { + public IInformation Create(); + } +} diff --git a/edc-client-dotnet/internalImpl/DocumentationManagerImpl.cs b/edc-client-dotnet/internalImpl/DocumentationManagerImpl.cs new file mode 100644 index 0000000..f34004e --- /dev/null +++ b/edc-client-dotnet/internalImpl/DocumentationManagerImpl.cs @@ -0,0 +1,68 @@ +using edcClientDotnet.io; +using edcClientDotnet.model; +using edcClientDotnet.utils; +using NLog; + +namespace edcClientDotnet.internalImpl +{ + public class DocumentationManagerImpl : IDocumentationManager + { + private readonly IEdcReader _reader; + private readonly IKeyUtil _keyUtil; + private Dictionary? _contexts; + private readonly static Logger _logger = LogManager.GetCurrentClassLogger(); + + public DocumentationManagerImpl(IEdcReader reader, IKeyUtil keyBuilder) + { + _reader = reader; + _keyUtil = keyBuilder; + } + + public IContextItem? GetContext(String? mainKey, String? subKey, String? languageCode, IReadOnlyDictionary defaultLanguages) + { + + _logger.Debug("Get Context item with mainkey: {}, subKey: {}, languageCode:{}", mainKey, subKey, languageCode); + LoadContext(); + + IContextItem? contextItem = _contexts.GetValueOrDefault(_keyUtil.GetKey(mainKey, subKey, languageCode)); + + if (contextItem == null && !String.IsNullOrEmpty(languageCode)) + { + _logger.Debug("Context item was null, getting from defaultLanguages:{}", defaultLanguages); + contextItem = FindOrDefaultContextItem(mainKey, subKey, defaultLanguages); + } + + return contextItem; + } + + public void ForceReload() + { + _logger.Debug("Force reload on next call"); + _contexts = null; + } + + public void LoadContext() + { + if (_contexts == null) + { + _logger.Debug("No contexts defined, read it"); + _contexts = _reader.GetContext(); + } + } + + private IContextItem? FindOrDefaultContextItem(String mainKey, String subKey, IReadOnlyDictionary defaultLangCodes) + { + IContextItem? defaultContext = null; + HashSet presentItems = _contexts.Where(e => _keyUtil.ContainsKey(e.Key, mainKey, subKey)).Select(row => row.Value).ToHashSet(); + + if (presentItems.Any()) + { + String exportId = String.IsNullOrEmpty(presentItems.Select(s => s.PublicationId).First()) ? "" : presentItems.Select(s => s.PublicationId).First(); + String defaultLang = defaultLangCodes.GetValueOrDefault(exportId); + defaultContext = _contexts.GetValueOrDefault(_keyUtil.GetKey(mainKey, subKey, defaultLang)); + } + return defaultContext; + } + + } +} diff --git a/edc-client-dotnet/internalImpl/EdcClientImpl.cs b/edc-client-dotnet/internalImpl/EdcClientImpl.cs new file mode 100644 index 0000000..8706db1 --- /dev/null +++ b/edc-client-dotnet/internalImpl/EdcClientImpl.cs @@ -0,0 +1,136 @@ +using edcClientDotnet.model; +using edcClientDotnet.utils; +using NLog; + +namespace edcClientDotnet.internalImpl +{ + public class EdcClientImpl : IEdcClient + { + private readonly IClientConfiguration _clientConfiguration; + private readonly IDocumentationManager _documentationManager; + private readonly ITranslationManager _translationManager; + private readonly IInformationManager _informationManager; + private readonly IUrlUtil _urlUtil; + private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public EdcClientImpl(IClientConfiguration clientConfiguration, IDocumentationManager documentationManager, + IUrlUtil urlUtil, ITranslationManager translationManager, IInformationManager informationManager) + { + _clientConfiguration = clientConfiguration; + _documentationManager = documentationManager; + _translationManager = translationManager; + _informationManager = informationManager; + _urlUtil = urlUtil; + } + + /// + /// + public String GetContextWebHelpUrl(String mainKey, String subKey, String languageCode) + { + _logger.Debug("Get WebHelp Context item with mainKey: {}, subKey: {}, languageCode:{}", mainKey, subKey, languageCode); + return GetContextWebHelpUrl(mainKey, subKey, 0, languageCode); + } + + /// + /// + public String GetContextWebHelpUrl(String mainKey, String subKey, int rank, String languageCode) + { + _logger.Debug("Get WebHelp Context item with mainKey: {}, subKey: {}, languageCode:{}", mainKey, subKey, languageCode); + String url; + + IContextItem context = _documentationManager.GetContext(mainKey, subKey, languageCode, _translationManager.GetDefaultPublicationLanguages()); + + if (context != null && (context.ArticleSize() > 0 || context.LinkSize() > 0)) + { + url = _urlUtil.GetContextUrl(context.PublicationId, mainKey, subKey, languageCode, rank); + } else + { + url = _urlUtil.GetHomeUrl(); + } + _logger.Debug("Get WebHelp url: {}", url); + return url; + } + + /// + public String GetDocumentationWebHelpUrl(long id, String languageCode, String srcPublicationId) + { + String url; + + if (id != null) + { + url = _urlUtil.GetDocumentationUrl(id, languageCode, srcPublicationId); + } else + { + url = _urlUtil.GetHomeUrl(); + } + + return url; + } + + /// + /// + public IContextItem GetContextItem(String? mainKey, String? subKey, String? languageCode) + { + _logger.Debug("Get WebHelp Context item with mainKey: {}, subKey: {}, languageCode:{}", mainKey, subKey, languageCode); + LoadContext(); + return _documentationManager.GetContext(mainKey, subKey, languageCode, _translationManager.GetDefaultPublicationLanguages()); + } + + /// + /// + public String GetLabel(String labelKey, String languageCode, String publicationId) + { + _logger.Debug("Getting label for key {}, language code {} and publication id {}", labelKey, languageCode, publicationId); + LoadContext(); + return _translationManager.GetLabel(labelKey, languageCode, publicationId); + } + + /// + /// + public String GetError(String errorKey, String languageCode, String publicationId) + { + _logger.Debug("Getting error for key {}, language code {} and publication id {}", errorKey, languageCode, publicationId); + LoadContext(); + + return _translationManager.GetError(errorKey, languageCode, publicationId); + } + public void SetServerUrl(String serverUrl) + { + _logger.Debug("New server url: {}", serverUrl); + _clientConfiguration.ServerUrl = serverUrl; + } + + /// + public void SetWebHelpContextUrl(String webHelpContextUrl) + { + _logger.Debug("New WebHelp Context: {}", webHelpContextUrl); + _clientConfiguration.WebHelpContext = webHelpContextUrl; + } + + /// + public void SetDocumentationContextUrl(String documentationContextUrl) + { + _logger.Debug("New Documentation Context: {}", documentationContextUrl); + _clientConfiguration.DocumentationContext = documentationContextUrl; + } + + public void ForceReload() + { + _logger.Debug("Force reload"); + _informationManager.ForceReload(); + _translationManager.ForceReload(); + _documentationManager.ForceReload(); + } + + /// + /// + public void LoadContext() + { + _logger.Debug("Loading of the configuration"); + _informationManager.LoadInformation(); + _translationManager.LoadTranslations(_informationManager.GetPublicationInformation()); + + _documentationManager.LoadContext(); + } + } +} diff --git a/edc-client-dotnet/internalImpl/InformationManagerImpl.cs b/edc-client-dotnet/internalImpl/InformationManagerImpl.cs new file mode 100644 index 0000000..28024e3 --- /dev/null +++ b/edc-client-dotnet/internalImpl/InformationManagerImpl.cs @@ -0,0 +1,39 @@ +using edcClientDotnet.io; +using edcClientDotnet.model; +using NLog; +using System.Collections.ObjectModel; + +namespace edcClientDotnet.internalImpl +{ + public class InformationManagerImpl : IInformationManager + { + private readonly IEdcReader _reader; + private readonly Dictionary _information = new(); + private readonly static Logger _logger = LogManager.GetCurrentClassLogger(); + + public InformationManagerImpl(IEdcReader reader){ _reader = reader; } + + public void LoadInformation() + { + foreach (KeyValuePair entry in _reader.GetInformations()) + { + if (!_information.ContainsKey(entry.Key)) + { + _information.Add(entry.Key, entry.Value); + } + } + } + + public void ForceReload() + { + _information.Clear(); + _logger.Debug("Information cleared, will be "); + } + + public ReadOnlyDictionary GetPublicationInformation() + { + return new ReadOnlyDictionary(_information); + } + + } +} diff --git a/edc-client-dotnet/internalImpl/TranslationConstants.cs b/edc-client-dotnet/internalImpl/TranslationConstants.cs new file mode 100644 index 0000000..3c4eedc --- /dev/null +++ b/edc-client-dotnet/internalImpl/TranslationConstants.cs @@ -0,0 +1,78 @@ +using edcClientDotnet.model; +using edcClientDotnet.utils; +using System.Collections; + +namespace edcClientDotnet.internalImpl +{ + public class TranslationConstants : IEnumerable + { + public static Dictionary GetDefaultLabels() + { + return new Dictionary + { + [ParseEnumDescription.GetDescription(I18NTranslation.ARTICLES_KEY)] = "Need more...", + [ParseEnumDescription.GetDescription(I18NTranslation.LINKS_KEY)] = "Related topics", + [ParseEnumDescription.GetDescription(I18NTranslation.COMING_SOON_KEY)] = "Contextual help is coming soon.", + [ParseEnumDescription.GetDescription(I18NTranslation.ERROR_TITLE_KEY)] = "Error", + }; + } + + public static Dictionary GetDefaultErrors() + { + return new Dictionary + { + [ParseEnumDescription.GetDescription(I18NTranslation.ERRORS_KEY)] = "An error occurred when fetching data!\nCheck the brick keys provided to the EdcHelp component." + }; + } + + public static readonly IEnumerable LANGUAGES_CODES = new HashSet + { + "en", // English + "ar", // Arabic + "bg", // Bulgarian + "zh", // Chinese + "hr", // Croatian + "cs", // Czech + "da", // Danish + "nl", // Dutch + "et", // Estonian + "fi", // Finnish + "fr", // French + "de", // German + "el", // Greek + "he", // Hebrew + "hu", // Hungarian + "is", // Icelandic + "ga", // Irish + "it", // Italian + "ja", // Japanese + "ko", // Korean + "lv", // Latvian + "lt", // Lithuanian + "lb", // Luxembourgish + "mt", // Maltese + "no", // Norwegian + "fa", // Persian + "pl", // Polish + "pt", // Portuguese + "ro", // Romanian + "ru", // Russian + "sk", // Slovak + "sl", // Slovenian + "es", // Spanish + "sv", // Swedish + "tr", // Turkish + "vi" // Vietnamese + }; + + public IEnumerator GetEnumerator() + { + return null; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return null; + } + } +} diff --git a/edc-client-dotnet/internalImpl/TranslationManagerImpl.cs b/edc-client-dotnet/internalImpl/TranslationManagerImpl.cs new file mode 100644 index 0000000..cc67dd4 --- /dev/null +++ b/edc-client-dotnet/internalImpl/TranslationManagerImpl.cs @@ -0,0 +1,96 @@ +using edcClientDotnet.io; +using edcClientDotnet.model; +using edcClientDotnet.utils; +using NLog; +using System.Collections.ObjectModel; + +namespace edcClientDotnet.internalImpl +{ + public class TranslationManagerImpl : ITranslationManager + { + private readonly IEdcReader _reader; + private readonly ITranslationUtil _translationUtil; + private II18NContent? _translation = null; + // The languages codes present among all the publications + private readonly HashSet _languageCodes = new(); + // The default language code for each publication id + private readonly Dictionary _defaultPublicationLanguages = new(); + private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + + public TranslationManagerImpl(IEdcReader reader, ITranslationUtil translationUtil) + { + _reader = reader; + _translationUtil = translationUtil; + } + + /// + /// + public void LoadTranslations(ReadOnlyDictionary publicationInformation) + { + if (_translation == null && publicationInformation != null) + { + foreach (var entry in publicationInformation) + { + IInformation information = entry.Value; + AddToDefaultLanguages(entry.Key, information); + AddToLanguages(information); + } + } + _translation = _reader.ReadLabel(_languageCodes); + } + + public Dictionary GetDefaultPublicationLanguages() + { + return _defaultPublicationLanguages; + } + + public String GetLabel(String labelKey, String languageCode, String publicationId) + { + _logger.Debug("Getting label with key {}, for languageCode {} and publicationId {}", labelKey, languageCode, publicationId); + String translationLabelValue = GetTranslation(languageCode, ParseEnumDescription.GetDescription(I18NTranslation.I18N_LABELS_ROOT), labelKey, publicationId); + return String.IsNullOrEmpty(translationLabelValue) ? TranslationConstants.GetDefaultLabels().GetValueOrDefault(labelKey) : translationLabelValue; + } + + public String GetError(String errorKey, String languageCode, String publicationId) + { + _logger.Debug("Getting error with key {}, for languageCode {} and publicationId {}", errorKey, languageCode, publicationId); + String translationErrorValue = GetTranslation(languageCode, ParseEnumDescription.GetDescription(I18NTranslation.I18N_ERRORS_ROOT), errorKey, publicationId); + return String.IsNullOrEmpty(translationErrorValue) ? TranslationConstants.GetDefaultErrors().GetValueOrDefault(errorKey) : translationErrorValue; + } + + public void ForceReload() + { + _translation = null; + _languageCodes.Clear(); + _defaultPublicationLanguages.Clear(); + } + + private String GetTranslation(String lang, String type, String key, String publicationId) + { + _logger.Debug("Getting translation with lang {}, type {}, for key {} and publicationId {}", lang, type, key, publicationId); + return _translation != null ? _translation.GetTranslation(lang, type, key, publicationId) : String.Empty; + } + + private void AddToDefaultLanguages(String publicationId, IInformation information) + { + if (information != null && _translationUtil.IsLanguageCodeValid(information.DefaultLanguage)) + { + _defaultPublicationLanguages.Add(publicationId, information.DefaultLanguage); + } + } + + private void AddToLanguages(IInformation information) + { + if (information != null && information.Languages != null) + { + foreach (String languageCode in information.Languages) + { + if (_translationUtil.IsLanguageCodeValid(languageCode)) + { + _languageCodes.Add(languageCode); + } + } + } + } + } +} diff --git a/edc-client-dotnet/internalImpl/factory/ContextItemFactory.cs b/edc-client-dotnet/internalImpl/factory/ContextItemFactory.cs new file mode 100644 index 0000000..548d27c --- /dev/null +++ b/edc-client-dotnet/internalImpl/factory/ContextItemFactory.cs @@ -0,0 +1,14 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl.model; +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.factory +{ + public class ContextItemFactory : IContextItemFactory + { + public IContextItem Create() + { + return new ContextItemImpl(); + } + } +} diff --git a/edc-client-dotnet/internalImpl/factory/DocumentationItemFactory.cs b/edc-client-dotnet/internalImpl/factory/DocumentationItemFactory.cs new file mode 100644 index 0000000..574b930 --- /dev/null +++ b/edc-client-dotnet/internalImpl/factory/DocumentationItemFactory.cs @@ -0,0 +1,14 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl.model; +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.factory +{ + public class DocumentationItemFactory : IDocumentationItemFactory + { + public IDocumentationItem Create() + { + return new DocumentationItemImpl(); + } + } +} diff --git a/edc-client-dotnet/internalImpl/factory/I18NFactory.cs b/edc-client-dotnet/internalImpl/factory/I18NFactory.cs new file mode 100644 index 0000000..1abbc12 --- /dev/null +++ b/edc-client-dotnet/internalImpl/factory/I18NFactory.cs @@ -0,0 +1,14 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl.model; +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.factory +{ + public class I18NFactory : II18NFactory + { + public II18NContent Create() + { + return new I18NContentImpl(); + } + } +} diff --git a/edc-client-dotnet/internalImpl/factory/InformationFactory.cs b/edc-client-dotnet/internalImpl/factory/InformationFactory.cs new file mode 100644 index 0000000..ebe2a2c --- /dev/null +++ b/edc-client-dotnet/internalImpl/factory/InformationFactory.cs @@ -0,0 +1,14 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl.model; +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.factory +{ + public class InformationFactory : IInformationFactory + { + public IInformation Create() + { + return new InformationImpl(); + } + } +} diff --git a/edc-client-dotnet/internalImpl/http/Error4xxException.cs b/edc-client-dotnet/internalImpl/http/Error4xxException.cs new file mode 100644 index 0000000..6949516 --- /dev/null +++ b/edc-client-dotnet/internalImpl/http/Error4xxException.cs @@ -0,0 +1,7 @@ +namespace edcClientDotnet.internalImpl.http +{ + public class Error4xxException : Exception + { + public Error4xxException(String message) : base(message) { } + } +} diff --git a/edc-client-dotnet/internalImpl/http/HttpClientDotnet.cs b/edc-client-dotnet/internalImpl/http/HttpClientDotnet.cs new file mode 100644 index 0000000..481a17a --- /dev/null +++ b/edc-client-dotnet/internalImpl/http/HttpClientDotnet.cs @@ -0,0 +1,39 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.http +{ + public class HttpClientDotnet : HttpClient + { + /// + /// + public String GetAsyncResponse(String url) + { + HttpResponseMessage response; + String result; + + using (HttpClient client = new HttpClient()) + { + try + { + response = client.GetAsync(url).Result; + int statusCode = (int)response.StatusCode; + if (statusCode >= 400 && statusCode < 500) + { + throw new Error4xxException("The url '" + url + "' return " + response.StatusCode); + } + + if (response.IsSuccessStatusCode) + { + result = response.Content.ReadAsStringAsync().Result; + return result; + } + } + catch (Exception ex) + { + throw new Error4xxException(ex.Message); + } + } + return null; + } + } +} diff --git a/edc-client-dotnet/internalImpl/io/HttpReaderImpl.cs b/edc-client-dotnet/internalImpl/io/HttpReaderImpl.cs new file mode 100644 index 0000000..132ad9b --- /dev/null +++ b/edc-client-dotnet/internalImpl/io/HttpReaderImpl.cs @@ -0,0 +1,353 @@ +using edcClientDotnet.factory; +using edcClientDotnet.internalImpl.http; +using edcClientDotnet.io; +using edcClientDotnet.model; +using edcClientDotnet.utils; +using Newtonsoft.Json.Linq; +using NLog; +using static edcClientDotnet.model.I18NTranslation; + +namespace edcClientDotnet.internalImpl.io +{ + public class HttpReaderImpl : IEdcReader + { + private static readonly String MultiDocFile = "multi-doc.json"; + private static readonly String ContextFile = "context.json"; + private static readonly String InfoFile = "info.json"; + private static readonly String PopoverI18NPath = "i18n/popover/"; + private static readonly String I18NFileExtension = ".json"; + private readonly HttpClientDotnet _httpClientDotnet; + private IClientConfiguration _clientConfiguration { get; } + private readonly IKeyUtil _keyUtil; + private readonly IContextItemFactory _contextItemFactory; + private readonly IDocumentationItemFactory _documentationItemFactory; + private readonly IInformationFactory _informationFactory; + private readonly II18NFactory _i18NFactory; + private readonly static Logger _logger = LogManager.GetCurrentClassLogger(); + + public HttpReaderImpl(HttpClientDotnet httpClientDotnet, IClientConfiguration clientConfigurationService, IKeyUtil keyUtil, IContextItemFactory contextItemFactory, + IDocumentationItemFactory documentationItemFactory, IInformationFactory informationFactory, II18NFactory i18NFactory) + { + _httpClientDotnet = httpClientDotnet; + _clientConfiguration = clientConfigurationService; + _keyUtil = keyUtil; + _contextItemFactory = contextItemFactory; + _documentationItemFactory = documentationItemFactory; + _informationFactory = informationFactory; + _i18NFactory = i18NFactory; + } + + /// + /// + public Dictionary ReadContext() + { + Dictionary contexts = new(); + foreach (var publicationId in ReadPublicationIds()) + { + contexts = ReadContext(publicationId); + } + return contexts; + } + + /// + /// + public Dictionary GetInformations() + { + Dictionary information = new(); + foreach (String publicationId in ReadPublicationIds()) + { + IInformation info = ReadInfoFile(publicationId); + + if (info is not null) + { + information.Add(publicationId, info); + } + } + return information; + } + + /// + /// + private IInformation ReadInfoFile(String publicationId) + { + String infoFileUrl = _clientConfiguration.DocumentationUrl.EndsWith("/") + ? _clientConfiguration.DocumentationUrl + publicationId + "/" + InfoFile + : _clientConfiguration.DocumentationUrl + "/" + publicationId + "/" + InfoFile; + + IInformation information = _informationFactory.Create(); + + try + { + String infoContent = _httpClientDotnet.GetAsyncResponse(infoFileUrl); + JObject jsonContent = JObject.Parse(infoContent); + _logger.Debug("Fetched content from info.json file {}", jsonContent); + + if (jsonContent != null) + { + HashSet languages = new(); + String defaultLangCode = jsonContent["defaultLanguage"]?.Value() != null ? jsonContent["defaultLanguage"].Value() : ParseEnumDescription.GetDescription(DEFAULT_LANGUAGE_CODE); + information.DefaultLanguage = defaultLangCode; + _logger.Debug("Setting default Language from info.json : {}", defaultLangCode); + IList presentLanguage = jsonContent["languages"].Children().ToList(); + + if (presentLanguage != null) + { + foreach (JToken lang in presentLanguage) + { + languages.Add(lang.ToString()); + } + } + _logger.Debug("Setting languages from info.json : {}", languages); + + information.Languages = languages; + } + } + catch (Exception e) + { + _logger.Error("Could not initialize info from info.json for publication id : {}", publicationId, e); + } + finally + { + if (String.IsNullOrEmpty(information.DefaultLanguage)) + { + information.DefaultLanguage = ParseEnumDescription.GetDescription(DEFAULT_LANGUAGE_CODE); + } + if (information.Languages == null || !information.Languages.Any()) + { + HashSet defaultLanguage = new HashSet(); + defaultLanguage.Add(ParseEnumDescription.GetDescription(DEFAULT_LANGUAGE_CODE)); + information.Languages = defaultLanguage; + } + _logger.Debug("Created information from info.json : {}", information); + } + return information; + } + + /// + /// + private HashSet ReadPublicationIds() + { + HashSet publicationIds = new(); + String multiDocUrl = _clientConfiguration.DocumentationUrl.EndsWith("/") + ? _clientConfiguration.DocumentationUrl + MultiDocFile + : _clientConfiguration.DocumentationUrl + "/" + MultiDocFile; + _logger.Info("Multidoc url: {}", multiDocUrl); + + try + { + string? content = _httpClientDotnet.GetAsyncResponse(multiDocUrl); + JArray jsonContent = JArray.Parse(content); + if (jsonContent != null) + { + foreach (JObject value in jsonContent.Children()) + { + string? pluginId = value["pluginId"]?.ToString(); + + if (pluginId != null) + publicationIds.Add(pluginId); + } + } + } + catch (Exception e) + { + throw new IOException(e.Message); + } + return publicationIds; + } + + /// + /// + private Dictionary ReadContext(String publicationId) + { + String urlContext = _clientConfiguration.DocumentationUrl.EndsWith("/") + ? _clientConfiguration.DocumentationUrl + publicationId + "/" + ContextFile + : _clientConfiguration.DocumentationUrl + "/" + publicationId + "/" + ContextFile; + + _logger.Info("Context url: {}", urlContext); + Dictionary contexts = new(); + try + { + String content = _httpClientDotnet.GetAsyncResponse(urlContext); + // Decode Json + JObject jsonContent = JObject.Parse(content); + if (jsonContent != null) + { + _logger.Debug("json Object: {}", jsonContent); + foreach (KeyValuePair entry in jsonContent) + { + ParseContext(contexts, publicationId, entry.Key, entry.Value); + } + } + } + catch (Exception e) + { + _logger.Warn("No context found, the product was not published", e); + } + + return contexts; + } + + private void ParseContext(Dictionary contexts, String publicationId, String mainKey, JToken? jsonElement) + { + _logger.Debug("Decode for main key: {}", mainKey); + foreach (KeyValuePair entry in jsonElement.ToObject()) + { + ParseContext(contexts, publicationId, mainKey, entry.Key, entry.Value); + } + } + + private void ParseContext(Dictionary contexts, String publicationId, String mainKey, String subKey, JToken? jsonElement) + { + _logger.Debug("Decode for sub key: {}", subKey); + foreach (KeyValuePair entry in jsonElement.ToObject()) + { + CreateContext(contexts, publicationId, mainKey, subKey, entry.Key, entry.Value); + } + } + + private void CreateContext(Dictionary contexts, String publicationId, String mainKey, String subKey, String languageCode, JToken? jsonElement) + { + _logger.Debug("Decode for language code: {}", languageCode); + String? description = jsonElement["description"]?.Value(); + IContextItem contextItem = _contextItemFactory.Create(); + contextItem.Label = GetLabel(jsonElement.ToObject()); + contextItem.LanguageCode = languageCode; + contextItem.Url = GetUrl(jsonElement.ToObject()); + contextItem.PublicationId = publicationId; + contextItem.Description = description; + contextItem.MainKey = mainKey; + contextItem.SubKey = subKey; + + CreateArticles(contextItem, jsonElement["articles"].Value(), languageCode); + CreateLinks(contextItem, jsonElement["links"].Value(), languageCode); + contexts.Add(_keyUtil.GetKey(mainKey, subKey, languageCode), contextItem); + } + + private void CreateArticles(IDocumentationItem documentationItem, JArray articles, String languageCode) + { + foreach (JObject articleJson in articles) + { + _logger.Debug("Article to decode: {}", articleJson); + IDocumentationItem article = _documentationItemFactory.Create(); + article.DocumentationItemType = DocumentationItemType.ARTICLE; + article.LanguageCode = languageCode; + article.ObjectId = GetId(articleJson); + article.Label = GetLabel(articleJson); + article.Url = GetUrl(articleJson); + _logger.Debug("new article: {}, id {}, label {}, url {}, documentationItemType {}, articles = [{}], links = [{}]", article, article.ObjectId, article.Label, article.Url, article.DocumentationItemType, article.GetArticles(), article.GetLinks()); + documentationItem.AddArticle(article); + } + } + + private void CreateLinks(IDocumentationItem documentationItem, JArray links, String languageCode) + { + foreach (JObject linkJson in links) + { + _logger.Debug("link to decode: {}", linkJson); + DocumentationItemType linksType = linkJson["type"]?.Value() == "CHAPTER" ? DocumentationItemType.CHAPTER : linkJson["type"]?.Value() == "DOCUMENT" ? DocumentationItemType.DOCUMENT : DocumentationItemType.UNKNOWN; + IDocumentationItem link = _documentationItemFactory.Create(); + link.DocumentationItemType = linksType; + link.LanguageCode = languageCode; + link.ObjectId = GetId(linkJson); + link.Label = GetLabel(linkJson); + link.Url = GetUrl(linkJson); + _logger.Debug("new link: {}", link); + documentationItem.AddLink(link); + } + } + + /// + private String GetLabelUrl(String languageCode) + { + String relativePath = PopoverI18NPath + languageCode + I18NFileExtension; + String i18nLabelUrl = _clientConfiguration.DocumentationUrl.EndsWith("/") + ? _clientConfiguration.DocumentationUrl + relativePath + : _clientConfiguration.DocumentationUrl + "/" + relativePath; + + _logger.Debug("Reading labels for lang {}, url {}, labelUrl {}", languageCode, relativePath, i18nLabelUrl); + + return i18nLabelUrl; + } + + /// + /// + private void ReadI18nContent(String languageCode, II18NContent i18NContent) + { + String label; + String labelUrl = GetLabelUrl(languageCode); + + try + { + label = _httpClientDotnet.GetAsyncResponse(labelUrl); + JObject? jsonContent = JObject.Parse(label); + HashSet labels = new(); + + foreach (KeyValuePair i18nLabelKey in jsonContent) + { + labels.Add(i18nLabelKey.Key); + } + + foreach (String key in labels) + { + Dictionary? dictObj = jsonContent[key]?.ToObject>(); + + foreach (KeyValuePair value in dictObj) + { + i18NContent.SetTranslation(languageCode, key, value.Key, value.Value); + } + } + } + catch (Exception e) + { + _logger.Error("Could not read the labels for the lang {}, err {}", languageCode, e); + } + } + + /// + /// + public II18NContent ReadLabel(HashSet languagesCode) + { + II18NContent i18NContent = _i18NFactory.Create(); + + if (languagesCode != null) + { + foreach (String language in languagesCode) + { + ReadI18nContent(language, i18NContent); + } + } + return i18NContent; + } + + private static string GetLabel(JObject? jsonObject) + { + if (jsonObject != null) + { + return jsonObject["label"]?.Value() ?? string.Empty; + } + return string.Empty; + } + + private static string GetUrl(JObject? jsonObject) + { + if (jsonObject != null) + { + return jsonObject["url"]?.Value() ?? string.Empty; + } + return string.Empty; + } + + private static long GetId(JObject? jsonObject) + { + if (jsonObject != null && jsonObject.ContainsKey("id")) + { + string? idValue = jsonObject["id"]?.Value(); + if (!string.IsNullOrEmpty(idValue)) + { + return int.Parse(idValue); + } + } + return 0; + } + } +} diff --git a/edc-client-dotnet/internalImpl/model/ClientConfigurationImpl.cs b/edc-client-dotnet/internalImpl/model/ClientConfigurationImpl.cs new file mode 100644 index 0000000..32373d1 --- /dev/null +++ b/edc-client-dotnet/internalImpl/model/ClientConfigurationImpl.cs @@ -0,0 +1,58 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.model +{ + public class ClientConfigurationImpl : IClientConfiguration + { + private String _serverUrl; + private String _webHelpContext = "help"; + private String _documentationContext = "doc"; + + public String ServerUrl + { + get => _serverUrl; + set => _serverUrl = value; + } + + public String WebHelpContext + { + get => _webHelpContext; + set + { + if (value == null) + throw new InvalidUrlException("The WebHelp context is null"); + _webHelpContext = value; + } + } + + public String DocumentationContext + { + get => _documentationContext; + set + { + _documentationContext = value ?? throw new InvalidUrlException("The documentation context is null"); + } + } + + public String WebHelpUrl + { + get + { + if (String.IsNullOrEmpty(_serverUrl)) + throw new InvalidUrlException("The server url is not defined"); + + return _serverUrl.EndsWith("/") ? _serverUrl + _webHelpContext : _serverUrl + "/" + _webHelpContext; + } + } + + public String DocumentationUrl + { + get + { + if (String.IsNullOrEmpty(_serverUrl)) + throw new InvalidUrlException("The server url is not defined"); + return _serverUrl.EndsWith("/") ? _serverUrl + _documentationContext : _serverUrl + "/" + _documentationContext; + } + } + } +} diff --git a/edc-client-dotnet/internalImpl/model/ContextItemImpl.cs b/edc-client-dotnet/internalImpl/model/ContextItemImpl.cs new file mode 100644 index 0000000..09b0bd3 --- /dev/null +++ b/edc-client-dotnet/internalImpl/model/ContextItemImpl.cs @@ -0,0 +1,31 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.model +{ + public class ContextItemImpl : DocumentationItemImpl, IContextItem + { + private String _description; + private String _mainKey; + private String _subKey; + + public ContextItemImpl() : base(DocumentationItemType.CONTEXTUAL) { } + + public String Description + { + get => _description; + set => _description = value; + } + + public String MainKey + { + get => _mainKey; + set => _mainKey = value; + } + + public String SubKey + { + get => _subKey; + set => _subKey = value; + } + } +} diff --git a/edc-client-dotnet/internalImpl/model/DocumentationItemImpl.cs b/edc-client-dotnet/internalImpl/model/DocumentationItemImpl.cs new file mode 100644 index 0000000..f70d400 --- /dev/null +++ b/edc-client-dotnet/internalImpl/model/DocumentationItemImpl.cs @@ -0,0 +1,87 @@ +using edcClientDotnet.model; +using System.Collections.ObjectModel; + +namespace edcClientDotnet.internalImpl.model +{ + public class DocumentationItemImpl : ObjectIdImpl, IDocumentationItem + { + private String? _label; + private String? _publicationId; + private String? _url; + private String? _languageCode; + private DocumentationItemType _documentationItemType; + private List _articles = new List(); + private List _links = new List(); + + public DocumentationItemImpl() { } + + public DocumentationItemImpl(DocumentationItemType documentationItemType) + { + _documentationItemType = documentationItemType; + } + + public DocumentationItemType DocumentationItemType + { + get => _documentationItemType; + set => _documentationItemType = value; + } + + public String Label + { + get => _label; + set => _label = value; + } + + public String Url + { + get => _url; + set + { + if (value is not null) + _url = value; + } + } + + public String PublicationId + { + get => _publicationId; + set => _publicationId = value; + } + + public String LanguageCode + { + get => _languageCode; + set => _languageCode = value; + } + + public void AddArticle(IDocumentationItem article) + { + if (article.DocumentationItemType == DocumentationItemType.ARTICLE) + { + _articles.Add(article); + } + } + + ReadOnlyCollection IDocumentationItem.GetArticles() + { + return _articles.AsReadOnly(); + } + + public int ArticleSize() { return _articles.Count(); } + + public void AddLink(IDocumentationItem link) + { + if (link.DocumentationItemType != DocumentationItemType.ARTICLE) + { + _links.Add(link); + } + } + + ReadOnlyCollection IDocumentationItem.GetLinks() + { + return _links.AsReadOnly(); + } + + public int LinkSize() { return _links.Count(); } + } +} diff --git a/edc-client-dotnet/internalImpl/model/I18NContentImpl.cs b/edc-client-dotnet/internalImpl/model/I18NContentImpl.cs new file mode 100644 index 0000000..2ef1df5 --- /dev/null +++ b/edc-client-dotnet/internalImpl/model/I18NContentImpl.cs @@ -0,0 +1,29 @@ +using edcClientDotnet.model; +using NLog; + +namespace edcClientDotnet.internalImpl.model +{ + public class I18NContentImpl : II18NContent + { + private readonly Dictionary _translation = new(); + private readonly static Logger _logger = LogManager.GetCurrentClassLogger(); + + public string GetTranslation(string lang, string type, string key, string publicationId) + { + _logger.Debug("Get the translated content for the lang: {}, type: {}, key: {}, value: {}", lang, type, key); + if(_translation.ContainsKey(lang + "." + type + "." + key)) { + return _translation[lang + "." + type + "." + key]; + } else + { + return null; + } + + } + + public void SetTranslation(string lang, string type, string key, string value) + { + _logger.Debug("Set the translated content for the lang: {}, type: {}, key: {}, value: {}", lang, type, key, value); + _translation.Add(lang + "." + type + "." + key, value); + } + } +} diff --git a/edc-client-dotnet/internalImpl/model/InformationImpl.cs b/edc-client-dotnet/internalImpl/model/InformationImpl.cs new file mode 100644 index 0000000..840972e --- /dev/null +++ b/edc-client-dotnet/internalImpl/model/InformationImpl.cs @@ -0,0 +1,25 @@ +using edcClientDotnet.model; +using edcClientDotnet.utils; +using static edcClientDotnet.model.I18NTranslation; + +namespace edcClientDotnet.internalImpl.model +{ + + public class InformationImpl : IInformation + { + private String _defaultLanguage = ParseEnumDescription.GetDescription(DEFAULT_LANGUAGE_CODE); + private HashSet _languages; + + public String DefaultLanguage + { + get => _defaultLanguage; + set => _defaultLanguage = value; + } + + public HashSet Languages + { + get => _languages; + set => _languages = value; + } + } +} diff --git a/edc-client-dotnet/internalImpl/model/ObjectIdImpl.cs b/edc-client-dotnet/internalImpl/model/ObjectIdImpl.cs new file mode 100644 index 0000000..a39d9e5 --- /dev/null +++ b/edc-client-dotnet/internalImpl/model/ObjectIdImpl.cs @@ -0,0 +1,15 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.internalImpl.model +{ + public class ObjectIdImpl : IObjectId + { + private long _id; + + public long ObjectId + { + get { return _id; } + set { _id = value; } + } + } +} diff --git a/edc-client-dotnet/internalImpl/util/KeyUtilImpl.cs b/edc-client-dotnet/internalImpl/util/KeyUtilImpl.cs new file mode 100644 index 0000000..3c84603 --- /dev/null +++ b/edc-client-dotnet/internalImpl/util/KeyUtilImpl.cs @@ -0,0 +1,18 @@ +using edcClientDotnet.utils; + +namespace edcClientDotnet.internalImpl.util +{ + public class KeyUtilImpl : IKeyUtil + { + public String GetKey(String mainKey, String subKey, String languageCode) + { + return mainKey + "." + subKey + "." + languageCode; + } + + public bool ContainsKey(String fullKey, String mainKey, String subKey) + { + return !String.IsNullOrEmpty(fullKey) && !String.IsNullOrEmpty(mainKey) && !String.IsNullOrEmpty(subKey) && fullKey.Contains(mainKey + "." + subKey); + } + + } +} diff --git a/edc-client-dotnet/internalImpl/util/TranslationUtilImpl.cs b/edc-client-dotnet/internalImpl/util/TranslationUtilImpl.cs new file mode 100644 index 0000000..2aff6c6 --- /dev/null +++ b/edc-client-dotnet/internalImpl/util/TranslationUtilImpl.cs @@ -0,0 +1,40 @@ +using edcClientDotnet.model; +using edcClientDotnet.utils; +using static edcClientDotnet.model.I18NTranslation; + +namespace edcClientDotnet.internalImpl.util +{ + public class TranslationUtilImpl : ITranslationUtil + { + public SortedDictionary GetPublicationDefaultLanguages(SortedDictionary information) + { + SortedDictionary languages = new(); + + foreach(var language in information) + { + languages.Add(language.Key, GetDefaultLanguage(language.Value)); + } + + return languages; + } + + public bool CheckTranslatedLabels(Dictionary labels) + { + + return labels != null && labels.Any() + && TranslationConstants.GetDefaultLabels().ToList().TrueForAll(e => labels.ContainsKey(e.Key)) + && labels.Values.ToList().TrueForAll(e => !String.IsNullOrEmpty(e)); + } + + public bool IsLanguageCodeValid(String languageCode) + { + return TranslationConstants.LANGUAGES_CODES.Contains(languageCode); + } + + private String GetDefaultLanguage(IInformation info) + { + return (info != null && String.IsNullOrEmpty(info.DefaultLanguage)) ? + ParseEnumDescription.GetDescription(DEFAULT_LANGUAGE_CODE) : info.DefaultLanguage; + } + } +} diff --git a/edc-client-dotnet/internalImpl/util/UrlUtilImpl.cs b/edc-client-dotnet/internalImpl/util/UrlUtilImpl.cs new file mode 100644 index 0000000..6a25d34 --- /dev/null +++ b/edc-client-dotnet/internalImpl/util/UrlUtilImpl.cs @@ -0,0 +1,35 @@ +using edcClientDotnet.model; +using edcClientDotnet.utils; + +namespace edcClientDotnet.internalImpl.util +{ + public class UrlUtilImpl : IUrlUtil + { + private IClientConfiguration _clientConfiguration; + + public UrlUtilImpl(IClientConfiguration clientConfiguration) + { + _clientConfiguration = clientConfiguration; + } + + public String GetHomeUrl() { return _clientConfiguration.WebHelpUrl + "/home"; } + + public String GetErrorUrl() { return _clientConfiguration.WebHelpUrl + "/error"; } + + /// + public String GetContextUrl(String publicationId, String mainKey, String subKey, String languageCode, int articleIndex) + { + return _clientConfiguration.WebHelpUrl + "/context/" + publicationId + "/" + mainKey + "/" + subKey + "/" + languageCode + "/" + articleIndex; + } + + /// + public String GetDocumentationUrl(long id, String languageCode, String srcPublicationId) + { + String language = String.IsNullOrEmpty(languageCode) ? "" : "/" + languageCode; + String publicationId = String.IsNullOrEmpty(srcPublicationId) ? "" : srcPublicationId + "/"; + return _clientConfiguration.WebHelpUrl + "/doc/" + publicationId + id + language; + } + + + } +} diff --git a/edc-client-dotnet/io/IEdcReader.cs b/edc-client-dotnet/io/IEdcReader.cs new file mode 100644 index 0000000..e8b91d4 --- /dev/null +++ b/edc-client-dotnet/io/IEdcReader.cs @@ -0,0 +1,34 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.io +{ + public interface IEdcReader + { + /// + /// Read all context items and associate it in the Dictionary. + /// The key of the Dictionary is the contextual key and he value is the associated context. + /// + /// a dictionary which associate the contextual key with the content item. + /// if an IO error occurred during the read + /// if the url is malformed + Dictionary ReadContext(); + + /// + /// Read the export information, for every publication, from the info.json files + /// The key of the returned dictionary is the publication id and the value the associated information object + /// + /// a dictionary containing the keys and label translations associated + /// if an IO error occurred during the read + /// if the url is malformed + Dictionary GetInformations(); + + /// + /// Read the translated popover label for the given language code + /// + /// + /// an object + /// + /// + II18NContent ReadLabel(HashSet languagesCodes); + } +} diff --git a/edc-client-dotnet/model/DocumentationItemType.cs b/edc-client-dotnet/model/DocumentationItemType.cs new file mode 100644 index 0000000..a0e1366 --- /dev/null +++ b/edc-client-dotnet/model/DocumentationItemType.cs @@ -0,0 +1,30 @@ +namespace edcClientDotnet.model +{ + public enum DocumentationItemType + { + /// + /// Unknown documentation item type + /// + UNKNOWN, + + /// + /// Chapter documentation type. This is a documentation item which can contain DOCUMENT and CONTEXTUEL documentation item. + /// + CHAPTER, + + /// + /// Contextual documentation item type ie bricks. It can contain ARTICLE documentation type + /// + CONTEXTUAL, + + /// + /// Document documentation item type.It can contain ARTICLE documentation type + /// + DOCUMENT, + + /// + /// Article documentation item type. it can't contain anything. + /// + ARTICLE + } +} diff --git a/edc-client-dotnet/model/I18NTranslation.cs b/edc-client-dotnet/model/I18NTranslation.cs new file mode 100644 index 0000000..0a030f3 --- /dev/null +++ b/edc-client-dotnet/model/I18NTranslation.cs @@ -0,0 +1,55 @@ +using System.ComponentModel; + +namespace edcClientDotnet.model +{ + public enum I18NTranslation + { + /// + /// I18N Default language code + /// + [Description("en")] + DEFAULT_LANGUAGE_CODE, + + /// + /// I18N Labels + /// + [Description("labels")] + I18N_LABELS_ROOT, + + /// + /// I18N Errors + /// + [Description("errors")] + I18N_ERRORS_ROOT, + + /// + /// I18N Articles + /// + [Description("articles")] + ARTICLES_KEY, + + /// + /// I18N Links + /// + [Description("links")] + LINKS_KEY, + + /// + /// I18N ComingSoon + /// + [Description("comingSoon")] + COMING_SOON_KEY, + + /// + /// I18N Error title + /// + [Description("errorTitle")] + ERROR_TITLE_KEY, + + /// + /// I18N Failed data + /// + [Description("failedData")] + ERRORS_KEY + } +} diff --git a/edc-client-dotnet/model/IClientConfiguration.cs b/edc-client-dotnet/model/IClientConfiguration.cs new file mode 100644 index 0000000..077b1a7 --- /dev/null +++ b/edc-client-dotnet/model/IClientConfiguration.cs @@ -0,0 +1,43 @@ +namespace edcClientDotnet.model +{ + public interface IClientConfiguration + { + /// + /// GET: Return the server url without context. + /// SET: Define the server url like http:/localhost:8080/. + /// The url is just the protocol, the host and the port. + /// + /// the server url + String ServerUrl { get; set; } + /// + /// GET: Return the WebHelp context. + /// This is the context to use the WebHelp application. The default value is "help". + /// SET: Define the WebHelp context. + /// + /// the WebHelp context + /// if the context is null + String WebHelpContext { get; set; } + + /// + /// Return the documentation context. + /// This is the context to use to read the documentation (edc export). The default value is doc. + /// SET: Define the documentation context. + /// + /// the documentation context + String DocumentationContext { get; set; } + + /// + /// Generate the WebHelp url bases on server url and its context. + /// + /// the WebHelp url + /// if the url is malformed + String WebHelpUrl { get; } + + /// + /// Generate the documentation url based on server url and its context. + /// + /// the documentation url + /// if the url is malformed + String DocumentationUrl { get; } + } +} diff --git a/edc-client-dotnet/model/IContextItem.cs b/edc-client-dotnet/model/IContextItem.cs new file mode 100644 index 0000000..7628564 --- /dev/null +++ b/edc-client-dotnet/model/IContextItem.cs @@ -0,0 +1,27 @@ +namespace edcClientDotnet.model +{ + // This class is a specialized DocumentationItem for the contextual content (bricks) + public interface IContextItem : IDocumentationItem + { + /// + /// GET: Return the description. + /// SET: Define the description + /// + /// the description + String Description { get; set; } + + /// + /// Return the main key pluginId, package, other, ... + /// SET: Define the main key + /// + /// the main key + String MainKey { get; set; } + + /// + /// GET: Return the secondary key (id of the brick) + /// SET: Define the secondary key + /// + /// the secondary key + String SubKey { get; set; } + } +} diff --git a/edc-client-dotnet/model/IDocumentationItem.cs b/edc-client-dotnet/model/IDocumentationItem.cs new file mode 100644 index 0000000..50c4684 --- /dev/null +++ b/edc-client-dotnet/model/IDocumentationItem.cs @@ -0,0 +1,85 @@ +using System.Collections.ObjectModel; + +namespace edcClientDotnet.model +{ + /// This class define a documentation component. + public interface IDocumentationItem : IObjectId + { + /// + /// GET: Return the label + /// SET: Define the label + /// + /// the label + String Label { get; set; } + + /// + /// GET: Return the url defined the configuration file (read from a documentation definition). + /// It's the real path on the documentation server + /// SET: Define the label + /// It's the real path on the documentation server. + /// + /// the url + String Url { get; set; } + + /// + /// GET: The publication id. + /// SET: Define the publication id + /// + /// the publicationId + String PublicationId { get; set; } + + /// + /// GET: Return the language code of this documentation. The code is defined by 2 digits in lowercase. + /// SET: Define the language code of this documentation. The code is defined by 2 digits in lowercase. + /// + /// the language code + String LanguageCode { get; set; } + + /// + /// GET: Return the documentation type. + /// SET: Define the documentation type + /// + /// the documentation type + DocumentationItemType DocumentationItemType { get; set; } + + /// + /// Add a documentation item as article. + /// Only {@link DocumentationItemType#ARTICLE} is accepted. + /// + /// the article to add + void AddArticle(IDocumentationItem article); + + /// + /// Return the list of articles. + /// This list is unmodifiable. + /// + /// the list of articles + ReadOnlyCollection GetArticles(); + + /// + /// Return the number of articles contained by this DocumentationItem + /// + /// the number of articles + int ArticleSize(); + + /// + /// Add a documentation item as link. + /// All is accepted excepted {@link DocumentationItemType}. + /// + /// the link to add + void AddLink(IDocumentationItem link); + + /// + /// Return the list of links. + /// This list is unmodifiable. + /// + /// the list of links + ReadOnlyCollection GetLinks(); + + /// + /// Return the number of links contained by this DocumentationItem + /// + /// the number of links + int LinkSize(); + } +} \ No newline at end of file diff --git a/edc-client-dotnet/model/II18NContent.cs b/edc-client-dotnet/model/II18NContent.cs new file mode 100644 index 0000000..898c0a9 --- /dev/null +++ b/edc-client-dotnet/model/II18NContent.cs @@ -0,0 +1,24 @@ +namespace edcClientDotnet.model +{ + public interface II18NContent + { + /// + /// Return I18n translation built with the lang and key + /// + /// the lang i18n translation + /// the label type + /// the label key + /// the publication id + /// translation + String GetTranslation(String lang, String type, String key, String publicationId); + + /// + /// Set content to build key + /// + /// + /// + /// + /// + void SetTranslation(String lang, String type, String key, String value); + } +} diff --git a/edc-client-dotnet/model/IInformation.cs b/edc-client-dotnet/model/IInformation.cs new file mode 100644 index 0000000..4a5eb82 --- /dev/null +++ b/edc-client-dotnet/model/IInformation.cs @@ -0,0 +1,10 @@ +namespace edcClientDotnet.model +{ + // This component define the information about the documentation (version, label, ...) + public interface IInformation + { + String DefaultLanguage { get; set; } + + HashSet Languages { get; set; } + } +} diff --git a/edc-client-dotnet/model/IObjectId.cs b/edc-client-dotnet/model/IObjectId.cs new file mode 100644 index 0000000..37d29d2 --- /dev/null +++ b/edc-client-dotnet/model/IObjectId.cs @@ -0,0 +1,7 @@ +namespace edcClientDotnet.model +{ + public interface IObjectId + { + long ObjectId{ get; set; } + } +} diff --git a/edc-client-dotnet/model/InvalidUrlException.cs b/edc-client-dotnet/model/InvalidUrlException.cs new file mode 100644 index 0000000..9f25289 --- /dev/null +++ b/edc-client-dotnet/model/InvalidUrlException.cs @@ -0,0 +1,8 @@ +namespace edcClientDotnet.model +{ + public class InvalidUrlException : Exception + { + public InvalidUrlException(String message) : base(message) { } + + } +} diff --git a/edc-client-dotnet/utils/IKeyUtil.cs b/edc-client-dotnet/utils/IKeyUtil.cs new file mode 100644 index 0000000..d6da6f1 --- /dev/null +++ b/edc-client-dotnet/utils/IKeyUtil.cs @@ -0,0 +1,23 @@ +namespace edcClientDotnet.utils +{ + public interface IKeyUtil + { + /// + /// Build the key according to the main, sub key and the language code. + /// + /// + /// + /// + /// the key + String GetKey(String mainKey, String subKey, String languageCode); + + /// + /// Check if the full key contains the main and subKey + /// + /// the full key, containing keys and language code + /// a main key + /// a sub key + /// returns true if mainKey.subKey is present for any language + Boolean ContainsKey(String fullKey, String mainKey, String subKey); + } +} diff --git a/edc-client-dotnet/utils/ITranslationUtil.cs b/edc-client-dotnet/utils/ITranslationUtil.cs new file mode 100644 index 0000000..d56335c --- /dev/null +++ b/edc-client-dotnet/utils/ITranslationUtil.cs @@ -0,0 +1,30 @@ +using edcClientDotnet.model; + +namespace edcClientDotnet.utils +{ + public interface ITranslationUtil + { + /// + /// Return a Dictionary of default languages by publication id + /// + /// the Dictionary containing the publication id as key and information as value + /// a Dictionary of publication id as key and default content language code as value + SortedDictionary GetPublicationDefaultLanguages(SortedDictionary information); + + /// + /// Check labels consistency + /// Labels must contain all the keys present in default language labels + /// And their values must not be empty + /// + /// the labels to check + /// true if labels are valid + Boolean CheckTranslatedLabels(Dictionary labels); + + /// + /// Return true if given language code is present in the list of the codes used in the application + /// + /// the language code to check + /// true if code is present + Boolean IsLanguageCodeValid(String languageCode); + } +} diff --git a/edc-client-dotnet/utils/IUrlUtil.cs b/edc-client-dotnet/utils/IUrlUtil.cs new file mode 100644 index 0000000..3ae3340 --- /dev/null +++ b/edc-client-dotnet/utils/IUrlUtil.cs @@ -0,0 +1,41 @@ +namespace edcClientDotnet.utils +{ + public interface IUrlUtil + { + /// + /// Return the home url for the help client + /// + /// the home url + /// If the base url is not defined + String GetHomeUrl(); + + /// + /// Return the error url for the help client + /// + /// the home url + /// If the base url is not defined + String GetErrorUrl(); + + /// + /// Build the web help context url for the brick defined with the keys, the language and the index of the article to display + /// + /// the identifier of the publication + /// the main key + /// the sub key + /// the language code + /// the article index to display + /// the url + /// If the url is malformed + String GetContextUrl(String publicationId, String mainKey, String subKey, String languageCode, int articleIndex); + + /// + /// Build the web help documentation url for the document defined by the identifier, the language code, and the publication identifier if present + /// + /// the idenitifer of the documentation + /// the 2 letters code of the language (en, fr..) + /// the identifier of the publication from where navigation will start + /// the url + /// If the url is malformed + String GetDocumentationUrl(long id, String languageCode, String srcPublicationId); + } +} diff --git a/edc-client-dotnet/utils/ParseEnumDescription.cs b/edc-client-dotnet/utils/ParseEnumDescription.cs new file mode 100644 index 0000000..6af8bca --- /dev/null +++ b/edc-client-dotnet/utils/ParseEnumDescription.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; +using System.Reflection; + +namespace edcClientDotnet.utils +{ + public static class ParseEnumDescription + { + public static String GetDescription(Enum e) + { + var attribute = + e.GetType() + .GetTypeInfo() + .GetMember(e.ToString()) + .FirstOrDefault(member => member.MemberType == MemberTypes.Field) + .GetCustomAttributes(typeof(DescriptionAttribute), false) + .SingleOrDefault() + as DescriptionAttribute; + + return attribute?.Description ?? e.ToString(); + } + } +}