diff --git a/src/VirtoCommerce.Xapi.Core/Extensions/SeoInfosExtensions.cs b/src/VirtoCommerce.Xapi.Core/Extensions/SeoInfosExtensions.cs index d12f88f..2db1d65 100644 --- a/src/VirtoCommerce.Xapi.Core/Extensions/SeoInfosExtensions.cs +++ b/src/VirtoCommerce.Xapi.Core/Extensions/SeoInfosExtensions.cs @@ -8,31 +8,31 @@ namespace VirtoCommerce.Xapi.Core.Extensions; public static class SeoInfosExtensions { - [Obsolete("Use VirtoCommerce.StoreModule.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] + [Obsolete("Use VirtoCommerce.Seo.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] public static SeoInfo GetBestMatchingSeoInfo(this IList seoInfos, string storeId, string cultureName) { return GetBestMatchingSeoInfoInternal(seoInfos, storeId, cultureName, cultureName, slug: null, permalink: null); } - [Obsolete("Use VirtoCommerce.StoreModule.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] + [Obsolete("Use VirtoCommerce.Seo.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] public static SeoInfo GetBestMatchingSeoInfo(this IList seoInfos, string storeId, string cultureName, string slug) { return GetBestMatchingSeoInfoInternal(seoInfos, storeId, cultureName, cultureName, slug, permalink: null); } - [Obsolete("Use VirtoCommerce.StoreModule.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] + [Obsolete("Use VirtoCommerce.Seo.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] public static SeoInfo GetBestMatchingSeoInfo(this IList seoInfos, string storeId, string defaultStoreLang, string cultureName, string slug) { return GetBestMatchingSeoInfoInternal(seoInfos, storeId, defaultStoreLang, cultureName, slug, permalink: null); } - [Obsolete("Use VirtoCommerce.StoreModule.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] + [Obsolete("Use VirtoCommerce.Seo.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] public static SeoInfo GetBestMatchingSeoInfo(this IList seoInfos, string storeId, string defaultStoreLang, string cultureName, string slug, string permalink) { return GetBestMatchingSeoInfoInternal(seoInfos, storeId, defaultStoreLang, cultureName, slug, permalink); } - [Obsolete("Use VirtoCommerce.StoreModule.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] + [Obsolete("Use VirtoCommerce.Seo.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] public static SeoInfo GetBestMatchingSeoInfo(this IList seoInfos, string defaultStoreLang, SeoSearchCriteria criteria) { @@ -40,7 +40,19 @@ public static SeoInfo GetBestMatchingSeoInfo(this IList seoInfos, strin criteria.Slug, criteria.Permalink); } + [Obsolete("Use VirtoCommerce.Seo.Core.Extensions", DiagnosticId = "VC0010", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")] + public static SeoInfo GetFallbackSeoInfo(string id, string name, string cultureName) + { + var result = AbstractTypeFactory.TryCreateInstance(); + result.SemanticUrl = id; + result.LanguageCode = cultureName; + result.Name = name; + return result; + } + +#pragma warning disable VC0010 // Type or member is obsolete private static SeoInfo GetBestMatchingSeoInfoInternal(IList seoInfos, string storeId, +#pragma warning restore VC0010 // Type or member is obsolete string defaultStoreLang, string cultureName, string slug, string permalink) { if (storeId.IsNullOrEmpty() || cultureName.IsNullOrEmpty()) @@ -50,16 +62,9 @@ private static SeoInfo GetBestMatchingSeoInfoInternal(IList seoInfos, s return seoInfos.GetBestMatchingSeoInfos(storeId, defaultStoreLang, cultureName, slug, permalink); } - public static SeoInfo GetFallbackSeoInfo(string id, string name, string cultureName) - { - var result = AbstractTypeFactory.TryCreateInstance(); - result.SemanticUrl = id; - result.LanguageCode = cultureName; - result.Name = name; - return result; - } - +#pragma warning disable VC0010 // Type or member is obsolete private static SeoInfo GetBestMatchingSeoInfos(this IEnumerable seoRecords, string storeId, string defaultStoreLang, string language, string slug, string permalink) +#pragma warning restore VC0010 // Type or member is obsolete { var result = seoRecords?.Select(s => new { @@ -73,7 +78,9 @@ private static SeoInfo GetBestMatchingSeoInfos(this IEnumerable seoReco return result; } +#pragma warning disable VC0010 // Type or member is obsolete private static int CalculateScore(SeoInfo seoInfo, string slug, string permalink, string storeId, string defaultStoreLang, string language) +#pragma warning restore VC0010 // Type or member is obsolete { var score = new[] { diff --git a/src/VirtoCommerce.Xapi.Core/Models/SlugInfoResponse.cs b/src/VirtoCommerce.Xapi.Core/Models/SlugInfoResponse.cs index 9b6e6a4..13b87c8 100644 --- a/src/VirtoCommerce.Xapi.Core/Models/SlugInfoResponse.cs +++ b/src/VirtoCommerce.Xapi.Core/Models/SlugInfoResponse.cs @@ -1,9 +1,10 @@ -using VirtoCommerce.CoreModule.Core.Seo; +using VirtoCommerce.Seo.Core.Models; namespace VirtoCommerce.Xapi.Core.Models { public class SlugInfoResponse { public SeoInfo EntityInfo { get; set; } + //public string RedirectUrl { get; set; } } } diff --git a/src/VirtoCommerce.Xapi.Core/Schemas/SeoInfoType.cs b/src/VirtoCommerce.Xapi.Core/Schemas/SeoInfoType.cs index 4996d88..67fb6dd 100644 --- a/src/VirtoCommerce.Xapi.Core/Schemas/SeoInfoType.cs +++ b/src/VirtoCommerce.Xapi.Core/Schemas/SeoInfoType.cs @@ -1,4 +1,4 @@ -using VirtoCommerce.CoreModule.Core.Seo; +using VirtoCommerce.Seo.Core.Models; namespace VirtoCommerce.Xapi.Core.Schemas { diff --git a/src/VirtoCommerce.Xapi.Core/Schemas/SlugInfoResponseType.cs b/src/VirtoCommerce.Xapi.Core/Schemas/SlugInfoResponseType.cs index d3c0765..7322542 100644 --- a/src/VirtoCommerce.Xapi.Core/Schemas/SlugInfoResponseType.cs +++ b/src/VirtoCommerce.Xapi.Core/Schemas/SlugInfoResponseType.cs @@ -7,6 +7,7 @@ public class SlugInfoResponseType : ExtendableGraphType public SlugInfoResponseType() { Field("entityInfo").Description("SEO info").Resolve(context => context.Source.EntityInfo); + // here should be redirectUrl soon } } } diff --git a/src/VirtoCommerce.Xapi.Core/VirtoCommerce.Xapi.Core.csproj b/src/VirtoCommerce.Xapi.Core/VirtoCommerce.Xapi.Core.csproj index ba43472..baa05bd 100644 --- a/src/VirtoCommerce.Xapi.Core/VirtoCommerce.Xapi.Core.csproj +++ b/src/VirtoCommerce.Xapi.Core/VirtoCommerce.Xapi.Core.csproj @@ -27,11 +27,11 @@ - - - + + - + + diff --git a/src/VirtoCommerce.Xapi.Data/Queries/SlugInfoQueryHandler.cs b/src/VirtoCommerce.Xapi.Data/Queries/SlugInfoQueryHandler.cs index 9268ce8..f5194f2 100644 --- a/src/VirtoCommerce.Xapi.Data/Queries/SlugInfoQueryHandler.cs +++ b/src/VirtoCommerce.Xapi.Data/Queries/SlugInfoQueryHandler.cs @@ -2,8 +2,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using VirtoCommerce.CoreModule.Core.Seo; using VirtoCommerce.Platform.Core.Common; +using VirtoCommerce.Seo.Core.Models; +using VirtoCommerce.Seo.Core.Services; using VirtoCommerce.StoreModule.Core.Extensions; using VirtoCommerce.StoreModule.Core.Model; using VirtoCommerce.StoreModule.Core.Services; @@ -11,55 +12,60 @@ using VirtoCommerce.Xapi.Core.Models; using VirtoCommerce.Xapi.Core.Queries; -namespace VirtoCommerce.Xapi.Data.Queries +namespace VirtoCommerce.Xapi.Data.Queries; + +public class SlugInfoQueryHandler : IQueryHandler { - public class SlugInfoQueryHandler : IQueryHandler + private readonly ICompositeSeoResolver _seoResolver; + private readonly IStoreService _storeService; + + public SlugInfoQueryHandler(ICompositeSeoResolver seoResolver, IStoreService storeService) + { + _seoResolver = seoResolver; + _storeService = storeService; + } + + public async Task Handle(SlugInfoQuery request, CancellationToken cancellationToken) { - private readonly CompositeSeoResolver _seoResolver; - private readonly IStoreService _storeService; + var result = new SlugInfoResponse(); - public SlugInfoQueryHandler(CompositeSeoResolver seoResolver, IStoreService storeService) + if (string.IsNullOrEmpty(request.Permalink)) { - _seoResolver = seoResolver; - _storeService = storeService; + return result; } - public async Task Handle(SlugInfoQuery request, CancellationToken cancellationToken) + var store = await _storeService.GetByIdAsync(request.StoreId); + if (store is null) { - var result = new SlugInfoResponse(); - - if (string.IsNullOrEmpty(request.Permalink)) - { - return result; - } + return result; + } - var store = await _storeService.GetByIdAsync(request.StoreId); - if (store is null) - { - return result; - } + var currentCulture = request.CultureName ?? store.DefaultLanguage; - var currentCulture = request.CultureName ?? store.DefaultLanguage; + var segments = request.Permalink.Split("/", StringSplitOptions.RemoveEmptyEntries); + var lastSegment = segments.LastOrDefault(); - var segments = request.Permalink.Split("/", StringSplitOptions.RemoveEmptyEntries); - var lastSegment = segments.LastOrDefault(); + var criteria = AbstractTypeFactory.TryCreateInstance(); + criteria.StoreId = store.Id; + criteria.LanguageCode = currentCulture; + criteria.Permalink = request.Permalink; + criteria.Slug = lastSegment; + criteria.UserId = request.UserId; - var criteria = AbstractTypeFactory.TryCreateInstance(); - criteria.StoreId = store.Id; - criteria.LanguageCode = currentCulture; - criteria.Permalink = request.Permalink; - criteria.Slug = lastSegment; - criteria.UserId = request.UserId; + result.EntityInfo = await GetBestMatchingSeoInfo(criteria, store); - result.EntityInfo = await GetBestMatchingSeoInfo(criteria, store); + //if (result.EntityInfo == null) + //{ + // // todo: use seofaultservice + // result.RedirectUrl = ""; + //} - return result; - } + return result; + } - protected virtual async Task GetBestMatchingSeoInfo(SeoSearchCriteria criteria, Store store) - { - var itemsToMatch = await _seoResolver.FindSeoAsync(criteria); - return itemsToMatch.GetBestMatchingSeoInfo(store, criteria.LanguageCode, criteria.Slug, criteria.Permalink); - } + protected virtual async Task GetBestMatchingSeoInfo(SeoSearchCriteria criteria, Store store) + { + var itemsToMatch = await _seoResolver.FindSeoAsync(criteria); + return itemsToMatch.GetBestMatchingSeoInfo(store, criteria.LanguageCode); } } diff --git a/src/VirtoCommerce.Xapi.Data/VirtoCommerce.Xapi.Data.csproj b/src/VirtoCommerce.Xapi.Data/VirtoCommerce.Xapi.Data.csproj index 9b496bd..d38b034 100644 --- a/src/VirtoCommerce.Xapi.Data/VirtoCommerce.Xapi.Data.csproj +++ b/src/VirtoCommerce.Xapi.Data/VirtoCommerce.Xapi.Data.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/VirtoCommerce.Xapi.Web/Module.cs b/src/VirtoCommerce.Xapi.Web/Module.cs index 69e5bf1..dc6fdd3 100644 --- a/src/VirtoCommerce.Xapi.Web/Module.cs +++ b/src/VirtoCommerce.Xapi.Web/Module.cs @@ -49,9 +49,9 @@ public void Initialize(IServiceCollection serviceCollection) #pragma warning restore CS0618 // Type or member is obsolete // Register .NET GraphQL server - serviceCollection.AddGraphQL(bulder => + serviceCollection.AddGraphQL(builder => { - bulder + builder .AddNewtonsoftJson() .AddSchema(serviceCollection, typeof(CoreAssemblyMarker), typeof(DataAssemblyMarker)) .AddPermissionAuthorization() @@ -71,9 +71,9 @@ public void Initialize(IServiceCollection serviceCollection) if (!IsSchemaIntrospectionEnabled) { - bulder.ReplaceValidationRule(); - bulder.ReplaceValidationRule(); - bulder.ReplaceValidationRule(); + builder.ReplaceValidationRule(); + builder.ReplaceValidationRule(); + builder.ReplaceValidationRule(); } }); diff --git a/src/VirtoCommerce.Xapi.Web/module.manifest b/src/VirtoCommerce.Xapi.Web/module.manifest index 5071f7f..79728f6 100644 --- a/src/VirtoCommerce.Xapi.Web/module.manifest +++ b/src/VirtoCommerce.Xapi.Web/module.manifest @@ -4,13 +4,13 @@ 3.915.0 - 3.887.0 + 3.889.0 - - + - + + diff --git a/tests/VirtoCommerce.Xapi.Tests/Extensions/SeoInfosExtensionsTests.cs b/tests/VirtoCommerce.Xapi.Tests/Extensions/SeoInfosExtensionsTests.cs deleted file mode 100644 index 22fc647..0000000 --- a/tests/VirtoCommerce.Xapi.Tests/Extensions/SeoInfosExtensionsTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Collections.Generic; -using VirtoCommerce.CoreModule.Core.Seo; -using VirtoCommerce.StoreModule.Core.Extensions; -using VirtoCommerce.StoreModule.Core.Model; -using Xunit; - -namespace VirtoCommerce.Xapi.Tests.Extensions -{ - public class SeoInfosExtensionsTests - { - [Fact] - public void GetBestMatchingSeoInfo_WithValidParameters_ReturnsSeoInfo() - { - // Arrange - var seoInfos = new List - { - new SeoInfo { StoreId = "Store1", LanguageCode = "en-US", SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store1", LanguageCode = "en-US", SemanticUrl = "product2" }, - new SeoInfo { StoreId = "Store2", LanguageCode = "en-US", SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store2", LanguageCode = "en-US", SemanticUrl = "product2" } - }; - var store = new Store { Id = "Store1", DefaultLanguage = "en-US" }; - var cultureName = "en-US"; - var slug = "product1"; - - // Act - var result = seoInfos.GetBestMatchingSeoInfo(store, cultureName, slug); - - // Assert - Assert.NotNull(result); - Assert.Equal("Store1", result.StoreId); - Assert.Equal("en-US", result.LanguageCode); - Assert.Equal("product1", result.SemanticUrl); - } - - [Fact] - public void GetBestMatchingSeoInfo_WithNullParameters_ReturnsNull() - { - // Arrange - var seoInfos = new List - { - new SeoInfo { StoreId = "Store1", LanguageCode = "en-US", SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store1", LanguageCode = "en-US", SemanticUrl = "product2" }, - new SeoInfo { StoreId = "Store2", LanguageCode = "en-US", SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store2", LanguageCode = "en-US", SemanticUrl = "product2" } - }; - Store store = null; - string cultureName = null; - string slug = null; - - // Act - var result = seoInfos.GetBestMatchingSeoInfo(store, cultureName, slug); - - // Assert - Assert.Null(result); - } - - [Fact] - public void GetBestMatchingSeoInfo_WithNonExistLang_ReturnsDefaultStoreLang() - { - // Arrange - var seoInfos = new List - { - new SeoInfo { StoreId = "Store1", LanguageCode = null, SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store1", LanguageCode = "en-US", SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store1", LanguageCode = "fr-FR", SemanticUrl = "product1" }, - }; - var store = new Store { Id = "Store1", DefaultLanguage = "en-US" }; - var cultureName = "de-DE"; - var slug = "product1"; - - // Act - var result = seoInfos.GetBestMatchingSeoInfo(store, cultureName, slug); - - // Assert - Assert.NotNull(result); - Assert.Equal(result.LanguageCode, store.DefaultLanguage); - } - - [Fact] - public void GetBestMatchingSeoInfo_WithNonExistLangAndStoreLang_ReturnsEmptyLang() - { - // Arrange - var seoInfos = new List - { - new SeoInfo { StoreId = "Store1", LanguageCode = "fr-FR", SemanticUrl = "product1" }, - new SeoInfo { StoreId = "Store1", LanguageCode = null, SemanticUrl = "product1" }, - }; - var store = new Store { Id = "Store1", DefaultLanguage = "en-US" }; - var cultureName = "de-DE"; - var slug = "product1"; - - // Act - var result = seoInfos.GetBestMatchingSeoInfo(store, cultureName, slug); - - // Assert - Assert.NotNull(result); - Assert.Null(result.LanguageCode); - } - } -}