FruitBank/Presentation/Nop.Web/Factories/JsonLdModelFactory.cs

188 lines
7.1 KiB
C#

using System.Globalization;
using System.Text.Encodings.Web;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Events;
using Nop.Web.Framework.Mvc.Routing;
using Nop.Web.Models.Catalog;
using Nop.Web.Models.JsonLD;
namespace Nop.Web.Factories;
/// <summary>
/// Represents the JSON-LD model factory implementation
/// </summary>
public partial class JsonLdModelFactory : IJsonLdModelFactory
{
#region Fields
protected readonly IEventPublisher _eventPublisher;
protected readonly INopUrlHelper _nopUrlHelper;
protected readonly IWebHelper _webHelper;
#endregion
#region Ctor
public JsonLdModelFactory(IEventPublisher eventPublisher,
INopUrlHelper nopUrlHelper,
IWebHelper webHelper)
{
_eventPublisher = eventPublisher;
_nopUrlHelper = nopUrlHelper;
_webHelper = webHelper;
}
#endregion
#region Utilities
/// <summary>
/// Prepare JSON-LD category breadcrumb model
/// </summary>
/// <param name="categoryModels">List of category models</param>
/// <returns>A task that represents the asynchronous operation
/// The task result contains JSON-LD category breadcrumb model
/// </returns>
protected virtual async Task<JsonLdBreadcrumbListModel> PrepareJsonLdBreadcrumbListAsync(IList<CategorySimpleModel> categoryModels)
{
var breadcrumbList = new JsonLdBreadcrumbListModel();
var position = 1;
foreach (var cat in categoryModels)
{
var breadcrumbListItem = new JsonLdBreadcrumbListItemModel
{
Position = position,
Item = new JsonLdBreadcrumbItemModel
{
Id = await _nopUrlHelper.RouteGenericUrlAsync<Category>(new { SeName = cat.SeName }, _webHelper.GetCurrentRequestProtocol()),
Name = cat.Name
}
};
breadcrumbList.ItemListElement.Add(breadcrumbListItem);
position++;
}
return breadcrumbList;
}
#endregion
#region Methods
/// <summary>
/// Prepare JSON-LD category breadcrumb model
/// </summary>
/// <param name="categoryModels">List of category models</param>
/// <returns>A task that represents the asynchronous operation
/// The task result contains JSON-LD category breadcrumb model
/// </returns>
public virtual async Task<JsonLdBreadcrumbListModel> PrepareJsonLdCategoryBreadcrumbAsync(IList<CategorySimpleModel> categoryModels)
{
var breadcrumbList = await PrepareJsonLdBreadcrumbListAsync(categoryModels);
await _eventPublisher.PublishAsync(new JsonLdCreatedEvent<JsonLdBreadcrumbListModel>(breadcrumbList));
return breadcrumbList;
}
/// <summary>
/// Prepare JSON-LD product breadcrumb model
/// </summary>
/// <param name="breadcrumbModel">Product breadcrumb model</param>
/// <returns>A task that represents the asynchronous operation
/// The task result contains JSON-LD product breadcrumb model
/// </returns>
public virtual async Task<JsonLdBreadcrumbListModel> PrepareJsonLdProductBreadcrumbAsync(ProductDetailsModel.ProductBreadcrumbModel breadcrumbModel)
{
var breadcrumbList = await PrepareJsonLdBreadcrumbListAsync(breadcrumbModel.CategoryBreadcrumb);
breadcrumbList.ItemListElement.Add(new JsonLdBreadcrumbListItemModel
{
Position = breadcrumbList.ItemListElement.Count + 1,
Item = new JsonLdBreadcrumbItemModel
{
Id = await _nopUrlHelper.RouteGenericUrlAsync<Product>(new { SeName = breadcrumbModel.ProductSeName }, _webHelper.GetCurrentRequestProtocol()),
Name = breadcrumbModel.ProductName,
}
});
await _eventPublisher.PublishAsync(new JsonLdCreatedEvent<JsonLdBreadcrumbListModel>(breadcrumbList));
return breadcrumbList;
}
/// <summary>
/// Prepare JSON-LD product model
/// </summary>
/// <param name="model">Product details model</param>
/// <param name="productUrl">Product URL</param>
/// <returns>A task that represents the asynchronous operation
/// The task result contains JSON-LD product model
/// </returns>
public virtual async Task<JsonLdProductModel> PrepareJsonLdProductAsync(ProductDetailsModel model, string productUrl = null)
{
productUrl ??= await _nopUrlHelper.RouteGenericUrlAsync<Product>(new { SeName = model.SeName }, _webHelper.GetCurrentRequestProtocol());
var productPrice = model.AssociatedProducts.Any()
? model.AssociatedProducts.Min(associatedProduct => associatedProduct.ProductPrice.PriceValue)
: model.ProductPrice.PriceValue;
var product = new JsonLdProductModel
{
Name = model.Name,
Sku = model.Sku,
Gtin = model.Gtin,
Mpn = model.ManufacturerPartNumber,
Description = model.ShortDescription,
Image = model.DefaultPictureModel.ImageUrl,
Offer = new JsonLdOfferModel
{
Url = productUrl.ToLowerInvariant(),
Price = model.ProductPrice.CallForPrice ? null : productPrice?.ToString("0.00", CultureInfo.InvariantCulture),
PriceCurrency = model.ProductPrice.CurrencyCode,
PriceValidUntil = model.AvailableEndDate,
Availability = @"https://schema.org/" + (model.InStock ? "InStock" : "OutOfStock")
},
Brand = model.ProductManufacturers?.Select(manufacturer => new JsonLdBrandModel { Name = manufacturer.Name }).ToList()
};
if (model.ProductReviewOverview.TotalReviews > 0)
{
var ratingPercent = model.ProductReviewOverview.RatingSum * 100 / model.ProductReviewOverview.TotalReviews / 5;
var ratingValue = ratingPercent / (decimal)20;
product.AggregateRating = new JsonLdAggregateRatingModel
{
RatingValue = ratingValue.ToString("0.0", CultureInfo.InvariantCulture),
ReviewCount = model.ProductReviewOverview.TotalReviews
};
product.Review = model.ProductReviews.Items?.Select(review => new JsonLdReviewModel
{
Name = JavaScriptEncoder.Default.Encode(review.Title),
ReviewBody = JavaScriptEncoder.Default.Encode(review.ReviewText),
ReviewRating = new JsonLdRatingModel
{
RatingValue = review.Rating
},
Author = new JsonLdPersonModel { Name = JavaScriptEncoder.Default.Encode(review.CustomerName) },
DatePublished = review.WrittenOnStr
}).ToList();
}
foreach (var associatedProduct in model.AssociatedProducts)
{
var parentUrl = !associatedProduct.VisibleIndividually ? productUrl : null;
product.HasVariant.Add(await PrepareJsonLdProductAsync(associatedProduct, parentUrl));
}
await _eventPublisher.PublishAsync(new JsonLdCreatedEvent<JsonLdProductModel>(product));
return product;
}
#endregion
}