From 0588bbcf52c2890ac72ec47ff8d8b8eed6e9252a Mon Sep 17 00:00:00 2001 From: Inna Boitsun Date: Thu, 18 May 2023 10:32:53 +0300 Subject: [PATCH 1/2] Update BreadcrumbViewService to use sitemapnavigator to be able to render fallback language page urls AB#71774 --- .../Controllers/HeaderBaseController.cs | 21 ++++---- .../Services/BreadcrumbViewService.cs | 49 +++++++++++-------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/Orckestra.Composer.CompositeC1/Controllers/HeaderBaseController.cs b/src/Orckestra.Composer.CompositeC1/Controllers/HeaderBaseController.cs index 682f53d0a..4feafb651 100644 --- a/src/Orckestra.Composer.CompositeC1/Controllers/HeaderBaseController.cs +++ b/src/Orckestra.Composer.CompositeC1/Controllers/HeaderBaseController.cs @@ -26,17 +26,20 @@ protected HeaderBaseController( public virtual ActionResult PageHeader() { - var page = PageService.GetPage(SitemapNavigator.CurrentPageId); - var canonicalUrl = page != null ? UrlUtils.ToAbsolute(PageService.GetPageUrl(page.Id)) : string.Empty; - - var pageHeaderViewModel = new PageHeaderViewModel + using (var connection = new DataConnection()) { - PageTitle = page.Title, - NoIndex = string.IsNullOrWhiteSpace(canonicalUrl), - CanonicalUrl = canonicalUrl - }; + var currentPageNode = connection.SitemapNavigator.CurrentPageNode; + var pageUrl = currentPageNode?.Url; + var canonicalUrl = !string.IsNullOrEmpty(pageUrl) ? UrlUtils.ToAbsolute(pageUrl) : string.Empty; + var pageHeaderViewModel = new PageHeaderViewModel + { + PageTitle = currentPageNode?.Title, + NoIndex = string.IsNullOrWhiteSpace(canonicalUrl), + CanonicalUrl = canonicalUrl + }; - return View("PageHeader", pageHeaderViewModel); + return View("PageHeader", pageHeaderViewModel); + } } protected virtual bool IsPageIndexed() diff --git a/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs b/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs index 37e2d4b78..f332653c9 100644 --- a/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs +++ b/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Web; +using Composite.Data; using Composite.Data.Types; using Orckestra.Composer.Services.Breadcrumb; using Orckestra.Composer.ViewModels.Breadcrumb; @@ -25,48 +27,53 @@ public virtual BreadcrumbViewModel CreateBreadcrumbViewModel(GetBreadcrumbParam if (param == null) { throw new ArgumentNullException(nameof(param)); } var pageId = new Guid(param.CurrentPageId); - var page = _pageService.GetPage(pageId, param.CultureInfo) ?? - throw new InvalidOperationException("Could not find any page matching this ID."); - - var breadcrumbViewModel = new BreadcrumbViewModel + using (var connection = new DataConnection(param.CultureInfo)) { - ActivePageName = HttpUtility.HtmlEncode(page.MenuTitle), - Items = CreateBreadcrumbItems(param, page) - }; - - return breadcrumbViewModel; + var page = connection.SitemapNavigator.GetPageNodeById(pageId) ?? throw new InvalidOperationException("Could not find any page matching this ID."); ; + var breadcrumbViewModel = new BreadcrumbViewModel + { + ActivePageName = HttpUtility.HtmlEncode(page.MenuTitle), + Items = CreateBreadcrumbItems(param, page, connection) + }; + return breadcrumbViewModel; + } } - protected virtual List CreateBreadcrumbItems(GetBreadcrumbParam param, IPage page) + protected virtual List CreateBreadcrumbItems(GetBreadcrumbParam param, PageNode page, DataConnection connection) { var breadcrumbStack = new Stack(); - var parentPageId = _pageService.GetParentPageId(page); + var parentPageId = page.ParentPage?.Id ?? Guid.Empty; while (parentPageId != Guid.Empty) { - var parentPage = _pageService.GetPage(parentPageId, param.CultureInfo); - - var itemVM = CreateParentPageItem(parentPage); - breadcrumbStack.Push(itemVM); - - parentPageId = _pageService.GetParentPageId(parentPage); + var parentPage = connection.SitemapNavigator.GetPageNodeById(parentPageId); + if (parentPage != null) + { + var itemVM = CreateBreadcrumbItemViewModel(parentPage); + breadcrumbStack.Push(itemVM); + parentPageId = parentPage.ParentPage?.Id ?? Guid.Empty; + } + else + { + parentPageId = Guid.Empty; + } } var items = UnrollStack(breadcrumbStack).ToList(); return items; } - protected virtual BreadcrumbItemViewModel CreateParentPageItem(IPage parentPage) + protected virtual BreadcrumbItemViewModel CreateBreadcrumbItemViewModel(PageNode page) { var itemVM = new BreadcrumbItemViewModel { - DisplayName = parentPage.MenuTitle + DisplayName = page.MenuTitle }; var pagesConfiguration = SiteConfiguration.GetPagesConfiguration(); - if (pagesConfiguration!= null && parentPage.PageTypeId != pagesConfiguration.FolderId) + if (pagesConfiguration != null && page.Page.PageTypeId != pagesConfiguration.FolderId) { - itemVM.Url = _pageService.GetPageUrl(parentPage); + itemVM.Url = page.Url; } return itemVM; From a801ec830e44ff3bd41af8dfae5ca7d4d6a2340b Mon Sep 17 00:00:00 2001 From: Inna Boitsun Date: Fri, 19 May 2023 10:26:09 +0300 Subject: [PATCH 2/2] fix unit tests --- .../Orckestra.Composer.CompositeC1.csproj | 2 + src/Orckestra.Composer.CompositeC1/Plugin.cs | 1 + .../Services/BreadcrumbViewService.cs | 12 +++--- .../Services/DataConnectionService.cs | 41 +++++++++++++++++++ .../Services/IDataConnectionService.cs | 10 +++++ .../Mocks/DataConnectionServiceMock.cs | 41 +++++++++++++++++++ ...rckestra.Composer.CompositeC1.Tests.csproj | 3 +- ...mbViewService_CreateBreadcrumbViewModel.cs | 7 ++-- 8 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 src/Orckestra.Composer.CompositeC1/Services/DataConnectionService.cs create mode 100644 src/Orckestra.Composer.CompositeC1/Services/IDataConnectionService.cs create mode 100644 tests/Orckestra.Composer.CompositeC1.Tests/Mocks/DataConnectionServiceMock.cs diff --git a/src/Orckestra.Composer.CompositeC1/Orckestra.Composer.CompositeC1.csproj b/src/Orckestra.Composer.CompositeC1/Orckestra.Composer.CompositeC1.csproj index 528c7edaf..bd630adb0 100644 --- a/src/Orckestra.Composer.CompositeC1/Orckestra.Composer.CompositeC1.csproj +++ b/src/Orckestra.Composer.CompositeC1/Orckestra.Composer.CompositeC1.csproj @@ -250,6 +250,8 @@ + + diff --git a/src/Orckestra.Composer.CompositeC1/Plugin.cs b/src/Orckestra.Composer.CompositeC1/Plugin.cs index 04ef361a9..cb9a0903b 100644 --- a/src/Orckestra.Composer.CompositeC1/Plugin.cs +++ b/src/Orckestra.Composer.CompositeC1/Plugin.cs @@ -56,6 +56,7 @@ private void RegisterDependencies(IComposerHost host) host.Register(ComponentLifestyle.Singleton); host.Register(); host.Register(); + host.Register(ComponentLifestyle.Singleton); host.Register(); host.Register(); diff --git a/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs b/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs index f332653c9..b99c85cc1 100644 --- a/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs +++ b/src/Orckestra.Composer.CompositeC1/Services/BreadcrumbViewService.cs @@ -15,11 +15,13 @@ public class BreadcrumbViewService : IBreadcrumbViewService { protected IPageService _pageService; protected ISiteConfiguration SiteConfiguration { get; private set; } + protected IDataConnectionService DataConnectionService { get; private set; } - public BreadcrumbViewService(IPageService pageService, ISiteConfiguration siteConfiguration) + public BreadcrumbViewService(IPageService pageService, ISiteConfiguration siteConfiguration, IDataConnectionService dataConnectionService) { _pageService = pageService ?? throw new ArgumentNullException(nameof(pageService)); SiteConfiguration = siteConfiguration; + DataConnectionService = dataConnectionService; } public virtual BreadcrumbViewModel CreateBreadcrumbViewModel(GetBreadcrumbParam param) @@ -27,9 +29,9 @@ public virtual BreadcrumbViewModel CreateBreadcrumbViewModel(GetBreadcrumbParam if (param == null) { throw new ArgumentNullException(nameof(param)); } var pageId = new Guid(param.CurrentPageId); - using (var connection = new DataConnection(param.CultureInfo)) + using (var connection = DataConnectionService.GetDataConnection(param.CultureInfo)) { - var page = connection.SitemapNavigator.GetPageNodeById(pageId) ?? throw new InvalidOperationException("Could not find any page matching this ID."); ; + var page = connection.GetPageNodeById(pageId) ?? throw new InvalidOperationException("Could not find any page matching this ID."); ; var breadcrumbViewModel = new BreadcrumbViewModel { ActivePageName = HttpUtility.HtmlEncode(page.MenuTitle), @@ -39,14 +41,14 @@ public virtual BreadcrumbViewModel CreateBreadcrumbViewModel(GetBreadcrumbParam } } - protected virtual List CreateBreadcrumbItems(GetBreadcrumbParam param, PageNode page, DataConnection connection) + protected virtual List CreateBreadcrumbItems(GetBreadcrumbParam param, PageNode page, IDataConnectionAdapter connection) { var breadcrumbStack = new Stack(); var parentPageId = page.ParentPage?.Id ?? Guid.Empty; while (parentPageId != Guid.Empty) { - var parentPage = connection.SitemapNavigator.GetPageNodeById(parentPageId); + var parentPage = connection.GetPageNodeById(parentPageId); if (parentPage != null) { var itemVM = CreateBreadcrumbItemViewModel(parentPage); diff --git a/src/Orckestra.Composer.CompositeC1/Services/DataConnectionService.cs b/src/Orckestra.Composer.CompositeC1/Services/DataConnectionService.cs new file mode 100644 index 000000000..9a7188a5d --- /dev/null +++ b/src/Orckestra.Composer.CompositeC1/Services/DataConnectionService.cs @@ -0,0 +1,41 @@ +using Composite.Data; +using System; +using System.Globalization; + +namespace Orckestra.Composer.CompositeC1.Services +{ + public class DataConnectionService: IDataConnectionService + { + public IDataConnectionAdapter GetDataConnection(CultureInfo culture) + { + return new DataConnectionAdapter(culture); + } + } + + public interface IDataConnectionAdapter : IDisposable + { + SitemapNavigator SitemapNavigator { get; } + PageNode GetPageNodeById(Guid id); + } + + public class DataConnectionAdapter : IDataConnectionAdapter + { + private readonly DataConnection _dataConnection; + public DataConnectionAdapter(CultureInfo culture) + { + _dataConnection = new DataConnection(culture); + } + + public virtual SitemapNavigator SitemapNavigator => _dataConnection.SitemapNavigator; + + public virtual PageNode GetPageNodeById(Guid id) + { + return SitemapNavigator.GetPageNodeById(id); + } + + public void Dispose() + { + _dataConnection.Dispose(); + } + } +} diff --git a/src/Orckestra.Composer.CompositeC1/Services/IDataConnectionService.cs b/src/Orckestra.Composer.CompositeC1/Services/IDataConnectionService.cs new file mode 100644 index 000000000..0ffbef6ed --- /dev/null +++ b/src/Orckestra.Composer.CompositeC1/Services/IDataConnectionService.cs @@ -0,0 +1,10 @@ +using Composite.Data; +using System.Globalization; + +namespace Orckestra.Composer.CompositeC1.Services +{ + public interface IDataConnectionService + { + IDataConnectionAdapter GetDataConnection(CultureInfo cultore); + } +} diff --git a/tests/Orckestra.Composer.CompositeC1.Tests/Mocks/DataConnectionServiceMock.cs b/tests/Orckestra.Composer.CompositeC1.Tests/Mocks/DataConnectionServiceMock.cs new file mode 100644 index 000000000..3609db90c --- /dev/null +++ b/tests/Orckestra.Composer.CompositeC1.Tests/Mocks/DataConnectionServiceMock.cs @@ -0,0 +1,41 @@ +using Composite.Core.Implementation; +using Composite.Data; +using Composite.Data.Types; +using Moq; +using Orckestra.Composer.CompositeC1.Services; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace Orckestra.Composer.CompositeC1.Tests.Mocks +{ + public class DataConnectionServiceMock : IDataConnectionService + { + private readonly IEnumerable _pagesSource; + public DataConnectionServiceMock(IEnumerable pagesSource) + { + _pagesSource = pagesSource; + } + + public IDataConnectionAdapter GetDataConnection(CultureInfo culture) + { + var mockDC = new Mock(); + var navigator = new Mock(); + mockDC.Setup(sm => sm.GetPageNodeById(It.IsAny())).Returns((id) => + { + var page = _pagesSource.FirstOrDefault(p => p.Id == id) as PageMock; + if (page == null) return null; + var parentPage = _pagesSource.FirstOrDefault(p => page.ParentPageId == p.Id) as PageMock; + var parentPageNode = parentPage != null ? new PageNode(parentPage, navigator.Object) : null; + var pageNodeMock = new Mock(page, navigator.Object); + pageNodeMock.SetupGet(p => p.ParentPage).Returns(parentPageNode); + pageNodeMock.SetupGet(p => p.Page).Returns(page); + pageNodeMock.SetupGet(p => p.MenuTitle).Returns(page.MenuTitle); + pageNodeMock.SetupGet(p => p.Url).Returns(page.Url); + return pageNodeMock.Object; + }); + return mockDC.Object; + } + } +} diff --git a/tests/Orckestra.Composer.CompositeC1.Tests/Orckestra.Composer.CompositeC1.Tests.csproj b/tests/Orckestra.Composer.CompositeC1.Tests/Orckestra.Composer.CompositeC1.Tests.csproj index 8ebc0f5a6..862a7e913 100644 --- a/tests/Orckestra.Composer.CompositeC1.Tests/Orckestra.Composer.CompositeC1.Tests.csproj +++ b/tests/Orckestra.Composer.CompositeC1.Tests/Orckestra.Composer.CompositeC1.Tests.csproj @@ -84,7 +84,7 @@ ..\..\packages\C1CMS.Assemblies.6.12.8122.18346\lib\net471\Microsoft.Practices.EnterpriseLibrary.Common.dll - False + True ..\..\packages\C1CMS.Assemblies.6.12.8122.18346\lib\net471\Microsoft.Practices.EnterpriseLibrary.Logging.dll @@ -178,6 +178,7 @@ + diff --git a/tests/Orckestra.Composer.CompositeC1.Tests/Services/BreadcrumbViewService/BreadcrumbViewService_CreateBreadcrumbViewModel.cs b/tests/Orckestra.Composer.CompositeC1.Tests/Services/BreadcrumbViewService/BreadcrumbViewService_CreateBreadcrumbViewModel.cs index b79c25c61..22d554b66 100644 --- a/tests/Orckestra.Composer.CompositeC1.Tests/Services/BreadcrumbViewService/BreadcrumbViewService_CreateBreadcrumbViewModel.cs +++ b/tests/Orckestra.Composer.CompositeC1.Tests/Services/BreadcrumbViewService/BreadcrumbViewService_CreateBreadcrumbViewModel.cs @@ -7,14 +7,12 @@ using Orckestra.Composer.CompositeC1.Services; using Orckestra.Composer.CompositeC1.Tests.Mocks; using Orckestra.Composer.Services.Breadcrumb; +using Orckestra.Composer.ViewModels.Breadcrumb; using Orckestra.ExperienceManagement.Configuration; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using static Orckestra.Composer.Utils.MessagesHelper.ArgumentException; -using static Orckestra.Composer.Utils.ExpressionUtility; -using Orckestra.Composer.ViewModels.Breadcrumb; using System.Linq.Expressions; namespace Orckestra.Composer.CompositeC1.Tests.Services.BreadcrumbViewService @@ -51,7 +49,10 @@ public void SetUp() var dataSource = BuildPageDataSource(contentPageId); var pageServiceMock = new PageServiceMock(dataSource); + + var dataConnectionServiceMcok = new DataConnectionServiceMock(dataSource); Container.Use(pageServiceMock); + Container.Use(dataConnectionServiceMcok); var mockedSiteConfiguration = new Mock();