638 lines
27 KiB
C#
638 lines
27 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Nop.Core;
|
|
using Nop.Core.Domain.Catalog;
|
|
using Nop.Core.Domain.Localization;
|
|
using Nop.Core.Domain.Orders;
|
|
using Nop.Core.Domain.Security;
|
|
using Nop.Core.Domain.Shipping;
|
|
using Nop.Core.Events;
|
|
using Nop.Services.Catalog;
|
|
using Nop.Services.Customers;
|
|
using Nop.Services.Html;
|
|
using Nop.Services.Localization;
|
|
using Nop.Services.Logging;
|
|
using Nop.Services.Messages;
|
|
using Nop.Services.Orders;
|
|
using Nop.Services.Security;
|
|
using Nop.Services.Seo;
|
|
using Nop.Services.Stores;
|
|
using Nop.Web.Factories;
|
|
using Nop.Web.Framework;
|
|
using Nop.Web.Framework.Controllers;
|
|
using Nop.Web.Framework.Mvc.Filters;
|
|
using Nop.Web.Framework.Mvc.Routing;
|
|
using Nop.Web.Models.Catalog;
|
|
|
|
namespace Nop.Web.Controllers;
|
|
|
|
[AutoValidateAntiforgeryToken]
|
|
public partial class ProductController : BasePublicController
|
|
{
|
|
#region Fields
|
|
|
|
protected readonly CaptchaSettings _captchaSettings;
|
|
protected readonly CatalogSettings _catalogSettings;
|
|
protected readonly IAclService _aclService;
|
|
protected readonly ICompareProductsService _compareProductsService;
|
|
protected readonly ICustomerActivityService _customerActivityService;
|
|
protected readonly ICustomerService _customerService;
|
|
protected readonly IEventPublisher _eventPublisher;
|
|
protected readonly IHtmlFormatter _htmlFormatter;
|
|
protected readonly ILocalizationService _localizationService;
|
|
protected readonly INopUrlHelper _nopUrlHelper;
|
|
protected readonly INotificationService _notificationService;
|
|
protected readonly IOrderService _orderService;
|
|
protected readonly IPermissionService _permissionService;
|
|
protected readonly IProductAttributeParser _productAttributeParser;
|
|
protected readonly IProductModelFactory _productModelFactory;
|
|
protected readonly IProductService _productService;
|
|
protected readonly IRecentlyViewedProductsService _recentlyViewedProductsService;
|
|
protected readonly IReviewTypeService _reviewTypeService;
|
|
protected readonly IShoppingCartModelFactory _shoppingCartModelFactory;
|
|
protected readonly IShoppingCartService _shoppingCartService;
|
|
protected readonly IStoreContext _storeContext;
|
|
protected readonly IStoreMappingService _storeMappingService;
|
|
protected readonly IUrlRecordService _urlRecordService;
|
|
protected readonly IWorkContext _workContext;
|
|
protected readonly IWorkflowMessageService _workflowMessageService;
|
|
protected readonly LocalizationSettings _localizationSettings;
|
|
protected readonly ShoppingCartSettings _shoppingCartSettings;
|
|
protected readonly ShippingSettings _shippingSettings;
|
|
|
|
#endregion
|
|
|
|
#region Ctor
|
|
|
|
public ProductController(CaptchaSettings captchaSettings,
|
|
CatalogSettings catalogSettings,
|
|
IAclService aclService,
|
|
ICompareProductsService compareProductsService,
|
|
ICustomerActivityService customerActivityService,
|
|
ICustomerService customerService,
|
|
IEventPublisher eventPublisher,
|
|
IHtmlFormatter htmlFormatter,
|
|
ILocalizationService localizationService,
|
|
INopUrlHelper nopUrlHelper,
|
|
INotificationService notificationService,
|
|
IOrderService orderService,
|
|
IPermissionService permissionService,
|
|
IProductAttributeParser productAttributeParser,
|
|
IProductModelFactory productModelFactory,
|
|
IProductService productService,
|
|
IRecentlyViewedProductsService recentlyViewedProductsService,
|
|
IReviewTypeService reviewTypeService,
|
|
IShoppingCartModelFactory shoppingCartModelFactory,
|
|
IShoppingCartService shoppingCartService,
|
|
IStoreContext storeContext,
|
|
IStoreMappingService storeMappingService,
|
|
IUrlRecordService urlRecordService,
|
|
IWorkContext workContext,
|
|
IWorkflowMessageService workflowMessageService,
|
|
LocalizationSettings localizationSettings,
|
|
ShoppingCartSettings shoppingCartSettings,
|
|
ShippingSettings shippingSettings)
|
|
{
|
|
_captchaSettings = captchaSettings;
|
|
_catalogSettings = catalogSettings;
|
|
_aclService = aclService;
|
|
_compareProductsService = compareProductsService;
|
|
_customerActivityService = customerActivityService;
|
|
_customerService = customerService;
|
|
_eventPublisher = eventPublisher;
|
|
_htmlFormatter = htmlFormatter;
|
|
_localizationService = localizationService;
|
|
_nopUrlHelper = nopUrlHelper;
|
|
_notificationService = notificationService;
|
|
_orderService = orderService;
|
|
_permissionService = permissionService;
|
|
_productAttributeParser = productAttributeParser;
|
|
_productModelFactory = productModelFactory;
|
|
_productService = productService;
|
|
_reviewTypeService = reviewTypeService;
|
|
_recentlyViewedProductsService = recentlyViewedProductsService;
|
|
_shoppingCartModelFactory = shoppingCartModelFactory;
|
|
_shoppingCartService = shoppingCartService;
|
|
_storeContext = storeContext;
|
|
_storeMappingService = storeMappingService;
|
|
_urlRecordService = urlRecordService;
|
|
_workContext = workContext;
|
|
_workflowMessageService = workflowMessageService;
|
|
_localizationSettings = localizationSettings;
|
|
_shoppingCartSettings = shoppingCartSettings;
|
|
_shippingSettings = shippingSettings;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Utilities
|
|
|
|
protected virtual async Task ValidateProductReviewAvailabilityAsync(Product product)
|
|
{
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
if (await _customerService.IsGuestAsync(customer) && !_catalogSettings.AllowAnonymousUsersToReviewProduct)
|
|
ModelState.AddModelError(string.Empty, await _localizationService.GetResourceAsync("Reviews.OnlyRegisteredUsersCanWriteReviews"));
|
|
|
|
if (!_catalogSettings.ProductReviewPossibleOnlyAfterPurchasing)
|
|
return;
|
|
|
|
var hasCompletedOrders = product.ProductType == ProductType.SimpleProduct
|
|
? await HasCompletedOrdersAsync(product)
|
|
: await (await _productService.GetAssociatedProductsAsync(product.Id)).AnyAwaitAsync(HasCompletedOrdersAsync);
|
|
|
|
if (!hasCompletedOrders)
|
|
ModelState.AddModelError(string.Empty, await _localizationService.GetResourceAsync("Reviews.ProductReviewPossibleOnlyAfterPurchasing"));
|
|
}
|
|
|
|
protected virtual async ValueTask<bool> HasCompletedOrdersAsync(Product product)
|
|
{
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
return (await _orderService.SearchOrdersAsync(customerId: customer.Id,
|
|
productId: product.Id,
|
|
osIds: [(int)OrderStatus.Complete],
|
|
pageSize: 1)).Any();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Product details page
|
|
|
|
public virtual async Task<IActionResult> ProductDetails(int productId, int updatecartitemid = 0)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(productId);
|
|
if (product == null || product.Deleted)
|
|
return InvokeHttp404();
|
|
|
|
var notAvailable =
|
|
//published?
|
|
(!product.Published && !_catalogSettings.AllowViewUnpublishedProductPage) ||
|
|
//ACL (access control list)
|
|
!await _aclService.AuthorizeAsync(product) ||
|
|
//Store mapping
|
|
!await _storeMappingService.AuthorizeAsync(product) ||
|
|
//availability dates
|
|
!_productService.ProductIsAvailable(product);
|
|
//Check whether the current user has a "Manage products" permission (usually a store owner)
|
|
//We should allows him (her) to use "Preview" functionality
|
|
var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL) && await _permissionService.AuthorizeAsync(StandardPermission.Catalog.PRODUCTS_VIEW);
|
|
if (notAvailable && !hasAdminAccess)
|
|
return InvokeHttp404();
|
|
|
|
//visible individually?
|
|
if (!product.VisibleIndividually)
|
|
{
|
|
//is this one an associated products?
|
|
var parentGroupedProduct = await _productService.GetProductByIdAsync(product.ParentGroupedProductId);
|
|
if (parentGroupedProduct == null)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
var seName = await _urlRecordService.GetSeNameAsync(parentGroupedProduct);
|
|
var productUrl = await _nopUrlHelper.RouteGenericUrlAsync<Product>(new { SeName = seName });
|
|
return LocalRedirectPermanent(productUrl);
|
|
}
|
|
|
|
//update existing shopping cart or wishlist item?
|
|
ShoppingCartItem updatecartitem = null;
|
|
if (_shoppingCartSettings.AllowCartItemEditing && updatecartitemid > 0)
|
|
{
|
|
var seName = await _urlRecordService.GetSeNameAsync(product);
|
|
var productUrl = await _nopUrlHelper.RouteGenericUrlAsync<Product>(new { SeName = seName });
|
|
var store = await _storeContext.GetCurrentStoreAsync();
|
|
var cart = await _shoppingCartService.GetShoppingCartAsync(await _workContext.GetCurrentCustomerAsync(), storeId: store.Id);
|
|
updatecartitem = cart.FirstOrDefault(x => x.Id == updatecartitemid);
|
|
|
|
//not found?
|
|
if (updatecartitem == null)
|
|
return LocalRedirect(productUrl);
|
|
|
|
//is it this product?
|
|
if (product.Id != updatecartitem.ProductId)
|
|
return LocalRedirect(productUrl);
|
|
}
|
|
|
|
//save as recently viewed
|
|
await _recentlyViewedProductsService.AddProductToRecentlyViewedListAsync(product.Id);
|
|
|
|
//display "edit" (manage) link
|
|
if (await _permissionService.AuthorizeAsync(StandardPermission.Security.ACCESS_ADMIN_PANEL) &&
|
|
await _permissionService.AuthorizeAsync(StandardPermission.Catalog.PRODUCTS_VIEW))
|
|
{
|
|
//a vendor should have access only to his products
|
|
var currentVendor = await _workContext.GetCurrentVendorAsync();
|
|
if (currentVendor == null || currentVendor.Id == product.VendorId)
|
|
{
|
|
DisplayEditLink(Url.Action("Edit", "Product", new { id = product.Id, area = AreaNames.ADMIN }));
|
|
}
|
|
}
|
|
|
|
//activity log
|
|
await _customerActivityService.InsertActivityAsync("PublicStore.ViewProduct",
|
|
string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.ViewProduct"), product.Name), product);
|
|
|
|
//model
|
|
var model = await _productModelFactory.PrepareProductDetailsModelAsync(product, updatecartitem, false);
|
|
//template
|
|
var productTemplateViewPath = await _productModelFactory.PrepareProductTemplateViewPathAsync(product);
|
|
|
|
return View(productTemplateViewPath, model);
|
|
}
|
|
|
|
[HttpPost]
|
|
public virtual async Task<IActionResult> EstimateShipping([FromQuery] ProductDetailsModel.ProductEstimateShippingModel model, IFormCollection form)
|
|
{
|
|
if (model == null)
|
|
model = new ProductDetailsModel.ProductEstimateShippingModel();
|
|
|
|
var errors = new List<string>();
|
|
|
|
if (!_shippingSettings.EstimateShippingCityNameEnabled && string.IsNullOrEmpty(model.ZipPostalCode))
|
|
errors.Add(await _localizationService.GetResourceAsync("Shipping.EstimateShipping.ZipPostalCode.Required"));
|
|
|
|
if (_shippingSettings.EstimateShippingCityNameEnabled && string.IsNullOrEmpty(model.City))
|
|
errors.Add(await _localizationService.GetResourceAsync("Shipping.EstimateShipping.City.Required"));
|
|
|
|
if (model.CountryId == null || model.CountryId == 0)
|
|
errors.Add(await _localizationService.GetResourceAsync("Shipping.EstimateShipping.Country.Required"));
|
|
|
|
if (errors.Count > 0)
|
|
return Json(new
|
|
{
|
|
Success = false,
|
|
Errors = errors
|
|
});
|
|
|
|
var product = await _productService.GetProductByIdAsync(model.ProductId);
|
|
if (product == null || product.Deleted)
|
|
{
|
|
errors.Add(await _localizationService.GetResourceAsync("Shipping.EstimateShippingPopUp.Product.IsNotFound"));
|
|
return Json(new
|
|
{
|
|
Success = false,
|
|
Errors = errors
|
|
});
|
|
}
|
|
|
|
var store = await _storeContext.GetCurrentStoreAsync();
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
|
|
var wrappedProduct = new ShoppingCartItem()
|
|
{
|
|
StoreId = store.Id,
|
|
ShoppingCartTypeId = (int)ShoppingCartType.ShoppingCart,
|
|
CustomerId = customer.Id,
|
|
ProductId = product.Id,
|
|
CreatedOnUtc = DateTime.UtcNow
|
|
};
|
|
|
|
var addToCartWarnings = new List<string>();
|
|
//customer entered price
|
|
wrappedProduct.CustomerEnteredPrice = await _productAttributeParser.ParseCustomerEnteredPriceAsync(product, form);
|
|
|
|
//entered quantity
|
|
wrappedProduct.Quantity = _productAttributeParser.ParseEnteredQuantity(product, form);
|
|
|
|
//product and gift card attributes
|
|
wrappedProduct.AttributesXml = await _productAttributeParser.ParseProductAttributesAsync(product, form, addToCartWarnings);
|
|
|
|
//rental attributes
|
|
_productAttributeParser.ParseRentalDates(product, form, out var rentalStartDate, out var rentalEndDate);
|
|
wrappedProduct.RentalStartDateUtc = rentalStartDate;
|
|
wrappedProduct.RentalEndDateUtc = rentalEndDate;
|
|
|
|
var result = await _shoppingCartModelFactory.PrepareEstimateShippingResultModelAsync(new[] { wrappedProduct }, model, false);
|
|
|
|
return Json(result);
|
|
}
|
|
|
|
//ignore SEO friendly URLs checks
|
|
[CheckLanguageSeoCode(ignore: true)]
|
|
public virtual async Task<IActionResult> GetProductCombinations(int productId)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(productId);
|
|
if (product == null)
|
|
return NotFound();
|
|
|
|
var model = await _productModelFactory.PrepareProductCombinationModelsAsync(product);
|
|
return Ok(model);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Recently viewed products
|
|
|
|
public virtual async Task<IActionResult> RecentlyViewedProducts()
|
|
{
|
|
if (!_catalogSettings.RecentlyViewedProductsEnabled)
|
|
return Content("");
|
|
|
|
var products = await _recentlyViewedProductsService.GetRecentlyViewedProductsAsync(_catalogSettings.RecentlyViewedProductsNumber);
|
|
|
|
var model = new List<ProductOverviewModel>();
|
|
model.AddRange(await _productModelFactory.PrepareProductOverviewModelsAsync(products));
|
|
|
|
return View(model);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Product reviews
|
|
|
|
[HttpPost, ActionName("ProductReviews")]
|
|
[ValidateCaptcha]
|
|
public virtual async Task<IActionResult> ProductReviewsAdd(int productId, ProductReviewsModel model, bool captchaValid)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(productId);
|
|
var currentStore = await _storeContext.GetCurrentStoreAsync();
|
|
|
|
if (product == null || product.Deleted || !product.Published || !product.AllowCustomerReviews ||
|
|
!await _productService.CanAddReviewAsync(product.Id, _catalogSettings.ShowProductReviewsPerStore ? currentStore.Id : 0))
|
|
return RedirectToRoute("Homepage");
|
|
|
|
//validate CAPTCHA
|
|
if (_captchaSettings.Enabled && _captchaSettings.ShowOnProductReviewPage && !captchaValid)
|
|
{
|
|
ModelState.AddModelError("", await _localizationService.GetResourceAsync("Common.WrongCaptchaMessage"));
|
|
}
|
|
|
|
await ValidateProductReviewAvailabilityAsync(product);
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
//save review
|
|
var rating = model.AddProductReview.Rating;
|
|
if (rating < 1 || rating > 5)
|
|
rating = _catalogSettings.DefaultProductRatingValue;
|
|
var isApproved = !_catalogSettings.ProductReviewsMustBeApproved;
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
|
|
var productReview = new ProductReview
|
|
{
|
|
ProductId = product.Id,
|
|
CustomerId = customer.Id,
|
|
Title = model.AddProductReview.Title,
|
|
ReviewText = model.AddProductReview.ReviewText,
|
|
Rating = rating,
|
|
HelpfulYesTotal = 0,
|
|
HelpfulNoTotal = 0,
|
|
IsApproved = isApproved,
|
|
CreatedOnUtc = DateTime.UtcNow,
|
|
StoreId = currentStore.Id,
|
|
};
|
|
|
|
await _productService.InsertProductReviewAsync(productReview);
|
|
|
|
//add product review and review type mapping
|
|
foreach (var additionalReview in model.AddAdditionalProductReviewList)
|
|
{
|
|
var additionalProductReview = new ProductReviewReviewTypeMapping
|
|
{
|
|
ProductReviewId = productReview.Id,
|
|
ReviewTypeId = additionalReview.ReviewTypeId,
|
|
Rating = additionalReview.Rating
|
|
};
|
|
|
|
await _reviewTypeService.InsertProductReviewReviewTypeMappingsAsync(additionalProductReview);
|
|
}
|
|
|
|
//update product totals
|
|
await _productService.UpdateProductReviewTotalsAsync(product);
|
|
|
|
//notify store owner
|
|
if (_catalogSettings.NotifyStoreOwnerAboutNewProductReviews)
|
|
await _workflowMessageService.SendProductReviewStoreOwnerNotificationMessageAsync(productReview, _localizationSettings.DefaultAdminLanguageId);
|
|
|
|
//activity log
|
|
await _customerActivityService.InsertActivityAsync("PublicStore.AddProductReview",
|
|
string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.AddProductReview"), product.Name), product);
|
|
|
|
//raise event
|
|
if (productReview.IsApproved)
|
|
await _eventPublisher.PublishAsync(new ProductReviewApprovedEvent(productReview));
|
|
|
|
model = await _productModelFactory.PrepareProductReviewsModelAsync(product);
|
|
model.AddProductReview.Title = null;
|
|
model.AddProductReview.ReviewText = null;
|
|
|
|
if (!isApproved)
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Reviews.SeeAfterApproving"));
|
|
else
|
|
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Reviews.SuccessfullyAdded"));
|
|
|
|
var seName = await _urlRecordService.GetSeNameAsync(product);
|
|
var productUrl = await _nopUrlHelper.RouteGenericUrlAsync<Product>(new { SeName = seName });
|
|
return LocalRedirect(productUrl);
|
|
}
|
|
|
|
//If we got this far, something failed, redisplay form
|
|
RouteData.Values["action"] = "ProductDetails";
|
|
|
|
//model
|
|
var productModel = await _productModelFactory.PrepareProductDetailsModelAsync(product);
|
|
//template
|
|
var productTemplateViewPath = await _productModelFactory.PrepareProductTemplateViewPathAsync(product);
|
|
|
|
return View(productTemplateViewPath, productModel);
|
|
}
|
|
|
|
[HttpPost]
|
|
public virtual async Task<IActionResult> SetProductReviewHelpfulness(int productReviewId, bool washelpful)
|
|
{
|
|
var productReview = await _productService.GetProductReviewByIdAsync(productReviewId) ?? throw new ArgumentException("No product review found with the specified id");
|
|
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
if (await _customerService.IsGuestAsync(customer) && !_catalogSettings.AllowAnonymousUsersToReviewProduct)
|
|
{
|
|
return Json(new
|
|
{
|
|
Result = await _localizationService.GetResourceAsync("Reviews.Helpfulness.OnlyRegistered"),
|
|
TotalYes = productReview.HelpfulYesTotal,
|
|
TotalNo = productReview.HelpfulNoTotal
|
|
});
|
|
}
|
|
|
|
//customers aren't allowed to vote for their own reviews
|
|
if (productReview.CustomerId == customer.Id)
|
|
{
|
|
return Json(new
|
|
{
|
|
Result = await _localizationService.GetResourceAsync("Reviews.Helpfulness.YourOwnReview"),
|
|
TotalYes = productReview.HelpfulYesTotal,
|
|
TotalNo = productReview.HelpfulNoTotal
|
|
});
|
|
}
|
|
|
|
await _productService.SetProductReviewHelpfulnessAsync(productReview, washelpful);
|
|
|
|
//new totals
|
|
await _productService.UpdateProductReviewHelpfulnessTotalsAsync(productReview);
|
|
|
|
return Json(new
|
|
{
|
|
Result = await _localizationService.GetResourceAsync("Reviews.Helpfulness.SuccessfullyVoted"),
|
|
TotalYes = productReview.HelpfulYesTotal,
|
|
TotalNo = productReview.HelpfulNoTotal
|
|
});
|
|
}
|
|
|
|
public virtual async Task<IActionResult> CustomerProductReviews(int? pageNumber)
|
|
{
|
|
if (await _customerService.IsGuestAsync(await _workContext.GetCurrentCustomerAsync()))
|
|
return Challenge();
|
|
|
|
if (!_catalogSettings.ShowProductReviewsTabOnAccountPage)
|
|
{
|
|
return RedirectToRoute("CustomerInfo");
|
|
}
|
|
|
|
var model = await _productModelFactory.PrepareCustomerProductReviewsModelAsync(pageNumber);
|
|
|
|
return View(model);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Email a friend
|
|
|
|
public virtual async Task<IActionResult> ProductEmailAFriend(int productId)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(productId);
|
|
if (product == null || product.Deleted || !product.Published || !_catalogSettings.EmailAFriendEnabled)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
var model = new ProductEmailAFriendModel();
|
|
model = await _productModelFactory.PrepareProductEmailAFriendModelAsync(model, product, false);
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost, ActionName("ProductEmailAFriend")]
|
|
[FormValueRequired("send-email")]
|
|
[ValidateCaptcha]
|
|
public virtual async Task<IActionResult> ProductEmailAFriendSend(ProductEmailAFriendModel model, bool captchaValid)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(model.ProductId);
|
|
if (product == null || product.Deleted || !product.Published || !_catalogSettings.EmailAFriendEnabled)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
//validate CAPTCHA
|
|
if (_captchaSettings.Enabled && _captchaSettings.ShowOnEmailProductToFriendPage && !captchaValid)
|
|
{
|
|
ModelState.AddModelError("", await _localizationService.GetResourceAsync("Common.WrongCaptchaMessage"));
|
|
}
|
|
|
|
//check whether the current customer is guest and ia allowed to email a friend
|
|
var customer = await _workContext.GetCurrentCustomerAsync();
|
|
if (await _customerService.IsGuestAsync(customer) && !_catalogSettings.AllowAnonymousUsersToEmailAFriend)
|
|
{
|
|
ModelState.AddModelError("", await _localizationService.GetResourceAsync("Products.EmailAFriend.OnlyRegisteredUsers"));
|
|
}
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
//email
|
|
await _workflowMessageService.SendProductEmailAFriendMessageAsync(customer,
|
|
(await _workContext.GetWorkingLanguageAsync()).Id, product,
|
|
model.YourEmailAddress, model.FriendEmail,
|
|
_htmlFormatter.FormatText(model.PersonalMessage, false, true, false, false, false, false));
|
|
|
|
model = await _productModelFactory.PrepareProductEmailAFriendModelAsync(model, product, true);
|
|
model.SuccessfullySent = true;
|
|
model.Result = await _localizationService.GetResourceAsync("Products.EmailAFriend.SuccessfullySent");
|
|
|
|
return View(model);
|
|
}
|
|
|
|
//If we got this far, something failed, redisplay form
|
|
model = await _productModelFactory.PrepareProductEmailAFriendModelAsync(model, product, true);
|
|
return View(model);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Comparing products
|
|
|
|
[HttpPost]
|
|
public virtual async Task<IActionResult> AddProductToCompareList(int productId)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(productId);
|
|
if (product == null || product.Deleted || !product.Published)
|
|
return Json(new
|
|
{
|
|
success = false,
|
|
message = "No product found with the specified ID"
|
|
});
|
|
|
|
if (!_catalogSettings.CompareProductsEnabled)
|
|
return Json(new
|
|
{
|
|
success = false,
|
|
message = "Product comparison is disabled"
|
|
});
|
|
|
|
await _compareProductsService.AddProductToCompareListAsync(productId);
|
|
|
|
//activity log
|
|
await _customerActivityService.InsertActivityAsync("PublicStore.AddToCompareList",
|
|
string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.AddToCompareList"), product.Name), product);
|
|
|
|
return Json(new
|
|
{
|
|
success = true,
|
|
message = string.Format(await _localizationService.GetResourceAsync("Products.ProductHasBeenAddedToCompareList.Link"), Url.RouteUrl("CompareProducts"))
|
|
//use the code below (commented) if you want a customer to be automatically redirected to the compare products page
|
|
//redirect = Url.RouteUrl("CompareProducts"),
|
|
});
|
|
}
|
|
|
|
public virtual async Task<IActionResult> RemoveProductFromCompareList(int productId)
|
|
{
|
|
var product = await _productService.GetProductByIdAsync(productId);
|
|
if (product == null)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
if (!_catalogSettings.CompareProductsEnabled)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
await _compareProductsService.RemoveProductFromCompareListAsync(productId);
|
|
|
|
return RedirectToRoute("CompareProducts");
|
|
}
|
|
|
|
public virtual async Task<IActionResult> CompareProducts()
|
|
{
|
|
if (!_catalogSettings.CompareProductsEnabled)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
var model = new CompareProductsModel
|
|
{
|
|
IncludeShortDescriptionInCompareProducts = _catalogSettings.IncludeShortDescriptionInCompareProducts,
|
|
IncludeFullDescriptionInCompareProducts = _catalogSettings.IncludeFullDescriptionInCompareProducts,
|
|
};
|
|
|
|
var products = await (await _compareProductsService.GetComparedProductsAsync())
|
|
//ACL and store mapping
|
|
.WhereAwait(async p => await _aclService.AuthorizeAsync(p) && await _storeMappingService.AuthorizeAsync(p))
|
|
//availability dates
|
|
.Where(p => _productService.ProductIsAvailable(p)).ToListAsync();
|
|
|
|
//prepare model
|
|
var poModels = (await _productModelFactory.PrepareProductOverviewModelsAsync(products, prepareSpecificationAttributes: true))
|
|
.ToList();
|
|
foreach (var poModel in poModels)
|
|
{
|
|
model.Products.Add(poModel);
|
|
}
|
|
|
|
return View(model);
|
|
}
|
|
|
|
public virtual IActionResult ClearCompareList()
|
|
{
|
|
if (!_catalogSettings.CompareProductsEnabled)
|
|
return RedirectToRoute("Homepage");
|
|
|
|
_compareProductsService.ClearCompareProducts();
|
|
|
|
return RedirectToRoute("CompareProducts");
|
|
}
|
|
|
|
#endregion
|
|
} |