diff --git a/dxa.net/NuGet/Sdl.ECommerce.Dxa.nuspec b/dxa.net/NuGet/Sdl.ECommerce.Dxa.nuspec index a3fe694..5d4408e 100644 --- a/dxa.net/NuGet/Sdl.ECommerce.Dxa.nuspec +++ b/dxa.net/NuGet/Sdl.ECommerce.Dxa.nuspec @@ -15,11 +15,11 @@ + - diff --git a/dxa.net/NuGet/Sdl.ECommerce.Formatting.nuspec b/dxa.net/NuGet/Sdl.ECommerce.Formatting.nuspec new file mode 100644 index 0000000..a0eae5b --- /dev/null +++ b/dxa.net/NuGet/Sdl.ECommerce.Formatting.nuspec @@ -0,0 +1,17 @@ + + + + Sdl.ECommerce.Formatting + 1.2.0 + Sdl + Sdl + + false + Sdl ECommerce Formatting. + + © Sdl 2018 + + + + + \ No newline at end of file diff --git a/dxa.net/NuGet/nuget.ps1 b/dxa.net/NuGet/nuget.ps1 index 3acfc82..53cbeae 100644 --- a/dxa.net/NuGet/nuget.ps1 +++ b/dxa.net/NuGet/nuget.ps1 @@ -16,7 +16,10 @@ Param( [string]$exampleViewsVersion = "0.0.1", [Parameter(Mandatory=$false, HelpMessage="Sdl.Dxa.Modules.Navigation version.")] - [string]$modulesNavigationVersion = "0.0.1" + [string]$modulesNavigationVersion = "0.0.1", + + [Parameter(Mandatory=$false, HelpMessage="Sdl.ECommerce.Formatting version.")] + [string]$formattingVersion = "0.0.1" ) $ErrorActionPreference = 'Stop'; @@ -43,4 +46,5 @@ $nuGetFile = Get-ChildItem -Path (Join-Path $PSScriptRoot "packages") -Filter "n & $nuGetFile.FullName pack 'Sdl.ECommerce.Dxa.nuspec' -version $dxaVersion -basepath $basePath -outputdirectory $outputDirectory & $nuGetFile.FullName pack 'Sdl.ECommerce.Example.Views.nuspec' -version $exampleViewsVersion -basepath $basePath -outputdirectory $outputDirectory -& $nuGetFile.FullName pack 'Sdl.Dxa.Modules.Navigation.nuspec' -version $modulesNavigationVersion -basepath $basePath -outputdirectory $outputDirectory \ No newline at end of file +& $nuGetFile.FullName pack 'Sdl.Dxa.Modules.Navigation.nuspec' -version $modulesNavigationVersion -basepath $basePath -outputdirectory $outputDirectory +& $nuGetFile.FullName pack 'Sdl.ECommerce.Formatting.nuspec' -version $formattingVersion -basepath $basePath -outputdirectory $outputDirectory \ No newline at end of file diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Api/Model/ICategory.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Api/Model/ICategory.cs index e0acafc..b136ef1 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Api/Model/ICategory.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Api/Model/ICategory.cs @@ -32,5 +32,10 @@ public interface ICategory /// Get the category's path name which can based on the name of the category. /// string PathName { get; } + + /// + /// Get the category's sanitized path name which can based on the name of the category. + /// + string SanitizedPathName { get; } } } diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.DXA/ECommerceContext.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.DXA/ECommerceContext.cs index 73eb1d9..24e49b1 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.DXA/ECommerceContext.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.DXA/ECommerceContext.cs @@ -33,6 +33,7 @@ public class ECommerceContext private static readonly IDictionary clients = new ConcurrentDictionary(); private const int DEFAULT_CATEGORY_EXPIRY_TIMEOUT = 3600000; + private const bool DEFAULT_CATEGORY_USE_SANITIZED_PATHNAMES = false; /// @@ -82,16 +83,18 @@ private static IECommerceClient Create(string locale) var clientType = WebConfigurationManager.AppSettings["ecommerce-service-client-type"] ?? "odata"; var categoryExpiryTimeoutStr = WebConfigurationManager.AppSettings["ecommerce-category-expiry-timeout"]; int categoryExpiryTimeout = categoryExpiryTimeoutStr != null ? int.Parse(categoryExpiryTimeoutStr) : DEFAULT_CATEGORY_EXPIRY_TIMEOUT; + var useSanitizedPathNamesStr = WebConfigurationManager.AppSettings["ecommerce-category-use-sanitized-pathnames"]; + bool useSanitizedPathNames = useSanitizedPathNamesStr != null ? bool.Parse(useSanitizedPathNamesStr) : DEFAULT_CATEGORY_USE_SANITIZED_PATHNAMES; if (clientType.Equals("odata")) { // TODO: Get token service data here as well - return new OData.ECommerceClient(endpointAddress, locale, DependencyResolver.Current.GetService); + return new OData.ECommerceClient(endpointAddress, locale, useSanitizedPathNames, DependencyResolver.Current.GetService); } if (clientType.Equals("rest")) { - return new ECommerceClient(endpointAddress, locale, new DXACacheProvider(locale), categoryExpiryTimeout, DependencyResolver.Current.GetService); + return new ECommerceClient(endpointAddress, locale, new DXACacheProvider(locale), categoryExpiryTimeout, useSanitizedPathNames, DependencyResolver.Current.GetService); } throw new DxaException("Invalid client type configured for the E-Commerce service: " + clientType); diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Formatting/SDL.ECommerce.Formatting.csproj b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Formatting/SDL.ECommerce.Formatting.csproj index ca59af3..0329834 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Formatting/SDL.ECommerce.Formatting.csproj +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Formatting/SDL.ECommerce.Formatting.csproj @@ -9,7 +9,7 @@ Properties SDL.ECommerce.Formatting SDL.ECommerce.Formatting - v4.5.2 + v4.5 512 true diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/ECommerceClient.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/ECommerceClient.cs index b58710a..dc38119 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/ECommerceClient.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/ECommerceClient.cs @@ -68,6 +68,7 @@ public class ECommerceClient : IECommerceClient private IProductDetailService detailService; private ICartService cartService; private IEditService editService; + private readonly bool useSanitizedPathNames; /// /// Constructor @@ -77,7 +78,8 @@ public class ECommerceClient : IECommerceClient /// Optional list of dependencies. public ECommerceClient( string endpointAddress, - string locale, + string locale, + bool useSanitizedPathNames, Func dependencies = null) { this.serviceConfiguration = new SimpleServiceConfiguration @@ -86,6 +88,7 @@ public ECommerceClient( Timeout = 1000 }; + this.useSanitizedPathNames = useSanitizedPathNames; this.dependencies = dependencies; } @@ -98,7 +101,7 @@ public IProductCategoryService CategoryService { if (categoryService == null) { - categoryService = this.Resolve() ?? new ProductCategoryService(this); + categoryService = this.Resolve() ?? new ProductCategoryService(this, this.useSanitizedPathNames); } return categoryService; diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/Category.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/Category.cs index d1ec64a..6cfcc37 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/Category.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/Category.cs @@ -26,6 +26,8 @@ IList ICategory.Categories } } + public string SanitizedPathName { get; set; } + internal void SetParent(ICategory parent) { this.parent = parent; diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/CategorySummary.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/CategorySummary.cs index ce76d16..b52e7c9 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/CategorySummary.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Model/CategorySummary.cs @@ -21,5 +21,7 @@ public ICategory Parent throw new NotImplementedException(); } } + + public string SanitizedPathName { get; set; } } } diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/SDL.ECommerce.OData.csproj b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/SDL.ECommerce.OData.csproj index 7b7fc22..b551794 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/SDL.ECommerce.OData.csproj +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/SDL.ECommerce.OData.csproj @@ -198,6 +198,10 @@ {1030d0f7-9334-4864-b495-540e3ad7928c} SDL.ECommerce.Api + + {e2beacd6-4a49-43b4-8e84-2dc4df9a4690} + SDL.ECommerce.Formatting + diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Service/ProductCategoryService.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Service/ProductCategoryService.cs index 5972125..c8a41fa 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Service/ProductCategoryService.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.OData/Service/ProductCategoryService.cs @@ -1,5 +1,6 @@ using SDL.ECommerce.Api.Model; using SDL.ECommerce.Api.Service; +using SDL.ECommerce.Formatting.Servants; using System; using System.Collections.Generic; using System.Linq; @@ -17,16 +18,20 @@ public class ProductCategoryService : IProductCategoryService private ECommerceClient ecommerceClient; private int categoryExpiryTimeout = 3600000; // TODO: Have this configurable + private bool useSanitizedPathNames = false; private ICategory rootCategory = new Category(); + private readonly ISanitizerServant _sanitizerServant; /// /// Constructor (only availably internally) /// /// - internal ProductCategoryService(ECommerceClient ecommerceClient) + internal ProductCategoryService(ECommerceClient ecommerceClient, bool useSanitizedPathNames) { this.ecommerceClient = ecommerceClient; - this.GetTopLevelCategories(); + this.useSanitizedPathNames = useSanitizedPathNames; + _sanitizerServant = new SanitizerServant(new SanitizerConfiguration()); + this.GetTopLevelCategories(); } /// @@ -168,6 +173,12 @@ internal void LoadCategories(ICategory parent, IECommerceODataV4Service service) else { ((Category)category).SetParent(parent); + + if (this.useSanitizedPathNames) + { + ((Category)category).SanitizedPathName = SanitizePathName(category.PathName); + } + newCategoryList.Add(category); } } @@ -179,6 +190,16 @@ internal void LoadCategories(ICategory parent, IECommerceODataV4Service service) } + /// + /// Sanitize a path name + /// + /// + /// + private string SanitizePathName(string pathName) + { + return _sanitizerServant.SanitizedUrlString(pathName); + } + /// /// Get category by Id via the cache. If setting the optional parameter 'refresh=true', then checks /// will be done on the categories while navigating if anyone needs to be refreshed. @@ -225,9 +246,19 @@ private ICategory GetCategoryByPathName(IList categories, String path { foreach (var category in categories) { - if (category.PathName.Equals(pathName)) + if (this.useSanitizedPathNames) { - return category; + if (category.SanitizedPathName != null && category.SanitizedPathName.Equals(pathName)) + { + return category; + } + } + else + { + if (category.PathName.Equals(pathName)) + { + return category; + } } } return null; diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/ECommerceClient.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/ECommerceClient.cs index 41f21a8..9f7af8a 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/ECommerceClient.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/ECommerceClient.cs @@ -12,6 +12,7 @@ public class ECommerceClient : IECommerceClient private readonly RestClient restClient; private readonly IECommerceCacheProvider cacheProvider; private readonly int categoryExpiryTimeout; + private readonly bool useSanitizedPathNames; private IProductCategoryService categoryService; private IProductDetailService productDetailService; @@ -23,11 +24,13 @@ public ECommerceClient(string endpointAddress, string locale, IECommerceCacheProvider cacheProvider, int categoryExpiryTimeout, + bool useSanitizedPathNames, Func dependencies = null) { this.restClient = new RestClient(endpointAddress + "/rest/v1/" + locale); this.cacheProvider = cacheProvider; this.categoryExpiryTimeout = categoryExpiryTimeout; + this.useSanitizedPathNames = useSanitizedPathNames; this.dependencies = dependencies; } @@ -49,7 +52,7 @@ public IProductCategoryService CategoryService { if ( categoryService == null ) { - categoryService = Resolve() ?? new ProductCategoryService(this.restClient, this.categoryExpiryTimeout); + categoryService = Resolve() ?? new ProductCategoryService(this.restClient, this.categoryExpiryTimeout, this.useSanitizedPathNames); } return categoryService; } diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/Category.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/Category.cs index 597f87b..600ee6e 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/Category.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/Category.cs @@ -17,6 +17,7 @@ class Category : ICategory public string Id { get; set; } public string Name { get; set; } public string PathName { get; set; } + public string SanitizedPathName { get; set; } public List ParentIds { get; set; } IList ICategory.Categories diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/LazyCategory.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/LazyCategory.cs index 4342c39..2b6d45e 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/LazyCategory.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Model/LazyCategory.cs @@ -61,5 +61,13 @@ public string PathName return GetCategory().PathName; } } + + public string SanitizedPathName + { + get + { + return GetCategory().SanitizedPathName; + } + } } } diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/SDL.ECommerce.Rest.csproj b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/SDL.ECommerce.Rest.csproj index 2713f40..29c3791 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/SDL.ECommerce.Rest.csproj +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/SDL.ECommerce.Rest.csproj @@ -89,6 +89,10 @@ {1030d0f7-9334-4864-b495-540e3ad7928c} SDL.ECommerce.Api + + {e2beacd6-4a49-43b4-8e84-2dc4df9a4690} + SDL.ECommerce.Formatting + diff --git a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Service/ProductCategoryService.cs b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Service/ProductCategoryService.cs index e676a94..40450e7 100644 --- a/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Service/ProductCategoryService.cs +++ b/dxa.net/ecommerce-framework-dotnet/SDL.ECommerce.Rest/Service/ProductCategoryService.cs @@ -6,6 +6,7 @@ using RestSharp; using SDL.ECommerce.Rest.Model; using SDL.ECommerce.Api; +using SDL.ECommerce.Formatting.Servants; namespace SDL.ECommerce.Rest.Service { @@ -15,14 +16,18 @@ namespace SDL.ECommerce.Rest.Service class ProductCategoryService : IProductCategoryService { private RestClient restClient; - private int categoryExpiryTimeout = 3600000; + private int categoryExpiryTimeout = 3600000; + private bool useSanitizedPathNames = false; private ICategory rootCategory = new Category(); + private readonly ISanitizerServant _sanitizerServant; - public ProductCategoryService(RestClient restClient, int categoryExpiryTimeout) + public ProductCategoryService(RestClient restClient, int categoryExpiryTimeout, bool useSanitizedPathNames) { this.restClient = restClient; + this.useSanitizedPathNames = useSanitizedPathNames; + _sanitizerServant = new SanitizerServant(new SanitizerConfiguration()); this.GetTopLevelCategories(); - this.categoryExpiryTimeout = categoryExpiryTimeout; + this.categoryExpiryTimeout = categoryExpiryTimeout; } /// @@ -163,6 +168,12 @@ internal void LoadCategories(ICategory parent) else { ((Category)category).SetParent(parent); + + if (this.useSanitizedPathNames) + { + ((Category)category).SanitizedPathName = SanitizePathName(category.PathName); + } + newCategoryList.Add(category); } } @@ -174,6 +185,16 @@ internal void LoadCategories(ICategory parent) } + /// + /// Sanitize a path name + /// + /// + /// + private string SanitizePathName(string pathName) + { + return _sanitizerServant.SanitizedUrlString(pathName); + } + /// /// Get categories from service /// @@ -248,9 +269,19 @@ private ICategory GetCategoryByPathName(IList categories, String path { foreach (var category in categories) { - if (category.PathName.Equals(pathName)) + if (this.useSanitizedPathNames) + { + if (category.SanitizedPathName != null && category.SanitizedPathName.Equals(pathName)) + { + return category; + } + } + else { - return category; + if (category.PathName.Equals(pathName)) + { + return category; + } } } return null; diff --git a/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/OData/IntegrationTests.cs b/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/OData/IntegrationTests.cs index b23779d..1b61e31 100644 --- a/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/OData/IntegrationTests.cs +++ b/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/OData/IntegrationTests.cs @@ -25,7 +25,7 @@ protected ECommerceClient ECommerceClient { var endpointAddress = TestContext.Properties["EndpointAddress"] as string; var locale = TestContext.Properties["Locale"] as string; - return new ECommerceClient(endpointAddress, locale); + return new ECommerceClient(endpointAddress, locale, false); } } diff --git a/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/Rest/IntegrationTests.cs b/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/Rest/IntegrationTests.cs index 779b0d6..ebdd004 100644 --- a/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/Rest/IntegrationTests.cs +++ b/dxa.net/ecommerce-framework-dotnet/Tests/SDL.ECommerce.IntegrationTests/Rest/IntegrationTests.cs @@ -47,7 +47,7 @@ protected ECommerceClient ECommerceClient var locale = TestContext.Properties["Locale"] as string; return new ECommerceClient(endpointAddress, locale); */ - return new ECommerceClient("http://preview:8097/ecommerce.svc", "en-US", new DummyCacheProvider(), 3600000); + return new ECommerceClient("http://preview:8097/ecommerce.svc", "en-US", new DummyCacheProvider(), 3600000, false); } }