From dea4e91fa2559799e1fad61c5ba9041517ee9562 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Mon, 30 Aug 2021 11:28:54 +0200 Subject: [PATCH 1/9] Remove unused variable --- src/Web/Grand.Web/Views/Checkout/Start.cshtml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Web/Grand.Web/Views/Checkout/Start.cshtml b/src/Web/Grand.Web/Views/Checkout/Start.cshtml index 5d8b7224e..2d2d9d8e6 100644 --- a/src/Web/Grand.Web/Views/Checkout/Start.cshtml +++ b/src/Web/Grand.Web/Views/Checkout/Start.cshtml @@ -16,8 +16,6 @@ } - var storeLocation = workContext.CurrentStore.SslEnabled ? workContext.CurrentStore.SecureUrl.TrimEnd('/') : workContext.CurrentStore.Url.TrimEnd('/'); - //title pagebuilder.AddTitleParts(Loc["Title.Checkout"]); } From 33b55367208bd619d18fc23e28526f6343010cd7 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Mon, 30 Aug 2021 11:38:55 +0200 Subject: [PATCH 2/9] Minor changes - robots.txt --- .../Common/GetRobotsTextFileHandler.cs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs b/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs index 94072347c..ab4cea2af 100644 --- a/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs +++ b/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs @@ -117,24 +117,14 @@ private async Task PrepareRobotsTextFile() const string newLine = "\r\n"; //Environment.NewLine sb.Append("User-agent: *"); sb.Append(newLine); + + var storeLocation = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); + //sitemaps - if (_config.SeoFriendlyUrlsForLanguagesEnabled) - { - //URLs are localizable. Append SEO code - foreach (var language in await _languageService.GetAllLanguages(storeId: _workContext.CurrentStore.Id)) - { - sb.AppendFormat("Sitemap: {0}{1}/sitemap.xml", _workContext.CurrentStore.Url, language.UniqueSeoCode); - sb.Append(newLine); - } - } - else - { - //localizable paths (without SEO code) - sb.AppendFormat("Sitemap: {0}sitemap.xml", _workContext.CurrentStore.Url); - sb.Append(newLine); - } + sb.AppendFormat("Sitemap: {0}sitemap.xml", storeLocation); + sb.Append(newLine); + //host - var storeLocation = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); sb.AppendFormat("Host: {0}", storeLocation); sb.Append(newLine); From 92a7e744aa9f046fd322263f6a443808979ea6c3 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Mon, 30 Aug 2021 11:45:34 +0200 Subject: [PATCH 3/9] Add new entity - DomainHost --- src/Core/Grand.Domain/Stores/DomainHost.cs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/Core/Grand.Domain/Stores/DomainHost.cs diff --git a/src/Core/Grand.Domain/Stores/DomainHost.cs b/src/Core/Grand.Domain/Stores/DomainHost.cs new file mode 100644 index 000000000..bd99b760c --- /dev/null +++ b/src/Core/Grand.Domain/Stores/DomainHost.cs @@ -0,0 +1,7 @@ +namespace Grand.Domain.Stores +{ + public class DomainHost : BaseEntity + { + public string Url { get; set; } + } +} From 49ef7b0bbdef47944e2c6721dc307764bb7f66ef Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 31 Aug 2021 12:11:08 +0200 Subject: [PATCH 4/9] Add support for multiple domains per store #99 --- .../Controllers/TokenWebController.cs | 2 +- .../Products/ProductAttributeFormatter.cs | 2 +- .../CheckoutAttributeFormatter.cs | 2 +- .../Extensions/AffiliateExtensions.cs | 2 +- .../Services/Campaigns/CampaignService.cs | 12 +- .../Contacts/ContactAttributeParser.cs | 2 +- .../Customers/CustomerReminderService.cs | 6 +- .../GetMerchandiseReturnTokensCommand.cs | 1 + .../Models/Tokens/GetOrderTokensCommand.cs | 1 + .../Models/Tokens/GetShipmentTokensCommand.cs | 1 + .../DotLiquidDrops/LiquidAskQuestion.cs | 8 +- .../LiquidAttributeCombination.cs | 2 +- .../DotLiquidDrops/LiquidAuctions.cs | 4 +- .../DotLiquidDrops/LiquidBlogComment.cs | 26 ++- .../DotLiquidDrops/LiquidContactUs.cs | 8 +- .../DotLiquidDrops/LiquidCustomer.cs | 21 +- .../DotLiquidDrops/LiquidEmail.cs | 2 +- .../DotLiquidDrops/LiquidEmailAFriend.cs | 6 +- .../DotLiquidDrops/LiquidGiftVoucher.cs | 2 +- .../DotLiquidDrops/LiquidKnowledgebase.cs | 24 ++- .../DotLiquidDrops/LiquidMerchandiseReturn.cs | 19 +- .../LiquidMerchandiseReturnItem.cs | 8 +- .../DotLiquidDrops/LiquidNewsComment.cs | 18 +- .../LiquidNewsLetterSubscription.cs | 18 +- .../DotLiquidDrops/LiquidObjectBuilder.cs | 39 ++-- .../DotLiquidDrops/LiquidOrder.cs | 30 ++- .../DotLiquidDrops/LiquidOrderItem.cs | 23 ++- .../LiquidOutOfStockSubscription.cs | 9 +- .../DotLiquidDrops/LiquidProduct.cs | 15 +- .../DotLiquidDrops/LiquidProductReview.cs | 10 +- .../DotLiquidDrops/LiquidShipment.cs | 15 +- .../DotLiquidDrops/LiquidShipmentItem.cs | 12 +- .../DotLiquidDrops/LiquidShoppingCart.cs | 2 +- .../DotLiquidDrops/LiquidShoppingCartItem.cs | 10 +- .../DotLiquidDrops/LiquidStore.cs | 6 +- .../LiquidVatValidationResult.cs | 4 +- .../DotLiquidDrops/LiquidVendor.cs | 2 +- .../DotLiquidDrops/LiquidVendorReview.cs | 4 +- .../Interfaces/IMessageProviderService.cs | 2 - .../Services/MessageProviderService.cs | 125 ++++++------ ...etMerchandiseReturnTokensCommandHandler.cs | 13 +- .../Messages/GetOrderTokensCommandHandler.cs | 4 +- .../GetShipmentTokensCommandHandler.cs | 2 +- .../Installation/InstallDataStores.cs | 4 +- src/Core/Grand.Domain/Stores/DomainHost.cs | 5 +- src/Core/Grand.Domain/Stores/Store.cs | 5 +- .../Grand.Domain/Stores/StoreExtensions.cs | 39 ++-- src/Core/Grand.Domain/SubBaseEntity.cs | 4 +- .../Caching/Constants/CommonCacheKey.cs | 23 +++ src/Core/Grand.Infrastructure/IStoreHelper.cs | 4 +- src/Core/Grand.Infrastructure/IWorkContext.cs | 5 + .../PayPalStandardPaymentProvider.cs | 2 +- .../WidgetsGoogleAnalyticsViewComponent.cs | 2 +- .../Store/_CreateOrUpdate.TabDomains.cshtml | 119 ++++++++++++ .../Store/_CreateOrUpdate.TabInfo.cshtml | 157 +++++++++++++++ .../Admin/Views/Store/_CreateOrUpdate.cshtml | 180 ++---------------- .../Controllers/CommonController.cs | 2 +- .../Controllers/StoreController.cs | 91 ++++++++- .../Extensions/PluginExtensions.cs | 2 +- .../Interfaces/IStoreViewModelService.cs | 3 + .../Grand.Web.Admin/Mapper/StoreProfile.cs | 6 + .../Models/Stores/StoreModel.cs | 17 +- .../Services/DiscountViewModelService.cs | 2 +- .../Services/StoreViewModelService.cs | 106 +++++++++-- .../Validators/Stores/DomainHostValidator.cs | 32 ++++ .../ServiceCollectionExtensions.cs | 2 +- src/Web/Grand.Web.Common/StoreHelper.cs | 44 ++++- src/Web/Grand.Web.Common/WorkContext.cs | 7 +- .../App_Data/Resources/DefaultLanguage.xml | 24 +++ .../Controllers/CheckoutController.cs | 2 +- .../Catalog/GetSearchAutoCompleteHandler.cs | 2 +- .../Common/GetRobotsTextFileHandler.cs | 2 +- 72 files changed, 970 insertions(+), 447 deletions(-) create mode 100644 src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabDomains.cshtml create mode 100644 src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabInfo.cshtml create mode 100644 src/Web/Grand.Web.Admin/Validators/Stores/DomainHostValidator.cs diff --git a/src/API/Grand.Api/Controllers/TokenWebController.cs b/src/API/Grand.Api/Controllers/TokenWebController.cs index 0528e85fe..8b96e175e 100644 --- a/src/API/Grand.Api/Controllers/TokenWebController.cs +++ b/src/API/Grand.Api/Controllers/TokenWebController.cs @@ -51,7 +51,7 @@ public TokenWebController( [HttpPost] public async Task Guest() { - var customer = await _customerService.InsertGuestCustomer(_storeHelper.HostStore); + var customer = await _customerService.InsertGuestCustomer(_storeHelper.StoreHost); var claims = new Dictionary { { "Guid", customer.CustomerGuid.ToString()} }; diff --git a/src/Business/Grand.Business.Catalog/Services/Products/ProductAttributeFormatter.cs b/src/Business/Grand.Business.Catalog/Services/Products/ProductAttributeFormatter.cs index 0589e3ee2..28f3e89cc 100644 --- a/src/Business/Grand.Business.Catalog/Services/Products/ProductAttributeFormatter.cs +++ b/src/Business/Grand.Business.Catalog/Services/Products/ProductAttributeFormatter.cs @@ -224,7 +224,7 @@ private async Task PrepareFormattedAttribute(Product product, ILi fileName = WebUtility.HtmlEncode(fileName); if (allowHyperlinks) { - var downloadLink = string.Format("{0}/download/getfileupload/?downloadId={1}", _workContext.CurrentStore.Url.TrimEnd('/'), download.DownloadGuid); + var downloadLink = string.Format("{0}/download/getfileupload/?downloadId={1}", _workContext.CurrentHost.Url.TrimEnd('/'), download.DownloadGuid); attributeText = string.Format("{1}", downloadLink, fileName); } else diff --git a/src/Business/Grand.Business.Checkout/Services/CheckoutAttributes/CheckoutAttributeFormatter.cs b/src/Business/Grand.Business.Checkout/Services/CheckoutAttributes/CheckoutAttributeFormatter.cs index 6dbf0e3ef..c9ab921c5 100644 --- a/src/Business/Grand.Business.Checkout/Services/CheckoutAttributes/CheckoutAttributeFormatter.cs +++ b/src/Business/Grand.Business.Checkout/Services/CheckoutAttributes/CheckoutAttributeFormatter.cs @@ -108,7 +108,7 @@ public virtual async Task FormatAttributes(IList custom if (allowHyperlinks) { //hyperlinks are allowed - var downloadLink = string.Format("{0}/download/getfileupload/?downloadId={1}", _workContext.CurrentStore.Url.TrimEnd('/'), download.DownloadGuid); + var downloadLink = string.Format("{0}/download/getfileupload/?downloadId={1}", _workContext.CurrentHost.Url.TrimEnd('/'), download.DownloadGuid); attributeText = string.Format("{1}", downloadLink, fileName); } else diff --git a/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs b/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs index 4fcff6d3d..3b128f443 100644 --- a/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs +++ b/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs @@ -54,7 +54,7 @@ public static string GenerateUrl(this Affiliate affiliate, IWorkContext workCont if (workContext == null) throw new ArgumentNullException(nameof(workContext)); - var storeUrl = workContext.CurrentStore.Url.TrimEnd('/'); + var storeUrl = workContext.CurrentHost.Url.TrimEnd('/'); var url = !String.IsNullOrEmpty(affiliate.FriendlyUrlName) ? CommonExtensions.ModifyQueryString(storeUrl, "affiliate", affiliate.FriendlyUrlName) : CommonExtensions.ModifyQueryString(storeUrl, "affiliateid", affiliate.Id); diff --git a/src/Business/Grand.Business.Marketing/Services/Campaigns/CampaignService.cs b/src/Business/Grand.Business.Marketing/Services/Campaigns/CampaignService.cs index 77063b311..7fb8abb52 100644 --- a/src/Business/Grand.Business.Marketing/Services/Campaigns/CampaignService.cs +++ b/src/Business/Grand.Business.Marketing/Services/Campaigns/CampaignService.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Grand.Infrastructure; namespace Grand.Business.Marketing.Services.Campaigns { @@ -33,6 +34,7 @@ public partial class CampaignService : ICampaignService private readonly ICustomerActivityService _customerActivityService; private readonly ITranslationService _translationService; private readonly ILanguageService _languageService; + private readonly IWorkContext _workContext; public CampaignService(IRepository campaignRepository, IRepository campaignHistoryRepository, @@ -44,7 +46,8 @@ public CampaignService(IRepository campaignRepository, IMediator mediator, ICustomerActivityService customerActivityService, ITranslationService translationService, - ILanguageService languageService) + ILanguageService languageService, + IWorkContext workContext) { _campaignRepository = campaignRepository; _campaignHistoryRepository = campaignHistoryRepository; @@ -59,6 +62,7 @@ public CampaignService(IRepository campaignRepository, _customerActivityService = customerActivityService; _translationService = translationService; _languageService = languageService; + _workContext = workContext; } /// @@ -326,11 +330,11 @@ public virtual async Task SendCampaign(Campaign campaign, EmailAccount emai store = (await _storeService.GetAllStores()).FirstOrDefault(); builder.AddStoreTokens(store, language, emailAccount) - .AddNewsLetterSubscriptionTokens(subscription, store); + .AddNewsLetterSubscriptionTokens(subscription, store, _workContext.CurrentHost); if (customer != null) { - builder.AddCustomerTokens(customer, store, language) + builder.AddCustomerTokens(customer, store, _workContext.CurrentHost, language) .AddShoppingCartTokens(customer, store, language); } @@ -392,7 +396,7 @@ public virtual async Task SendCampaign(Campaign campaign, EmailAccount emailAcco var customer = await _customerService.GetCustomerByEmail(email); if (customer != null) { - builder.AddCustomerTokens(customer, store, language) + builder.AddCustomerTokens(customer, store, _workContext.CurrentHost, language) .AddShoppingCartTokens(customer, store, language); } diff --git a/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs b/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs index 778449b75..f0dbbd21c 100644 --- a/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs +++ b/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs @@ -232,7 +232,7 @@ public virtual async Task FormatAttributes( if (allowHyperlinks) { //hyperlinks are allowed - var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _workContext.CurrentStore.Url.TrimEnd('/'), download.DownloadGuid); + var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _workContext.CurrentHost.Url.TrimEnd('/'), download.DownloadGuid); attributeText = string.Format("{1}", downloadLink, fileName); } else diff --git a/src/Business/Grand.Business.Marketing/Services/Customers/CustomerReminderService.cs b/src/Business/Grand.Business.Marketing/Services/Customers/CustomerReminderService.cs index 54c442407..87b8e44cd 100644 --- a/src/Business/Grand.Business.Marketing/Services/Customers/CustomerReminderService.cs +++ b/src/Business/Grand.Business.Marketing/Services/Customers/CustomerReminderService.cs @@ -101,7 +101,7 @@ protected async Task SendEmail(Customer customer, CustomerReminder custome var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language) + .AddCustomerTokens(customer, store, null, language) .AddShoppingCartTokens(customer, store, language); LiquidObject liquidObject = await builder.BuildAsync(); @@ -171,9 +171,9 @@ protected async Task SendEmail(Customer customer, Order order, CustomerRem var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language) + .AddCustomerTokens(customer, store, null, language) .AddShoppingCartTokens(customer, store, language) - .AddOrderTokens(order, customer, await _storeService.GetStoreById(order.StoreId)); + .AddOrderTokens(order, customer, await _storeService.GetStoreById(order.StoreId), null); var liquidObject = await builder.BuildAsync(); var body = LiquidExtensions.Render(liquidObject, reminderLevel.Body); diff --git a/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetMerchandiseReturnTokensCommand.cs b/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetMerchandiseReturnTokensCommand.cs index e3f891514..3f3af103e 100644 --- a/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetMerchandiseReturnTokensCommand.cs +++ b/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetMerchandiseReturnTokensCommand.cs @@ -11,6 +11,7 @@ public class GetMerchandiseReturnTokensCommand : IRequest public Order Order { get; set; } public Customer Customer { get; set; } public Store Store { get; set; } + public DomainHost Host { get; set; } public OrderNote OrderNote { get; set; } = null; public Vendor Vendor { get; set; } = null; public double RefundedAmount { get; set; } = 0; diff --git a/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetShipmentTokensCommand.cs b/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetShipmentTokensCommand.cs index 86ce4d384..440a3885f 100644 --- a/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetShipmentTokensCommand.cs +++ b/src/Business/Grand.Business.Messages/Commands/Models/Tokens/GetShipmentTokensCommand.cs @@ -12,6 +12,7 @@ public class GetShipmentTokensCommand : IRequest public Shipment Shipment { get; set; } public Order Order { get; set; } public Store Store { get; set; } + public DomainHost Host { get; set; } public Language Language { get; set; } } } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAskQuestion.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAskQuestion.cs index 4bc2fe83f..bfdef407f 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAskQuestion.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAskQuestion.cs @@ -5,10 +5,10 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidAskQuestion : Drop { - private string message; - private string email; - private string fullName; - private string phone; + private readonly string message; + private readonly string email; + private readonly string fullName; + private readonly string phone; public LiquidAskQuestion(string message, string email, string fullName, string phone) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAttributeCombination.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAttributeCombination.cs index 1499c9ec9..15083984a 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAttributeCombination.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAttributeCombination.cs @@ -7,7 +7,7 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidAttributeCombination : Drop { - private ProductAttributeCombination _combination; + private readonly ProductAttributeCombination _combination; public LiquidAttributeCombination(ProductAttributeCombination combination) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAuctions.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAuctions.cs index 32bc9e87b..04a05e697 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAuctions.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidAuctions.cs @@ -6,8 +6,8 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidAuctions : Drop { - private Product _product; - private Bid _bid; + private readonly Product _product; + private readonly Bid _bid; public LiquidAuctions(Product product, Bid bid = null) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidBlogComment.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidBlogComment.cs index ccfa0bd03..9b6b3d5f8 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidBlogComment.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidBlogComment.cs @@ -9,16 +9,24 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidBlogComment : Drop { - private BlogComment _blogComment; - private BlogPost _blogPost; - private Store _store; + private readonly BlogComment _blogComment; + private readonly BlogPost _blogPost; + private readonly Store _store; + private readonly DomainHost _host; private readonly Language _language; - public LiquidBlogComment(BlogComment blogComment, BlogPost blogPost, Store store, Language language) + + private string url; + + public LiquidBlogComment(BlogComment blogComment, BlogPost blogPost, Store store, DomainHost host, Language language) { _blogComment = blogComment; _blogPost = blogPost; _store = store; + _host = host; _language = language; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + AdditionalTokens = new Dictionary(); } @@ -31,7 +39,15 @@ public string BlogPostURL { get { - return $"{(_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/'))}/{_blogPost.GetSeName(_language.Id)}"; + return $"{url}/{_blogPost.GetSeName(_language.Id)}"; + } + } + + public string BlogPostCommentText + { + get + { + return _blogComment?.CommentText; } } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidContactUs.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidContactUs.cs index 1dbdb23d2..2a3c63d57 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidContactUs.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidContactUs.cs @@ -5,10 +5,10 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidContactUs : Drop { - private string senderEmail; - private string senderName; - private string body; - private string attributeDescription; + private readonly string senderEmail; + private readonly string senderName; + private readonly string body; + private readonly string attributeDescription; public LiquidContactUs(string senderEmail, string senderName, string body, string attributeDescription) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs index 9a894755b..c2634272d 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs @@ -11,15 +11,18 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidCustomer : Drop { - private Customer _customer; - private CustomerNote _customerNote; - private Store _store; - - public LiquidCustomer(Customer customer, Store store, CustomerNote customerNote = null) + private readonly Customer _customer; + private readonly CustomerNote _customerNote; + private readonly Store _store; + private readonly DomainHost _domainHost; + private readonly string url; + public LiquidCustomer(Customer customer, Store store, DomainHost domainHost, CustomerNote customerNote = null) { _customer = customer; _customerNote = customerNote; _store = store; + _domainHost = domainHost; + url = _domainHost?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); AdditionalTokens = new Dictionary(); } @@ -105,17 +108,17 @@ public string VatNumberStatus public string PasswordRecoveryURL { - get { return string.Format("{0}/passwordrecovery/confirm?token={1}&email={2}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _customer.GetUserFieldFromEntity(SystemCustomerFieldNames.PasswordRecoveryToken), WebUtility.UrlEncode(_customer.Email)); } + get { return string.Format("{0}/passwordrecovery/confirm?token={1}&email={2}", url, _customer.GetUserFieldFromEntity(SystemCustomerFieldNames.PasswordRecoveryToken), WebUtility.UrlEncode(_customer.Email)); } } public string AccountActivationURL { - get { return string.Format("{0}/account/activation?token={1}&email={2}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _customer.GetUserFieldFromEntity(SystemCustomerFieldNames.AccountActivationToken), WebUtility.UrlEncode(_customer.Email)); ; } + get { return string.Format("{0}/account/activation?token={1}&email={2}", url, _customer.GetUserFieldFromEntity(SystemCustomerFieldNames.AccountActivationToken), WebUtility.UrlEncode(_customer.Email)); ; } } public string WishlistURLForCustomer { - get { return string.Format("{0}/wishlist/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _customer.CustomerGuid); } + get { return string.Format("{0}/wishlist/{1}", url, _customer.CustomerGuid); } } public string NewNoteText @@ -130,7 +133,7 @@ public string NewTitleText public string CustomerNoteAttachmentUrl { - get { return string.Format("{0}/download/customernotefile/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _customerNote.Id); } + get { return string.Format("{0}/download/customernotefile/{1}", url, _customerNote.Id); } } public string Token diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmail.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmail.cs index 0163e619e..771545d49 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmail.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmail.cs @@ -4,7 +4,7 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidEmail : Drop { - private string _emailId { get; set; } + private readonly string _emailId; public LiquidEmail(string emailId) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmailAFriend.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmailAFriend.cs index 656531ff7..9c9218412 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmailAFriend.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidEmailAFriend.cs @@ -5,9 +5,9 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidEmailAFriend : Drop { - private string _personalMessage; - private string _customerEmail; - private string _friendsEmail; + private readonly string _personalMessage; + private readonly string _customerEmail; + private readonly string _friendsEmail; public LiquidEmailAFriend(string personalMessage, string customerEmail, string friendsEmail) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidGiftVoucher.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidGiftVoucher.cs index 16089f6cf..22b2b6db5 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidGiftVoucher.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidGiftVoucher.cs @@ -8,7 +8,7 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidGiftVoucher : Drop { - private GiftVoucher _giftVoucher; + private readonly GiftVoucher _giftVoucher; public LiquidGiftVoucher(GiftVoucher giftVoucher) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidKnowledgebase.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidKnowledgebase.cs index 5180ef3f7..ea4a11984 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidKnowledgebase.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidKnowledgebase.cs @@ -9,30 +9,40 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidKnowledgebase : Drop { - private KnowledgebaseArticle _article; - private KnowledgebaseArticleComment _articleComment; - private Store _store; - private Language _language; + private readonly KnowledgebaseArticle _article; + private readonly KnowledgebaseArticleComment _articleComment; + private readonly Store _store; + private readonly DomainHost _host; + private readonly Language _language; - public LiquidKnowledgebase(KnowledgebaseArticle article, KnowledgebaseArticleComment articleComment, Store store, Language language) + private string url; + + public LiquidKnowledgebase(KnowledgebaseArticle article, KnowledgebaseArticleComment articleComment, Store store, DomainHost host, Language language) { _article = article; _articleComment = articleComment; _store = store; + _host = host; _language = language; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + AdditionalTokens = new Dictionary(); } - public string ArticleCommentTitle + public string ArticleTitle { get { return _article.Name; } } + public string ArticleCommentText { + get { return _articleComment.CommentText; } + } public string ArticleCommentUrl { get { - return $"{(_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/'))}/{_article.GetSeName(_language.Id)}"; + return $"{url}/{_article.GetSeName(_language.Id)}"; } } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturn.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturn.cs index 463a570ce..c27c55384 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturn.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturn.cs @@ -9,18 +9,27 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidMerchandiseReturn : Drop { - private MerchandiseReturn _merchandiseReturn; - private Order _order; - private Store _store; + private readonly MerchandiseReturn _merchandiseReturn; + private readonly Order _order; + private readonly Store _store; + private readonly DomainHost _host; + private MerchandiseReturnNote _merchandiseReturnNote; private ICollection _items; - public LiquidMerchandiseReturn(MerchandiseReturn merchandiseReturn, Store store, Order order, MerchandiseReturnNote merchandiseReturnNote = null) + private string url; + + public LiquidMerchandiseReturn(MerchandiseReturn merchandiseReturn, Store store, DomainHost host, + Order order, MerchandiseReturnNote merchandiseReturnNote = null) { _merchandiseReturn = merchandiseReturn; _order = order; _store = store; + _host = host; _merchandiseReturnNote = merchandiseReturnNote; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + _items = new List(); AdditionalTokens = new Dictionary(); } @@ -156,7 +165,7 @@ public string MerchandiseReturnNoteAttachmentUrl { get { - return string.Format("{0}/download/merchandisereturnnotefile/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _merchandiseReturnNote?.Id); + return string.Format("{0}/download/merchandisereturnnotefile/{1}", url, _merchandiseReturnNote?.Id); } } public IDictionary AdditionalTokens { get; set; } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturnItem.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturnItem.cs index b68958e90..24c1cb06d 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturnItem.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidMerchandiseReturnItem.cs @@ -9,10 +9,10 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidMerchandiseReturnItem : Drop { - private MerchandiseReturnItem _item; - private Product _product; - private OrderItem _orderItem; - private string _languageId; + private readonly MerchandiseReturnItem _item; + private readonly Product _product; + private readonly OrderItem _orderItem; + private readonly string _languageId; public LiquidMerchandiseReturnItem(MerchandiseReturnItem item, OrderItem orderItem, Product product, string languageid) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsComment.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsComment.cs index de9b4e47f..746ef78c8 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsComment.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsComment.cs @@ -9,17 +9,23 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidNewsComment : Drop { - private NewsComment _newsComment; - private NewsItem _newsItem; - private Store _store; - private Language _language; + private readonly NewsComment _newsComment; + private readonly NewsItem _newsItem; + private readonly Store _store; + private readonly DomainHost _host; + private readonly Language _language; - public LiquidNewsComment(NewsItem newsItem, NewsComment newsComment, Store store, Language language) + private string url; + + public LiquidNewsComment(NewsItem newsItem, NewsComment newsComment, Store store, DomainHost host, Language language) { _newsComment = newsComment; _newsItem = newsItem; _store = store; _language = language; + _host = host; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); AdditionalTokens = new Dictionary(); } @@ -41,7 +47,7 @@ public string CommentTitle public string NewsURL { - get { return $"{(_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/'))}/{_newsItem.GetSeName(_language.Id)}"; } + get { return $"{url}/{_newsItem.GetSeName(_language.Id)}"; } } public IDictionary AdditionalTokens { get; set; } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsLetterSubscription.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsLetterSubscription.cs index 2af613f19..31010d86b 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsLetterSubscription.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidNewsLetterSubscription.cs @@ -8,12 +8,20 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidNewsLetterSubscription : Drop { - private NewsLetterSubscription _subscription; - private Store _store; - public LiquidNewsLetterSubscription(NewsLetterSubscription subscription, Store store) + private readonly NewsLetterSubscription _subscription; + private readonly Store _store; + private readonly DomainHost _host; + + private string url; + + public LiquidNewsLetterSubscription(NewsLetterSubscription subscription, Store store, DomainHost host) { _subscription = subscription; _store = store; + _host = host; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + AdditionalTokens = new Dictionary(); } @@ -27,7 +35,7 @@ public string ActivationUrl get { string urlFormat = "{0}/newsletter/subscriptionactivation/{1}/{2}"; - var activationUrl = String.Format(urlFormat, (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _subscription.NewsLetterSubscriptionGuid, "true"); + var activationUrl = String.Format(urlFormat, url, _subscription.NewsLetterSubscriptionGuid, "true"); return activationUrl; } } @@ -37,7 +45,7 @@ public string DeactivationUrl get { string urlFormat = "{0}/newsletter/subscriptionactivation/{1}/{2}"; - var deActivationUrl = String.Format(urlFormat, (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _subscription.NewsLetterSubscriptionGuid, "false"); + var deActivationUrl = String.Format(urlFormat, url, _subscription.NewsLetterSubscriptionGuid, "false"); return deActivationUrl; } } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidObjectBuilder.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidObjectBuilder.cs index f9abf7709..ab6eb3518 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidObjectBuilder.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidObjectBuilder.cs @@ -49,7 +49,7 @@ public LiquidObjectBuilder AddStoreTokens(Store store, Language language, EmailA return this; } - public LiquidObjectBuilder AddOrderTokens(Order order, Customer customer, Store store, OrderNote orderNote = null, Vendor vendor = null, double refundedAmount = 0) + public LiquidObjectBuilder AddOrderTokens(Order order, Customer customer, Store store, DomainHost host, OrderNote orderNote = null, Vendor vendor = null, double refundedAmount = 0) { _chain.Add(async liquidObject => { @@ -58,6 +58,7 @@ public LiquidObjectBuilder AddOrderTokens(Order order, Customer customer, Store Customer = customer, Vendor = vendor, Store = store, + Host = host, OrderNote = orderNote, RefundedAmount = refundedAmount }); @@ -67,23 +68,23 @@ public LiquidObjectBuilder AddOrderTokens(Order order, Customer customer, Store return this; } - public LiquidObjectBuilder AddShipmentTokens(Shipment shipment, Order order, Store store, Language language) + public LiquidObjectBuilder AddShipmentTokens(Shipment shipment, Order order, Store store, DomainHost host, Language language) { _chain.Add(async liquidObject => { - var liquidShipment = await _mediator.Send(new GetShipmentTokensCommand() { Shipment = shipment, Order = order, Store = store, Language = language }); + var liquidShipment = await _mediator.Send(new GetShipmentTokensCommand() { Shipment = shipment, Order = order, Store = store, Host = host, Language = language }); liquidObject.Shipment = liquidShipment; await _mediator.EntityTokensAdded(shipment, liquidShipment, liquidObject); }); return this; } - public LiquidObjectBuilder AddMerchandiseReturnTokens(MerchandiseReturn merchandiseReturn, Store store, Order order, Language language, MerchandiseReturnNote merchandiseReturnNote = null) + public LiquidObjectBuilder AddMerchandiseReturnTokens(MerchandiseReturn merchandiseReturn, Store store, DomainHost host, Order order, Language language, MerchandiseReturnNote merchandiseReturnNote = null) { _chain.Add(async liquidObject => { - var liquidMerchandiseReturn = await _mediator.Send(new GetMerchandiseReturnTokensCommand() { Order = order, Language = language, MerchandiseReturn = merchandiseReturn, MerchandiseReturnNote = merchandiseReturnNote, Store = store }); + var liquidMerchandiseReturn = await _mediator.Send(new GetMerchandiseReturnTokensCommand() { Order = order, Language = language, MerchandiseReturn = merchandiseReturn, MerchandiseReturnNote = merchandiseReturnNote, Store = store, Host = host }); liquidObject.MerchandiseReturn = liquidMerchandiseReturn; await _mediator.EntityTokensAdded(merchandiseReturn, liquidMerchandiseReturn, liquidObject); }); @@ -101,11 +102,11 @@ public LiquidObjectBuilder AddGiftVoucherTokens(GiftVoucher giftVoucher, Languag return this; } - public LiquidObjectBuilder AddCustomerTokens(Customer customer, Store store, Language language, CustomerNote customerNote = null) + public LiquidObjectBuilder AddCustomerTokens(Customer customer, Store store, DomainHost host, Language language, CustomerNote customerNote = null) { _chain.Add(async liquidObject => { - var liquidCustomer = new LiquidCustomer(customer, store, customerNote); + var liquidCustomer = new LiquidCustomer(customer, store, host, customerNote); liquidObject.Customer = liquidCustomer; await _mediator.EntityTokensAdded(customer, liquidCustomer, liquidObject); @@ -142,11 +143,11 @@ public LiquidObjectBuilder AddVendorTokens(Vendor vendor, Language language) return this; } - public LiquidObjectBuilder AddNewsLetterSubscriptionTokens(NewsLetterSubscription subscription, Store store) + public LiquidObjectBuilder AddNewsLetterSubscriptionTokens(NewsLetterSubscription subscription, Store store, DomainHost host) { _chain.Add(async liquidObject => { - var liquidNewsletterSubscription = new LiquidNewsLetterSubscription(subscription, store); + var liquidNewsletterSubscription = new LiquidNewsLetterSubscription(subscription, store, host); liquidObject.NewsLetterSubscription = liquidNewsletterSubscription; await _mediator.EntityTokensAdded(subscription, liquidNewsletterSubscription, liquidObject); }); @@ -175,44 +176,44 @@ public LiquidObjectBuilder AddVendorReviewTokens(Vendor vendor, VendorReview ven return this; } - public LiquidObjectBuilder AddBlogCommentTokens(BlogPost blogPost, BlogComment blogComment, Store store, Language language) + public LiquidObjectBuilder AddBlogCommentTokens(BlogPost blogPost, BlogComment blogComment, Store store, DomainHost host, Language language) { _chain.Add(async liquidObject => { - var liquidBlogComment = new LiquidBlogComment(blogComment, blogPost, store, language); + var liquidBlogComment = new LiquidBlogComment(blogComment, blogPost, store, host, language); liquidObject.BlogComment = liquidBlogComment; await _mediator.EntityTokensAdded(blogComment, liquidBlogComment, liquidObject); }); return this; } - public LiquidObjectBuilder AddArticleCommentTokens(KnowledgebaseArticle article, KnowledgebaseArticleComment articleComment, Store store, Language language) + public LiquidObjectBuilder AddArticleCommentTokens(KnowledgebaseArticle article, KnowledgebaseArticleComment articleComment, Store store, DomainHost host, Language language) { _chain.Add(async liquidObject => { - var liquidKnowledgebase = new LiquidKnowledgebase(article, articleComment, store, language); + var liquidKnowledgebase = new LiquidKnowledgebase(article, articleComment, store, host, language); liquidObject.Knowledgebase = liquidKnowledgebase; await _mediator.EntityTokensAdded(articleComment, liquidKnowledgebase, liquidObject); }); return this; } - public LiquidObjectBuilder AddNewsCommentTokens(NewsItem newsItem, NewsComment newsComment, Store store, Language language) + public LiquidObjectBuilder AddNewsCommentTokens(NewsItem newsItem, NewsComment newsComment, Store store, DomainHost host, Language language) { _chain.Add(async liquidObject => { - var liquidNewsComment = new LiquidNewsComment(newsItem, newsComment, store, language); + var liquidNewsComment = new LiquidNewsComment(newsItem, newsComment, store, host, language); liquidObject.NewsComment = liquidNewsComment; await _mediator.EntityTokensAdded(newsComment, liquidNewsComment, liquidObject); }); return this; } - public LiquidObjectBuilder AddProductTokens(Product product, Language language, Store store) + public LiquidObjectBuilder AddProductTokens(Product product, Language language, Store store, DomainHost host) { _chain.Add(async liquidObject => { - var liquidProduct = new LiquidProduct(product, language, store); + var liquidProduct = new LiquidProduct(product, language, store, host); liquidObject.Product = liquidProduct; await _mediator.EntityTokensAdded(product, liquidProduct, liquidObject); }); @@ -231,11 +232,11 @@ public LiquidObjectBuilder AddAttributeCombinationTokens(Product product, Produc return this; } - public LiquidObjectBuilder AddOutOfStockTokens(Product product, OutOfStockSubscription subscription, Store store, Language language) + public LiquidObjectBuilder AddOutOfStockTokens(Product product, OutOfStockSubscription subscription, Store store, DomainHost host, Language language) { _chain.Add(async liquidObject => { - var liquidOutOfStockSubscription = new LiquidOutOfStockSubscription(product, subscription, store, language); + var liquidOutOfStockSubscription = new LiquidOutOfStockSubscription(product, subscription, store, host, language); liquidObject.OutOfStockSubscription = liquidOutOfStockSubscription; await _mediator.EntityTokensAdded(subscription, liquidOutOfStockSubscription, liquidObject); }); diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrder.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrder.cs index 970525676..2b724d933 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrder.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrder.cs @@ -14,15 +14,20 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidOrder : Drop { - private Order _order; - private Language _language; - private Customer _customer; - private Currency _currency; - private Store _store; - private OrderNote _orderNote; + private readonly Order _order; + private readonly Language _language; + private readonly Customer _customer; + private readonly Currency _currency; + private readonly Store _store; + private readonly Vendor _vendor; + private readonly DomainHost _host; + private readonly OrderNote _orderNote; + private ICollection _orderItems; - private Vendor _vendor; - public LiquidOrder(Order order, Customer customer, Language language, Currency currency, Store store, OrderNote orderNote = null, Vendor vendor = null) + + private string url; + + public LiquidOrder(Order order, Customer customer, Language language, Currency currency, Store store, DomainHost host, OrderNote orderNote = null, Vendor vendor = null) { _order = order; @@ -32,6 +37,11 @@ public LiquidOrder(Order order, Customer customer, Language language, Currency c _currency = currency; _store = store; _vendor = vendor; + _host = host; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + + _orderItems = new List(); AdditionalTokens = new Dictionary(); } @@ -209,7 +219,7 @@ public DateTime CreatedOnUtc public string OrderURLForCustomer { - get { return string.Format("{0}/orderdetails/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _order.Id); } + get { return string.Format("{0}/orderdetails/{1}", url, _order.Id); } } public string AmountRefunded { get; set; } @@ -223,7 +233,7 @@ public string OrderNoteAttachmentUrl { get { - return string.Format("{0}/download/ordernotefile/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _orderNote.Id); + return string.Format("{0}/download/ordernotefile/{1}", url, _orderNote.Id); } } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrderItem.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrderItem.cs index da657e6f2..bb6d421bc 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrderItem.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOrderItem.cs @@ -13,19 +13,26 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidOrderItem : Drop { - private OrderItem _orderItem; - private Product _product; - private Language _language; - private Store _store; - private Vendor _vendor; + private readonly OrderItem _orderItem; + private readonly Product _product; + private readonly Language _language; + private readonly Store _store; + private readonly DomainHost _host; + private readonly Vendor _vendor; - public LiquidOrderItem(OrderItem orderItem, Product product, Language language, Store store, Vendor vendor) + private string url; + + public LiquidOrderItem(OrderItem orderItem, Product product, Language language, Store store, DomainHost host, Vendor vendor) { _orderItem = orderItem; _store = store; _language = language; _product = product; _vendor = vendor; + _host = host; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + AdditionalTokens = new Dictionary(); } @@ -41,14 +48,14 @@ public LiquidOrderItem(OrderItem orderItem, Product product, Language language, public string DownloadUrl { get { - string downloadUrl = string.Format("{0}/download/getdownload/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _orderItem.OrderItemGuid); + string downloadUrl = string.Format("{0}/download/getdownload/{1}", url, _orderItem.OrderItemGuid); return downloadUrl; } } public string LicenseUrl { get { - string licenseUrl = string.Format("{0}/download/getlicense/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _orderItem.OrderItemGuid); + string licenseUrl = string.Format("{0}/download/getlicense/{1}", url, _orderItem.OrderItemGuid); return licenseUrl; } } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOutOfStockSubscription.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOutOfStockSubscription.cs index 7040283ff..56ef41854 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOutOfStockSubscription.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidOutOfStockSubscription.cs @@ -12,14 +12,19 @@ public partial class LiquidOutOfStockSubscription : Drop private readonly OutOfStockSubscription _outOfStockSubscription; private readonly Product _product; private readonly Store _store; + private readonly DomainHost _host; private readonly Language _language; + private readonly string url; - public LiquidOutOfStockSubscription(Product product, OutOfStockSubscription outOfStockSubscription, Store store, Language language) + public LiquidOutOfStockSubscription(Product product, OutOfStockSubscription outOfStockSubscription, Store store, DomainHost host, Language language) { _outOfStockSubscription = outOfStockSubscription; _product = product; _store = store; _language = language; + _host = host; + + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); AdditionalTokens = new Dictionary(); } @@ -36,7 +41,7 @@ public string AttributeInfo public string ProductUrl { - get { return string.Format("{0}/{1}", _store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/'), _product.GetSeName(_language.Id)); } + get { return string.Format("{0}/{1}", url, _product.GetSeName(_language.Id)); } } public IDictionary AdditionalTokens { get; set; } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProduct.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProduct.cs index 0468e9a20..525758006 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProduct.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProduct.cs @@ -9,15 +9,20 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidProduct : Drop { - private Product _product; - private Language _language; - private Store _store; + private readonly Product _product; + private readonly Language _language; + private readonly Store _store; + private readonly DomainHost _host; + private readonly string url; - public LiquidProduct(Product product, Language language, Store store) + public LiquidProduct(Product product, Language language, Store store, DomainHost host) { _product = product; _language = language; _store = store; + _host = host; + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + AdditionalTokens = new Dictionary(); } @@ -76,7 +81,7 @@ public string Flag { } public string ProductURLForCustomer { - get { return string.Format("{0}/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _product.GetSeName(_language.Id)); } + get { return string.Format("{0}/{1}", url, _product.GetSeName(_language.Id)); } } public double Weight { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProductReview.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProductReview.cs index fcec1254d..ace2ca1ad 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProductReview.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidProductReview.cs @@ -6,8 +6,8 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidProductReview : Drop { - private ProductReview _productReview; - private Product _product; + private readonly ProductReview _productReview; + private readonly Product _product; public LiquidProductReview(Product product, ProductReview productReview) { @@ -24,6 +24,12 @@ public string ProductName } } + public string ProductReviewReplyText { + get { + return _productReview.ReplyText; + } + } + public IDictionary AdditionalTokens { get; set; } } } \ No newline at end of file diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs index 0fabc3a7f..5ff05e511 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs @@ -10,20 +10,25 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidShipment : Drop { - private Shipment _shipment; - private Order _order; - private Store _store; - private Language _language; + private readonly Shipment _shipment; + private readonly Order _order; + private readonly Store _store; + private readonly Language _language; + private readonly DomainHost _host; + private readonly string url; private ICollection _shipmentItems; - public LiquidShipment(Shipment shipment, Order order, Store store, Language language) + public LiquidShipment(Shipment shipment, Order order, Store store, DomainHost host, Language language) { _shipment = shipment; _language = language; _store = store; _order = order; + _host = host; + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + _shipmentItems = new List(); AdditionalTokens = new Dictionary(); } diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipmentItem.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipmentItem.cs index 92ca7f464..57e49a0c4 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipmentItem.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipmentItem.cs @@ -11,12 +11,12 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidShipmentItem : Drop { - private ShipmentItem _shipmentItem; - private Shipment _shipment; - private Product _product; - private Order _order; - private OrderItem _orderItem; - private Language _language; + private readonly ShipmentItem _shipmentItem; + private readonly Shipment _shipment; + private readonly Product _product; + private readonly Order _order; + private readonly OrderItem _orderItem; + private readonly Language _language; public LiquidShipmentItem(ShipmentItem shipmentItem, Shipment shipment, Order order, OrderItem orderItem, Product product, Language language) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCart.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCart.cs index 5f37b56c3..f8cf6acb9 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCart.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCart.cs @@ -8,7 +8,7 @@ namespace Grand.Business.Messages.DotLiquidDrops public partial class LiquidShoppingCart : Drop { private ICollection _items; - private Customer _customer; + private readonly Customer _customer; public LiquidShoppingCart(Customer customer) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCartItem.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCartItem.cs index 02e13e813..b6485fe75 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCartItem.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShoppingCartItem.cs @@ -10,11 +10,11 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidShoppingCartItem : Drop { - private Product _product; - private Language _language; - private string _attributeDescription; - private string _pictureUrl; - private ShoppingCartItem _shoppingCartItem; + private readonly Product _product; + private readonly Language _language; + private readonly string _attributeDescription; + private readonly string _pictureUrl; + private readonly ShoppingCartItem _shoppingCartItem; public LiquidShoppingCartItem(Product product, string attributeDescription, diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidStore.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidStore.cs index e89343288..53382337e 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidStore.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidStore.cs @@ -9,9 +9,9 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidStore : Drop { - private Store _store; - private EmailAccount _emailAccount; - private Language _language; + private readonly Store _store; + private readonly EmailAccount _emailAccount; + private readonly Language _language; public LiquidStore(Store store, Language language, EmailAccount emailAccount = null) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVatValidationResult.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVatValidationResult.cs index 4627fdd0f..e6dd37793 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVatValidationResult.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVatValidationResult.cs @@ -5,8 +5,8 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidVatValidationResult : Drop { - private string name; - private string address; + private readonly string name; + private readonly string address; public LiquidVatValidationResult(string name, string address) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendor.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendor.cs index 0755e3832..c7f011a6c 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendor.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendor.cs @@ -6,7 +6,7 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidVendor : Drop { - private Vendor _vendor; + private readonly Vendor _vendor; public LiquidVendor(Vendor vendor) { diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendorReview.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendorReview.cs index 77bd025b1..9d95c82f7 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendorReview.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidVendorReview.cs @@ -6,8 +6,8 @@ namespace Grand.Business.Messages.DotLiquidDrops { public partial class LiquidVendorReview : Drop { - private VendorReview _vendorReview; - private Vendor _vendor; + private readonly VendorReview _vendorReview; + private readonly Vendor _vendor; public LiquidVendorReview(Vendor vendor, VendorReview vendorReview) { _vendorReview = vendorReview; diff --git a/src/Business/Grand.Business.Messages/Interfaces/IMessageProviderService.cs b/src/Business/Grand.Business.Messages/Interfaces/IMessageProviderService.cs index 5dd958751..bd7b47e88 100644 --- a/src/Business/Grand.Business.Messages/Interfaces/IMessageProviderService.cs +++ b/src/Business/Grand.Business.Messages/Interfaces/IMessageProviderService.cs @@ -411,8 +411,6 @@ Task SendProductQuestionMessage(Customer customer, Store store, string lang /// /// Sends a blog comment notification message to a store owner /// - /// Blog comment - /// Message language identifier /// Queued email identifier Task SendBlogCommentMessage(BlogPost blogPost, BlogComment blogComment, string languageId); diff --git a/src/Business/Grand.Business.Messages/Services/MessageProviderService.cs b/src/Business/Grand.Business.Messages/Services/MessageProviderService.cs index c59aa2481..4018c4df0 100644 --- a/src/Business/Grand.Business.Messages/Services/MessageProviderService.cs +++ b/src/Business/Grand.Business.Messages/Services/MessageProviderService.cs @@ -19,6 +19,7 @@ using Grand.Domain.Shipping; using Grand.Domain.Stores; using Grand.Domain.Vendors; +using Grand.Infrastructure; using Grand.SharedKernel.Extensions; using MediatR; using System; @@ -39,6 +40,7 @@ public partial class MessageProviderService : IMessageProviderService private readonly IEmailAccountService _emailAccountService; private readonly IMessageTokenProvider _messageTokenProvider; private readonly IStoreService _storeService; + private readonly IStoreHelper _storeHelper; private readonly IGroupService _groupService; private readonly IMediator _mediator; @@ -55,6 +57,7 @@ public MessageProviderService(IMessageTemplateService messageTemplateService, IEmailAccountService emailAccountService, IMessageTokenProvider messageTokenProvider, IStoreService storeService, + IStoreHelper storeHelper, IGroupService groupService, IMediator mediator, EmailAccountSettings emailAccountSettings, @@ -66,6 +69,7 @@ public MessageProviderService(IMessageTemplateService messageTemplateService, _emailAccountService = emailAccountService; _messageTokenProvider = messageTokenProvider; _storeService = storeService; + _storeHelper = storeHelper; _groupService = groupService; _emailAccountSettings = emailAccountSettings; _commonSettings = commonSettings; @@ -162,7 +166,7 @@ protected virtual async Task SendCustomerMessage(Customer customer, Store s var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language, customerNote); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language, customerNote); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -325,9 +329,9 @@ private async Task SendOrderStoreOwnerMessage(string template, Order order, var liquidBuilder = new LiquidObjectBuilder(_mediator); liquidBuilder.AddStoreTokens(store, language, emailAccount) - .AddOrderTokens(order, customer, store); + .AddOrderTokens(order, customer, store, _storeHelper.DomainHost); if (customer != null) - liquidBuilder.AddCustomerTokens(customer, store, language); + liquidBuilder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await liquidBuilder.BuildAsync(); //event notification @@ -443,10 +447,10 @@ private async Task SendOrderCustomerMessage(string message, Order order, Cu var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddOrderTokens(order, customer, store); + .AddOrderTokens(order, customer, store, _storeHelper.DomainHost); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -528,10 +532,10 @@ private async Task SendOrderVendorMessage(string message, Order order, Vend var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddOrderTokens(order, customer, store, vendor: vendor); + .AddOrderTokens(order, customer, store, _storeHelper.DomainHost, vendor: vendor); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -596,11 +600,11 @@ private async Task SendShipmentCustomerMessage(string message, Shipment shi var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddShipmentTokens(shipment, order, store, language) - .AddOrderTokens(order, customer, store); + .AddShipmentTokens(shipment, order, store, _storeHelper.DomainHost, language) + .AddOrderTokens(order, customer, store, _storeHelper.DomainHost); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -642,9 +646,9 @@ public virtual async Task SendNewOrderNoteAddedCustomerMessage(Order order, var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddOrderTokens(order, customer, store, orderNote); + .AddOrderTokens(order, customer, store, _storeHelper.DomainHost, orderNote); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -710,7 +714,7 @@ private async Task SendNewsLetterSubscriptionMessage(string message, NewsLe var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddNewsLetterSubscriptionTokens(subscription, store); + .AddNewsLetterSubscriptionTokens(subscription, store, _storeHelper.DomainHost); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -758,8 +762,8 @@ public virtual async Task SendProductEmailAFriendMessage(Customer customer, var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) .AddEmailAFriendTokens(personalMessage, customerEmail, friendsEmail) - .AddCustomerTokens(customer, store, language) - .AddProductTokens(product, language, store); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) + .AddProductTokens(product, language, store, _storeHelper.DomainHost); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -800,7 +804,7 @@ public virtual async Task SendWishlistEmailAFriendMessage(Customer customer var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language) + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) .AddEmailAFriendTokens(personalMessage, customerEmail, friendsEmail); LiquidObject liquidObject = await builder.BuildAsync(); @@ -847,8 +851,8 @@ public virtual async Task SendProductQuestionMessage(Customer customer, Sto var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language) - .AddProductTokens(product, language, store); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) + .AddProductTokens(product, language, store, _storeHelper.DomainHost); LiquidObject liquidObject = await builder.BuildAsync(); liquidObject.AskQuestion = new LiquidAskQuestion(message, customerEmail, fullName, phone); @@ -864,8 +868,7 @@ public virtual async Task SendProductQuestionMessage(Customer customer, Sto var subjectReplaced = LiquidExtensions.Render(liquidObject, subject); var bodyReplaced = LiquidExtensions.Render(liquidObject, body); - await _mediator.Send(new InsertContactUsCommand() - { + await _mediator.Send(new InsertContactUsCommand() { CustomerId = customer.Id, StoreId = store.Id, VendorId = product.VendorId, @@ -926,9 +929,9 @@ public virtual async Task SendNewMerchandiseReturnStoreOwnerMessage(Merchan builder.AddStoreTokens(store, language, emailAccount); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); - builder.AddMerchandiseReturnTokens(merchandiseReturn, store, order, language); + builder.AddMerchandiseReturnTokens(merchandiseReturn, store, _storeHelper.DomainHost, order, language); LiquidObject liquidObject = await builder.BuildAsync(); @@ -982,9 +985,9 @@ public virtual async Task SendMerchandiseReturnStatusChangedCustomerMessage var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); - builder.AddMerchandiseReturnTokens(merchandiseReturn, store, order, language); + builder.AddMerchandiseReturnTokens(merchandiseReturn, store, _storeHelper.DomainHost, order, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject); @@ -1027,9 +1030,9 @@ public virtual async Task SendNewMerchandiseReturnCustomerMessage(Merchandi var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); - builder.AddMerchandiseReturnTokens(merchandiseReturn, store, order, language); + builder.AddMerchandiseReturnTokens(merchandiseReturn, store, _storeHelper.DomainHost, order, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject); @@ -1075,9 +1078,9 @@ public virtual async Task SendNewMerchandiseReturnNoteAddedCustomerMessage( var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); - builder.AddMerchandiseReturnTokens(merchandiseReturn, store, order, language, merchandiseReturnNote); + builder.AddMerchandiseReturnTokens(merchandiseReturn, store, _storeHelper.DomainHost, order, language, merchandiseReturnNote); LiquidObject liquidObject = await builder.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject); @@ -1123,7 +1126,7 @@ public virtual async Task SendNewVendorAccountApplyStoreOwnerMessage(Custom var emailAccount = await GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var builder = new LiquidObjectBuilder(_mediator).AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language) + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) .AddVendorTokens(vendor, language); LiquidObject liquidObject = await builder.BuildAsync(); @@ -1242,7 +1245,7 @@ public virtual async Task SendProductReviewMessage(Product product, Product .AddProductReviewTokens(product, productReview); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -1287,7 +1290,7 @@ public virtual async Task SendVendorReviewMessage(VendorReview vendorReview .AddVendorReviewTokens(vendor, vendorReview); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); builder.AddVendorTokens(vendor, language); LiquidObject liquidObject = await builder.BuildAsync(); @@ -1325,7 +1328,7 @@ public virtual async Task SendQuantityBelowStoreOwnerMessage(Product produc var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddProductTokens(product, language, store); + .AddProductTokens(product, language, store, _storeHelper.DomainHost); LiquidObject liquidObject = await builder.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject); @@ -1360,7 +1363,7 @@ public virtual async Task SendQuantityBelowStoreOwnerMessage(Product produc var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddProductTokens(product, language, store) + .AddProductTokens(product, language, store, _storeHelper.DomainHost) .AddAttributeCombinationTokens(product, combination); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -1398,7 +1401,7 @@ public virtual async Task SendCustomerDeleteStoreOwnerMessage(Customer cust var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); @@ -1412,8 +1415,6 @@ public virtual async Task SendCustomerDeleteStoreOwnerMessage(Customer cust /// /// Sends a blog comment notification message to a store owner /// - /// Blog comment - /// Message language identifier /// Queued email identifier public virtual async Task SendBlogCommentMessage(BlogPost blogPost, BlogComment blogComment, string languageId) { @@ -1432,11 +1433,11 @@ public virtual async Task SendBlogCommentMessage(BlogPost blogPost, BlogCom var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddBlogCommentTokens(blogPost, blogComment, store, language); + .AddBlogCommentTokens(blogPost, blogComment, store, _storeHelper.DomainHost, language); var customer = await _mediator.Send(new GetCustomerByIdQuery() { Id = blogComment.CustomerId }); if (customer != null && await _groupService.IsRegistered(customer)) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -1472,11 +1473,11 @@ public virtual async Task SendArticleCommentMessage(KnowledgebaseArticle ar var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddArticleCommentTokens(article, articleComment, store, language); + .AddArticleCommentTokens(article, articleComment, store, _storeHelper.DomainHost, language); var customer = await _mediator.Send(new GetCustomerByIdQuery() { Id = articleComment.CustomerId }); if (customer != null && await _groupService.IsRegistered(customer)) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject); @@ -1511,10 +1512,10 @@ public virtual async Task SendNewsCommentMessage(NewsItem newsItem, NewsCom var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddNewsCommentTokens(newsItem, newsComment, store, language); + .AddNewsCommentTokens(newsItem, newsComment, store, _storeHelper.DomainHost, language); var customer = await _mediator.Send(new GetCustomerByIdQuery() { Id = newsComment.CustomerId }); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -1553,9 +1554,9 @@ public virtual async Task SendBackinStockMessage(Customer customer, Product var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount); if (customer != null) - builder.AddCustomerTokens(customer, store, language); + builder.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); - builder.AddOutOfStockTokens(product, subscription, store, language); + builder.AddOutOfStockTokens(product, subscription, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject); @@ -1609,7 +1610,7 @@ public virtual async Task SendContactUsMessage(Customer customer, Store sto var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); liquidObject.ContactUs = new LiquidContactUs(senderEmail, senderName, body, attrInfo); @@ -1622,8 +1623,7 @@ public virtual async Task SendContactUsMessage(Customer customer, Store sto //store in database if (_commonSettings.StoreInDatabaseContactUsForm) { - await _mediator.Send(new InsertContactUsCommand() - { + await _mediator.Send(new InsertContactUsCommand() { CustomerId = customer.Id, StoreId = store.Id, VendorId = "", @@ -1690,7 +1690,7 @@ public virtual async Task SendContactVendorMessage(Customer customer, Store var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); liquidObject.ContactUs = new LiquidContactUs(senderEmail, senderName, body, ""); //event notification @@ -1702,8 +1702,7 @@ public virtual async Task SendContactVendorMessage(Customer customer, Store //store in database if (_commonSettings.StoreInDatabaseContactUsForm) { - await _mediator.Send(new InsertContactUsCommand() - { + await _mediator.Send(new InsertContactUsCommand() { CustomerId = customer.Id, StoreId = store.Id, VendorId = vendor.Id, @@ -1752,7 +1751,7 @@ public virtual async Task SendCustomerActionAddToCartMessage(CustomerAction builder.AddStoreTokens(store, language, emailAccount); //product var product = await _mediator.Send(new GetProductByIdQuery() { Id = cartItem.ProductId }); - builder.AddProductTokens(product, language, store); + builder.AddProductTokens(product, language, store, _storeHelper.DomainHost); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -1794,8 +1793,8 @@ public virtual async Task SendCustomerActionAddToOrderMessage(CustomerActio var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddOrderTokens(order, customer, store) - .AddCustomerTokens(customer, store, language); + .AddOrderTokens(order, customer, store, _storeHelper.DomainHost) + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -1850,8 +1849,8 @@ public virtual async Task SendAuctionWinEndedCustomerMessage(Product produc var builder = new LiquidObjectBuilder(_mediator); builder.AddAuctionTokens(product, bid) - .AddCustomerTokens(customer, store, language) - .AddProductTokens(product, language, store) + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) + .AddProductTokens(product, language, store, _storeHelper.DomainHost) .AddStoreTokens(store, language, emailAccount); LiquidObject liquidObject = await builder.BuildAsync(); @@ -1887,7 +1886,7 @@ public virtual async Task SendAuctionEndedLostCustomerMessage(Product produ var builder = new LiquidObjectBuilder(_mediator); builder.AddAuctionTokens(product, bid) - .AddProductTokens(product, language, store) + .AddProductTokens(product, language, store, _storeHelper.DomainHost) .AddStoreTokens(store, language, emailAccount); LiquidObject liquidObject = await builder.BuildAsync(); @@ -1900,7 +1899,7 @@ public virtual async Task SendAuctionEndedLostCustomerMessage(Product produ { languageId = customer.GetUserFieldFromEntity(SystemCustomerFieldNames.LanguageId); } - builder2.AddCustomerTokens(customer, store, language); + builder2.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject2 = await builder2.BuildAsync(); //event notification @@ -1931,7 +1930,7 @@ public virtual async Task SendAuctionEndedBinCustomerMessage(Product produc var emailAccount = await GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var builder = new LiquidObjectBuilder(_mediator); - builder.AddProductTokens(product, language, store) + builder.AddProductTokens(product, language, store, _storeHelper.DomainHost) .AddStoreTokens(store, language, emailAccount); LiquidObject liquidObject = await builder.BuildAsync(); @@ -1947,7 +1946,7 @@ public virtual async Task SendAuctionEndedBinCustomerMessage(Product produc languageId = customer.GetUserFieldFromEntity(SystemCustomerFieldNames.LanguageId); } - builder2.AddCustomerTokens(customer, store, language); + builder2.AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject2 = await builder2.BuildAsync(); //event notification await _mediator.MessageTokensAdded(messageTemplate, liquidObject2); @@ -1989,7 +1988,7 @@ public virtual async Task SendAuctionEndedStoreOwnerMessage(Product product emailAccount = await GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); builder.AddAuctionTokens(product, bid) - .AddCustomerTokens(customer, store, language) + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) .AddStoreTokens(store, language, emailAccount); } else @@ -2001,7 +2000,7 @@ public virtual async Task SendAuctionEndedStoreOwnerMessage(Product product return 0; emailAccount = await GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); - builder.AddProductTokens(product, language, store); + builder.AddProductTokens(product, language, store, _storeHelper.DomainHost); } LiquidObject liquidObject = await builder.BuildAsync(); //event notification @@ -2046,7 +2045,7 @@ public virtual async Task SendOutBidCustomerMessage(Product product, string var builder = new LiquidObjectBuilder(_mediator); builder.AddAuctionTokens(product, bid) - .AddCustomerTokens(customer, store, language) + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language) .AddStoreTokens(store, language, emailAccount); LiquidObject liquidObject = await builder.BuildAsync(); @@ -2084,7 +2083,7 @@ public virtual async Task SendCustomerActionMessage(CustomerAction action, var builder = new LiquidObjectBuilder(_mediator); builder.AddStoreTokens(store, language, emailAccount) - .AddCustomerTokens(customer, store, language); + .AddCustomerTokens(customer, store, _storeHelper.DomainHost, language); LiquidObject liquidObject = await builder.BuildAsync(); //event notification diff --git a/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetMerchandiseReturnTokensCommandHandler.cs b/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetMerchandiseReturnTokensCommandHandler.cs index 58e41bc02..1f9ca6c8e 100644 --- a/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetMerchandiseReturnTokensCommandHandler.cs +++ b/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetMerchandiseReturnTokensCommandHandler.cs @@ -1,16 +1,11 @@ -using Grand.Business.Catalog.Interfaces.Prices; -using Grand.Business.Catalog.Interfaces.Products; +using Grand.Business.Catalog.Interfaces.Products; using Grand.Business.Common.Extensions; using Grand.Business.Common.Interfaces.Directory; using Grand.Business.Common.Interfaces.Localization; using Grand.Business.Messages.Commands.Models; using Grand.Business.Messages.DotLiquidDrops; -using Grand.Domain.Messages; -using Grand.Domain.Tax; using MediatR; using System.Linq; -using System.Net; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -34,15 +29,15 @@ public GetMerchandiseReturnTokensCommandHandler( public async Task Handle(GetMerchandiseReturnTokensCommand request, CancellationToken cancellationToken) { - var liquidMerchandiseReturn = new LiquidMerchandiseReturn(request.MerchandiseReturn, request.Store, request.Order, request.MerchandiseReturnNote); + var liquidMerchandiseReturn = new LiquidMerchandiseReturn(request.MerchandiseReturn, request.Store, request.Host, request.Order, request.MerchandiseReturnNote); var country = await _countryService.GetCountryById(request.MerchandiseReturn.PickupAddress.CountryId); liquidMerchandiseReturn.Status = request.MerchandiseReturn.MerchandiseReturnStatus.GetTranslationEnum(_translationService, request.Language.Id); - + liquidMerchandiseReturn.PickupAddressStateProvince = !string.IsNullOrEmpty(request.MerchandiseReturn.PickupAddress.StateProvinceId) ? - country?.StateProvinces.FirstOrDefault(x=>x.Id == request.MerchandiseReturn.PickupAddress.StateProvinceId)?.GetTranslation(x => x.Name, request.Language.Id) : ""; + country?.StateProvinces.FirstOrDefault(x => x.Id == request.MerchandiseReturn.PickupAddress.StateProvinceId)?.GetTranslation(x => x.Name, request.Language.Id) : ""; liquidMerchandiseReturn.PickupAddressCountry = !string.IsNullOrEmpty(request.MerchandiseReturn.PickupAddress.CountryId) ? diff --git a/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetOrderTokensCommandHandler.cs b/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetOrderTokensCommandHandler.cs index 1d04dccb2..6b2f247ac 100644 --- a/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetOrderTokensCommandHandler.cs +++ b/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetOrderTokensCommandHandler.cs @@ -73,12 +73,12 @@ public async Task Handle(GetOrderTokensCommand request, Cancellatio var language = await _languageService.GetLanguageById(request.Order.CustomerLanguageId); var currency = await _currencyService.GetCurrencyByCode(request.Order.CustomerCurrencyCode); - var liquidOrder = new LiquidOrder(request.Order, request.Customer, language, currency, request.Store, request.OrderNote, request.Vendor); + var liquidOrder = new LiquidOrder(request.Order, request.Customer, language, currency, request.Store, request.Host, request.OrderNote, request.Vendor); foreach (var item in request.Order.OrderItems.Where(x => x.VendorId == request.Vendor?.Id || request.Vendor == null)) { var product = await _productService.GetProductById(item.ProductId); Vendor vendorItem = string.IsNullOrEmpty(item.VendorId) ? null : await _vendorService.GetVendorById(item.VendorId); - var liqitem = new LiquidOrderItem(item, product, language, request.Store, vendorItem); + var liqitem = new LiquidOrderItem(item, product, language, request.Store, request.Host, vendorItem); #region Download diff --git a/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetShipmentTokensCommandHandler.cs b/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetShipmentTokensCommandHandler.cs index ac5c2eb28..c99a2a958 100644 --- a/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetShipmentTokensCommandHandler.cs +++ b/src/Business/Grand.Business.System/Commands/Handlers/Messages/GetShipmentTokensCommandHandler.cs @@ -20,7 +20,7 @@ public GetShipmentTokensCommandHandler( public async Task Handle(GetShipmentTokensCommand request, CancellationToken cancellationToken) { - var liquidShipment = new LiquidShipment(request.Shipment, request.Order, request.Store, request.Language); + var liquidShipment = new LiquidShipment(request.Shipment, request.Order, request.Store, request.Host, request.Language); foreach (var shipmentItem in request.Shipment.ShipmentItems) { var orderitem = request.Order.OrderItems.FirstOrDefault(x => x.Id == shipmentItem.OrderItemId); diff --git a/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs b/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs index 063efdd8c..675d97ef9 100644 --- a/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs +++ b/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs @@ -21,14 +21,14 @@ protected virtual async Task InstallStores(string companyName, string companyAdd Shortcut = "Store", Url = storeUrl, SslEnabled = false, - Hosts = "yourstore.com,www.yourstore.com", DisplayOrder = 1, CompanyName = companyName, CompanyAddress = companyAddress, CompanyPhoneNumber = companyPhoneNumber, CompanyVat = null, CompanyEmail = companyEmail, - CompanyHours = "Monday - Sunday / 8:00AM - 6:00PM" + CompanyHours = "Monday - Sunday / 8:00AM - 6:00PM", + Domains = new List(){ new DomainHost() { HostName = "yourstore.com", Url = storeUrl, Primary = true } } }, }; diff --git a/src/Core/Grand.Domain/Stores/DomainHost.cs b/src/Core/Grand.Domain/Stores/DomainHost.cs index bd99b760c..2dca87875 100644 --- a/src/Core/Grand.Domain/Stores/DomainHost.cs +++ b/src/Core/Grand.Domain/Stores/DomainHost.cs @@ -1,7 +1,10 @@ namespace Grand.Domain.Stores { - public class DomainHost : BaseEntity + public class DomainHost : SubBaseEntity { + public string HostName { get; set; } public string Url { get; set; } + public bool Primary { get; set; } + } } diff --git a/src/Core/Grand.Domain/Stores/Store.cs b/src/Core/Grand.Domain/Stores/Store.cs index 713df6bfb..e9c8b8e4f 100644 --- a/src/Core/Grand.Domain/Stores/Store.cs +++ b/src/Core/Grand.Domain/Stores/Store.cs @@ -11,6 +11,7 @@ public partial class Store : BaseEntity, ITranslationEntity public Store() { Locales = new List(); + Domains = new List(); } /// @@ -39,9 +40,9 @@ public Store() public string SecureUrl { get; set; } /// - /// Gets or sets the comma separated list of possible HTTP_HOST values + /// Gets or sets the list of domains /// - public string Hosts { get; set; } + public IList Domains { get; set; } /// /// Gets or sets the identifier of the default language for this store; "" is set when we use the default language display order diff --git a/src/Core/Grand.Domain/Stores/StoreExtensions.cs b/src/Core/Grand.Domain/Stores/StoreExtensions.cs index c25da9d7b..ad970e478 100644 --- a/src/Core/Grand.Domain/Stores/StoreExtensions.cs +++ b/src/Core/Grand.Domain/Stores/StoreExtensions.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; namespace Grand.Domain.Stores @@ -7,46 +6,38 @@ namespace Grand.Domain.Stores public static class StoreExtensions { /// - /// Parse comma-separated Hosts + /// Indicates whether a store contains a specified host /// /// Store - /// Comma-separated hosts - public static string[] ParseHostValues(this Store store) + /// Host + /// true - contains, false - no + public static bool ContainsHostValue(this Store store, string host) { if (store == null) throw new ArgumentNullException(nameof(store)); - var parsedValues = new List(); - if (!String.IsNullOrEmpty(store.Hosts)) - { - string[] hosts = store.Hosts.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string host in hosts) - { - var tmp = host.Trim(); - if (!String.IsNullOrEmpty(tmp)) - parsedValues.Add(tmp); - } - } - return parsedValues.ToArray(); + if (string.IsNullOrEmpty(host)) + return false; + + var contains = store.Domains.FirstOrDefault(x => x.HostName.Equals(host, StringComparison.OrdinalIgnoreCase)) != null; + return contains; } /// - /// Indicates whether a store contains a specified host + /// Return domain host /// /// Store /// Host - /// true - contains, false - no - public static bool ContainsHostValue(this Store store, string host) + /// DomainHost + public static DomainHost HostValue(this Store store, string host) { if (store == null) throw new ArgumentNullException(nameof(store)); - if (String.IsNullOrEmpty(host)) - return false; + if (string.IsNullOrEmpty(host)) + return null; - var contains = store.ParseHostValues() - .FirstOrDefault(x => x.Equals(host, StringComparison.OrdinalIgnoreCase)) != null; - return contains; + return store.Domains.FirstOrDefault(x => x.HostName.Equals(host, StringComparison.OrdinalIgnoreCase)); } } } diff --git a/src/Core/Grand.Domain/SubBaseEntity.cs b/src/Core/Grand.Domain/SubBaseEntity.cs index d7ac10d3e..2ebbab9b3 100644 --- a/src/Core/Grand.Domain/SubBaseEntity.cs +++ b/src/Core/Grand.Domain/SubBaseEntity.cs @@ -1,8 +1,8 @@ namespace Grand.Domain { - public abstract partial class SubBaseEntity: ParentEntity + public abstract partial class SubBaseEntity : ParentEntity { - + } } diff --git a/src/Core/Grand.Infrastructure/Caching/Constants/CommonCacheKey.cs b/src/Core/Grand.Infrastructure/Caching/Constants/CommonCacheKey.cs index 7ffa08fbe..834e0d72e 100644 --- a/src/Core/Grand.Infrastructure/Caching/Constants/CommonCacheKey.cs +++ b/src/Core/Grand.Infrastructure/Caching/Constants/CommonCacheKey.cs @@ -165,6 +165,29 @@ public static partial class CacheKey #endregion + #region Domains + + /// + /// Key for caching + /// + public static string DOMAINS_PATTERN_KEY => "Grand.domains"; + + /// + /// Key for caching + /// + public static string DOMAINS_ALL_KEY => "Grand.domains.all"; + + /// + /// Key for caching + /// + /// + /// {0} : store ID + /// + public static string DOMAINS_BY_ID_KEY => "Grand.domains.id-{0}"; + + #endregion + + #region Tax /// diff --git a/src/Core/Grand.Infrastructure/IStoreHelper.cs b/src/Core/Grand.Infrastructure/IStoreHelper.cs index 54a7a5b19..077d296e4 100644 --- a/src/Core/Grand.Infrastructure/IStoreHelper.cs +++ b/src/Core/Grand.Infrastructure/IStoreHelper.cs @@ -5,10 +5,10 @@ namespace Grand.Infrastructure { public interface IStoreHelper { - Store HostStore { get; } + Store StoreHost { get; } + DomainHost DomainHost { get; } Task SetStoreCookie(string storeId); - Task SetCurrentStore(string storeId); } } diff --git a/src/Core/Grand.Infrastructure/IWorkContext.cs b/src/Core/Grand.Infrastructure/IWorkContext.cs index 66a8b5311..35d8af0f4 100644 --- a/src/Core/Grand.Infrastructure/IWorkContext.cs +++ b/src/Core/Grand.Infrastructure/IWorkContext.cs @@ -40,6 +40,11 @@ public interface IWorkContext /// Vendor CurrentVendor { get; } + /// + /// Gets the current host + /// + DomainHost CurrentHost { get; } + /// /// Set the current vendor (logged-in manager) /// diff --git a/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProvider.cs b/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProvider.cs index 7526cc900..bc99133ee 100644 --- a/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProvider.cs +++ b/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProvider.cs @@ -104,7 +104,7 @@ private string GetPaypalUrl() private async Task> CreateQueryParameters(Order order) { //get store location - var storeLocation = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); + var storeLocation = _workContext.CurrentHost.Url; var stateProvince = ""; var countryCode = ""; if (!String.IsNullOrEmpty(order.ShippingAddress?.StateProvinceId)) diff --git a/src/Plugins/Widgets.GoogleAnalytics/Components/WidgetsGoogleAnalyticsViewComponent.cs b/src/Plugins/Widgets.GoogleAnalytics/Components/WidgetsGoogleAnalyticsViewComponent.cs index 77017c9cb..26dd27ba3 100644 --- a/src/Plugins/Widgets.GoogleAnalytics/Components/WidgetsGoogleAnalyticsViewComponent.cs +++ b/src/Plugins/Widgets.GoogleAnalytics/Components/WidgetsGoogleAnalyticsViewComponent.cs @@ -110,7 +110,7 @@ private async Task GetEcommerceScript(Order order) var analyticsEcommerceScript = _googleAnalyticsEcommerceSettings.EcommerceScript + "\n"; analyticsEcommerceScript = analyticsEcommerceScript.Replace("{GOOGLEID}", _googleAnalyticsEcommerceSettings.GoogleId); analyticsEcommerceScript = analyticsEcommerceScript.Replace("{ORDERID}", order.Id.ToString()); - analyticsEcommerceScript = analyticsEcommerceScript.Replace("{SITE}", _workContext.CurrentStore.Url.Replace("http://", "").Replace("/", "")); + analyticsEcommerceScript = analyticsEcommerceScript.Replace("{SITE}", _workContext.CurrentHost.Url.Replace("http://", "").Replace("/", "")); analyticsEcommerceScript = analyticsEcommerceScript.Replace("{TOTAL}", order.OrderTotal.ToString("0.00", usCulture)); analyticsEcommerceScript = analyticsEcommerceScript.Replace("{TAX}", order.OrderTax.ToString("0.00", usCulture)); var orderShipping = _googleAnalyticsEcommerceSettings.IncludingTax ? order.OrderShippingInclTax : order.OrderShippingExclTax; diff --git a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabDomains.cshtml b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabDomains.cshtml new file mode 100644 index 000000000..7d54971c8 --- /dev/null +++ b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabDomains.cshtml @@ -0,0 +1,119 @@ +@model StoreModel +@if (!String.IsNullOrEmpty(Model.Id)) +{ +
+
+
+
+
+ + +} +else +{ +
+ @Loc["Admin.Configuration.Stores.Domains.SaveBeforeEdit"] +
+} diff --git a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabInfo.cshtml b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabInfo.cshtml new file mode 100644 index 000000000..cc28f627c --- /dev/null +++ b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.TabInfo.cshtml @@ -0,0 +1,157 @@ +@model StoreModel +@using Microsoft.AspNetCore.Mvc.Razor; + +@{ Func + template = @
+
+ +
+ + +
+
+
+ +
+ + +
+
+ +
; +} +
+ c.LanguageId).ToList()> +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+ @Loc["Admin.Configuration.Stores.Fields.SslEnabled.Hint2"] +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
diff --git a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.cshtml b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.cshtml index 5bf2d4024..9669092e1 100644 --- a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.cshtml +++ b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Store/_CreateOrUpdate.cshtml @@ -22,165 +22,27 @@ -@{ Func - template = @
-
- -
- - -
-
-
- -
- - -
-
- -
; -} -
- c.LanguageId).ToList()> -
-
- -
- - +
+ + + + + +
+
-
-
- -
- - + + + + +
+
-
-
- -
-
- -
- - -
-
-
- -
- - -
-
-
-
- @Loc["Admin.Configuration.Stores.Fields.SslEnabled.Hint2"] -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
- -
- - -
-
-
-
+ + + + + + + \ No newline at end of file diff --git a/src/Web/Grand.Web.Admin/Controllers/CommonController.cs b/src/Web/Grand.Web.Admin/Controllers/CommonController.cs index 9d8b2a7a4..09860d230 100644 --- a/src/Web/Grand.Web.Admin/Controllers/CommonController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/CommonController.cs @@ -144,7 +144,7 @@ public async Task SystemInfo() }); } //store URL - var currentStoreUrl = _workContext.CurrentStore.Url; + var currentStoreUrl = _workContext.CurrentHost.Url; if (!String.IsNullOrEmpty(currentStoreUrl) && (currentStoreUrl.Equals(HttpContext.Request.Host.Host, StringComparison.OrdinalIgnoreCase))) model.SystemWarnings.Add(new SystemInfoModel.SystemWarningModel { Level = SystemInfoModel.SystemWarningModel.SystemWarningLevel.Pass, diff --git a/src/Web/Grand.Web.Admin/Controllers/StoreController.cs b/src/Web/Grand.Web.Admin/Controllers/StoreController.cs index 8aeb22610..f765cd160 100644 --- a/src/Web/Grand.Web.Admin/Controllers/StoreController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/StoreController.cs @@ -44,8 +44,7 @@ public async Task List(DataSourceRequest command) .Select(x => x.ToModel()) .ToList(); - var gridModel = new DataSourceResult - { + var gridModel = new DataSourceResult { Data = storeModels, Total = storeModels.Count() }; @@ -167,5 +166,93 @@ public async Task Delete(string id) Error(ModelState); return RedirectToAction("Edit", new { id = store.Id }); } + + #region Domains + + [PermissionAuthorizeAction(PermissionActionName.Preview)] + [HttpPost] + public async Task Domains(string storeId) + { + var store = await _storeService.GetStoreById(storeId); + if (store == null) + //No store found with the specified id + return ErrorForKendoGridJson("Store not found"); + + var model = store.ToModel(); + + var gridModel = new DataSourceResult { + Data = model.Domains.ToList(), + Total = model.Domains.Count + }; + + return Json(gridModel); + } + + [PermissionAuthorizeAction(PermissionActionName.Edit)] + [HttpPost] + public async Task DomainInsert(string storeId, DomainHostModel model) + { + var store = await _storeService.GetStoreById(storeId); + if (store == null) + //No store found with the specified id + return ErrorForKendoGridJson("Store not found"); + + if (ModelState.IsValid) + { + await _storeViewModelService.InsertDomainHostModel(store, model); + return new JsonResult(""); + } + return ErrorForKendoGridJson(ModelState); + } + + [PermissionAuthorizeAction(PermissionActionName.Edit)] + [HttpPost] + public async Task DomainUpdate(string storeId, DomainHostModel model) + { + var store = await _storeService.GetStoreById(storeId); + if (store == null) + //No store found with the specified id + return ErrorForKendoGridJson("Store not found"); + + var domain = store.Domains.FirstOrDefault(x => x.Id == model.Id); + if (domain == null) + return ErrorForKendoGridJson("Domain not found"); + + if (domain.Primary) + return ErrorForKendoGridJson("You can't edit primary domain"); + + if (ModelState.IsValid) + { + await _storeViewModelService.UpdateDomainHostModel(store, model); + return new JsonResult(""); + } + return ErrorForKendoGridJson(ModelState); + } + + [PermissionAuthorizeAction(PermissionActionName.Edit)] + [HttpPost] + public async Task DomainDelete(string storeId, string id) + { + var store = await _storeService.GetStoreById(storeId); + if (store == null) + //No store found with the specified id + return ErrorForKendoGridJson("Store not found"); + + var domain = store.Domains.FirstOrDefault(x => x.Id == id); + if (domain == null) + return ErrorForKendoGridJson("Domain not found"); + + if (domain.Primary) + return ErrorForKendoGridJson("You can't delete primary domain"); + + if (ModelState.IsValid) + { + await _storeViewModelService.DeleteDomainHostModel(store, id); + return new JsonResult(""); + } + + return ErrorForKendoGridJson(ModelState); + } + #endregion } } diff --git a/src/Web/Grand.Web.Admin/Extensions/PluginExtensions.cs b/src/Web/Grand.Web.Admin/Extensions/PluginExtensions.cs index 49df00ced..6cd0e2847 100644 --- a/src/Web/Grand.Web.Admin/Extensions/PluginExtensions.cs +++ b/src/Web/Grand.Web.Admin/Extensions/PluginExtensions.cs @@ -19,7 +19,7 @@ public static string GetLogoUrl(this PluginInfo pluginDescriptor, IWorkContext w { return null; } - var storeLocation = workContext.CurrentStore.SslEnabled ? workContext.CurrentStore.SecureUrl.TrimEnd('/') : workContext.CurrentStore.Url.TrimEnd('/'); + var storeLocation = workContext.CurrentHost.Url.TrimEnd('/'); var pluginDirectory = pluginDescriptor.OriginalAssemblyFile.Directory; var logoPluginJpg = Path.Combine(pluginDirectory.FullName, "logo.jpg"); if (File.Exists(logoPluginJpg)) diff --git a/src/Web/Grand.Web.Admin/Interfaces/IStoreViewModelService.cs b/src/Web/Grand.Web.Admin/Interfaces/IStoreViewModelService.cs index b78a0d702..c42e96ee8 100644 --- a/src/Web/Grand.Web.Admin/Interfaces/IStoreViewModelService.cs +++ b/src/Web/Grand.Web.Admin/Interfaces/IStoreViewModelService.cs @@ -14,6 +14,9 @@ public interface IStoreViewModelService Task InsertStoreModel(StoreModel model); Task UpdateStoreModel(Store store, StoreModel model); Task DeleteStore(Store store); + Task InsertDomainHostModel(Store store, DomainHostModel model); + Task UpdateDomainHostModel(Store store, DomainHostModel model); + Task DeleteDomainHostModel(Store store, string id); } } diff --git a/src/Web/Grand.Web.Admin/Mapper/StoreProfile.cs b/src/Web/Grand.Web.Admin/Mapper/StoreProfile.cs index 3ecc776cd..a983f7224 100644 --- a/src/Web/Grand.Web.Admin/Mapper/StoreProfile.cs +++ b/src/Web/Grand.Web.Admin/Mapper/StoreProfile.cs @@ -11,6 +11,7 @@ public class StoreProfile : Profile, IAutoMapperProfile public StoreProfile() { CreateMap() + .ForMember(dest => dest.Domains, mo => mo.MapFrom(x => x.Domains)) .ForMember(dest => dest.AvailableLanguages, mo => mo.Ignore()) .ForMember(dest => dest.AvailableWarehouses, mo => mo.Ignore()) .ForMember(dest => dest.AvailableCountries, mo => mo.Ignore()) @@ -18,7 +19,12 @@ public StoreProfile() .ForMember(dest => dest.Locales, mo => mo.Ignore()); CreateMap() .ForMember(dest => dest.Id, mo => mo.Ignore()) + .ForMember(dest => dest.Domains, mo => mo.Ignore()) .ForMember(dest => dest.Locales, mo => mo.MapFrom(x => x.Locales.ToTranslationProperty())); + + CreateMap(); + CreateMap(); + } public int Order => 0; diff --git a/src/Web/Grand.Web.Admin/Models/Stores/StoreModel.cs b/src/Web/Grand.Web.Admin/Models/Stores/StoreModel.cs index 89abbeb1b..fe4347515 100644 --- a/src/Web/Grand.Web.Admin/Models/Stores/StoreModel.cs +++ b/src/Web/Grand.Web.Admin/Models/Stores/StoreModel.cs @@ -11,6 +11,7 @@ public partial class StoreModel : BaseEntityModel, ILocalizedModel(); + Domains = new List(); AvailableLanguages = new List(); AvailableWarehouses = new List(); AvailableCountries = new List(); @@ -32,9 +33,6 @@ public StoreModel() [GrandResourceDisplayName("Admin.Configuration.Stores.Fields.SecureUrl")] public virtual string SecureUrl { get; set; } - [GrandResourceDisplayName("Admin.Configuration.Stores.Fields.Hosts")] - public string Hosts { get; set; } - [GrandResourceDisplayName("Admin.Configuration.Stores.Fields.DefaultAdminTheme")] public string DefaultAdminTheme { get; set; } @@ -78,6 +76,9 @@ public StoreModel() [GrandResourceDisplayName("Admin.Configuration.Stores.Fields.DefaultCurrency")] public string DefaultCurrencyId { get; set; } public IList AvailableCurrencies { get; set; } + + public IList Domains { get; set; } + } public partial class StoreLocalizedModel : ILocalizedModelLocal @@ -90,4 +91,14 @@ public partial class StoreLocalizedModel : ILocalizedModelLocal [GrandResourceDisplayName("Admin.Configuration.Stores.Fields.Shortcut")] public string Shortcut { get; set; } } + + public class DomainHostModel : BaseEntityModel + { + [GrandResourceDisplayName("Admin.Configuration.Stores.Domains.Fields.HostName")] + public string HostName { get; set; } + [GrandResourceDisplayName("Admin.Configuration.Stores.Domains.Fields.Url")] + public string Url { get; set; } + [GrandResourceDisplayName("Admin.Configuration.Stores.Domains.Fields.Primary")] + public bool Primary { get; set; } + } } \ No newline at end of file diff --git a/src/Web/Grand.Web.Admin/Services/DiscountViewModelService.cs b/src/Web/Grand.Web.Admin/Services/DiscountViewModelService.cs index ecd2c2c26..f48103a52 100644 --- a/src/Web/Grand.Web.Admin/Services/DiscountViewModelService.cs +++ b/src/Web/Grand.Web.Admin/Services/DiscountViewModelService.cs @@ -243,7 +243,7 @@ public virtual string GetRequirementUrlInternal(IDiscountRule discountRequiremen if (discount == null) throw new ArgumentNullException(nameof(discount)); - var storeLocation = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); + var storeLocation = _workContext.CurrentHost.Url.TrimEnd('/'); string url = string.Format("{0}/{1}", storeLocation, discountRequirementRule.GetConfigurationUrl(discount.Id, discountRequirementId)); return url; diff --git a/src/Web/Grand.Web.Admin/Services/StoreViewModelService.cs b/src/Web/Grand.Web.Admin/Services/StoreViewModelService.cs index c59cf06c8..413f43cbc 100644 --- a/src/Web/Grand.Web.Admin/Services/StoreViewModelService.cs +++ b/src/Web/Grand.Web.Admin/Services/StoreViewModelService.cs @@ -39,16 +39,14 @@ public virtual async Task PrepareLanguagesModel(StoreModel model) if (model == null) throw new ArgumentNullException(nameof(model)); - model.AvailableLanguages.Add(new SelectListItem - { + model.AvailableLanguages.Add(new SelectListItem { Text = "---", Value = "" }); var languages = await _languageService.GetAllLanguages(true); foreach (var language in languages) { - model.AvailableLanguages.Add(new SelectListItem - { + model.AvailableLanguages.Add(new SelectListItem { Text = language.Name, Value = language.Id }); @@ -61,16 +59,14 @@ public virtual async Task PrepareWarehouseModel(StoreModel model) throw new ArgumentNullException(nameof(model)); //warehouse - model.AvailableWarehouses.Add(new SelectListItem - { + model.AvailableWarehouses.Add(new SelectListItem { Text = "---", Value = "" }); var warehouses = await _warehouseService.GetAllWarehouses(); foreach (var warehouse in warehouses) { - model.AvailableWarehouses.Add(new SelectListItem - { + model.AvailableWarehouses.Add(new SelectListItem { Text = warehouse.Name, Value = warehouse.Id }); @@ -82,8 +78,7 @@ public virtual async Task PrepareCountryModel(StoreModel model) throw new ArgumentNullException(nameof(model)); //countries - model.AvailableCountries.Add(new SelectListItem - { + model.AvailableCountries.Add(new SelectListItem { Text = "---", Value = "" }); @@ -91,8 +86,7 @@ public virtual async Task PrepareCountryModel(StoreModel model) var countries = await _countryService.GetAllCountries(); foreach (var country in countries) { - model.AvailableCountries.Add(new SelectListItem - { + model.AvailableCountries.Add(new SelectListItem { Text = country.Name, Value = country.Id }); @@ -104,8 +98,7 @@ public virtual async Task PrepareCurrencyModel(StoreModel model) throw new ArgumentNullException(nameof(model)); //countries - model.AvailableCurrencies.Add(new SelectListItem - { + model.AvailableCurrencies.Add(new SelectListItem { Text = "---", Value = "" }); @@ -113,8 +106,7 @@ public virtual async Task PrepareCurrencyModel(StoreModel model) var currencies = await _currencyService.GetAllCurrencies(); foreach (var currency in currencies) { - model.AvailableCurrencies.Add(new SelectListItem - { + model.AvailableCurrencies.Add(new SelectListItem { Text = currency.Name, Value = currency.Id }); @@ -135,18 +127,43 @@ public virtual async Task InsertStoreModel(StoreModel model) if (!string.IsNullOrEmpty(store.SecureUrl) && !store.SecureUrl.EndsWith("/")) store.SecureUrl += "/"; + var storeUri = new Uri(store.Url); + store.Domains.Add(new DomainHost() { + HostName = storeUri.Host, + Url = store.SslEnabled ? store.SecureUrl : store.Url, + Primary = true + }); + await _storeService.InsertStore(store); return store; } public virtual async Task UpdateStoreModel(Store store, StoreModel model) { store = model.ToEntity(store); + //ensure we have "/" at the end if (!store.Url.EndsWith("/")) store.Url += "/"; if (!string.IsNullOrEmpty(store.SecureUrl) && !store.SecureUrl.EndsWith("/")) store.SecureUrl += "/"; + var domain = store.Domains.FirstOrDefault(x => x.Primary); + if (domain == null) + { + var storeUri = new Uri(store.Url); + store.Domains.Add(new DomainHost() { + HostName = storeUri.Host, + Url = store.SslEnabled ? store.SecureUrl : store.Url, + Primary = true + }); + } + else + { + var storeUri = new Uri(store.Url); + domain.HostName = storeUri.Host; + domain.Url = store.SslEnabled ? store.SecureUrl : store.Url; + } + await _storeService.UpdateStore(store); return store; } @@ -173,5 +190,62 @@ public virtual async Task DeleteStore(Store store) await _settingService.DeleteSetting(setting); } } + + #region DomainHost + + public virtual async Task InsertDomainHostModel(Store store, DomainHostModel model) + { + if (store == null) + throw new ArgumentNullException(nameof(store)); + if (model == null) + throw new ArgumentNullException(nameof(model)); + + if (!model.Url.EndsWith("/")) + model.Url += "/"; + + var storeUri = new Uri(model.Url); + + store.Domains.Add(new DomainHost() { + HostName = storeUri.Host, + Url = model.Url + }); + await _storeService.UpdateStore(store); + + } + + public virtual async Task UpdateDomainHostModel(Store store, DomainHostModel model) + { + if (store == null) + throw new ArgumentNullException(nameof(store)); + if (model == null) + throw new ArgumentNullException(nameof(model)); + + if (!model.Url.EndsWith("/")) + model.Url += "/"; + + var domain = store.Domains.FirstOrDefault(x => x.Id == model.Id); + if (domain != null) + { + var storeUri = new Uri(model.Url); + domain.HostName = storeUri.Host; + domain.Url = model.Url; + } + + await _storeService.UpdateStore(store); + } + + public virtual async Task DeleteDomainHostModel(Store store, string id) + { + var domain = store.Domains.FirstOrDefault(x => x.Id == id); + if (domain != null) + { + store.Domains.Remove(domain); + await _storeService.UpdateStore(store); + } + + } + + #endregion + } } diff --git a/src/Web/Grand.Web.Admin/Validators/Stores/DomainHostValidator.cs b/src/Web/Grand.Web.Admin/Validators/Stores/DomainHostValidator.cs new file mode 100644 index 000000000..f911515ab --- /dev/null +++ b/src/Web/Grand.Web.Admin/Validators/Stores/DomainHostValidator.cs @@ -0,0 +1,32 @@ +using FluentValidation; +using Grand.Infrastructure.Validators; +using Grand.Business.Common.Interfaces.Localization; +using Grand.Web.Admin.Models.Stores; +using System.Collections.Generic; +using System; + +namespace Grand.Web.Admin.Validators.Stores +{ + public class DomainHostValidator : BaseGrandValidator + { + public DomainHostValidator( + IEnumerable> validators, + ITranslationService translationService) + : base(validators) + { + RuleFor(x => x.Url).NotEmpty().WithMessage(translationService.GetResource("Admin.Configuration.Stores.Domains.Fields.Url.Required")); + RuleFor(x => x.Url).Must((x, y, context) => + { + try + { + var storeUri = new Uri(x.Url); + return true; + } + catch + { + return false; + } + }).WithMessage(translationService.GetResource("Admin.Configuration.Stores.Domains.Fields.Url.WrongFormat")); + } + } +} \ No newline at end of file diff --git a/src/Web/Grand.Web.Common/Infrastructure/ServiceCollectionExtensions.cs b/src/Web/Grand.Web.Common/Infrastructure/ServiceCollectionExtensions.cs index 5629a2e78..db6ffe24c 100644 --- a/src/Web/Grand.Web.Common/Infrastructure/ServiceCollectionExtensions.cs +++ b/src/Web/Grand.Web.Common/Infrastructure/ServiceCollectionExtensions.cs @@ -275,7 +275,7 @@ public static void AddSettings(this IServiceCollection services) var type = item.GetType(); var storeId = ""; var settingService = x.GetRequiredService(); - var store = x.GetRequiredService().HostStore; + var store = x.GetRequiredService().StoreHost; if (store != null) storeId = store.Id; diff --git a/src/Web/Grand.Web.Common/StoreHelper.cs b/src/Web/Grand.Web.Common/StoreHelper.cs index 06658067a..9926a0493 100644 --- a/src/Web/Grand.Web.Common/StoreHelper.cs +++ b/src/Web/Grand.Web.Common/StoreHelper.cs @@ -16,7 +16,9 @@ public class StoreHelper : IStoreHelper private readonly IHttpContextAccessor _httpContextAccessor; private readonly IStoreService _storeService; + private Store _cachedStore; + private DomainHost _cachedDomainHost; private const string STORE_COOKIE_NAME = ".Grand.Store"; @@ -24,7 +26,9 @@ public class StoreHelper : IStoreHelper #region Ctor - public StoreHelper(IHttpContextAccessor httpContextAccessor, IStoreService storeService) + public StoreHelper( + IHttpContextAccessor httpContextAccessor, + IStoreService storeService) { _httpContextAccessor = httpContextAccessor; _storeService = storeService; @@ -44,10 +48,8 @@ protected virtual string GetStoreCookie() } #endregion - public Store HostStore - { - get - { + public Store StoreHost { + get { if (_cachedStore == null) { //try to determine the current store by HOST header @@ -85,6 +87,35 @@ public Store HostStore } } + public DomainHost DomainHost { + get + { + if (_cachedDomainHost == null) + { + //try to determine the current HOST header + string host = _httpContextAccessor.HttpContext?.Request?.Headers[HeaderNames.Host]; + if (StoreHost != null) + { + _cachedDomainHost = StoreHost.HostValue(host) ?? new DomainHost() { + Id = int.MinValue.ToString(), + Url = StoreHost.SslEnabled ? StoreHost.SecureUrl : StoreHost.Url, + HostName = "temporary-store" + }; + } + if (_cachedDomainHost == null) + { + _cachedDomainHost = new DomainHost() { + Id = int.MinValue.ToString(), + Url = host, + HostName = "temporary" + }; + } + return _cachedDomainHost; + } + return _cachedDomainHost; + } + } + /// /// Set the current store by BackgroundService /// @@ -124,8 +155,7 @@ public virtual async Task SetStoreCookie(string storeId) var cookieExpiresDate = DateTime.UtcNow.AddHours(CommonHelper.CookieAuthExpires); //set new cookie value - var options = new CookieOptions - { + var options = new CookieOptions { HttpOnly = true, Expires = cookieExpiresDate }; diff --git a/src/Web/Grand.Web.Common/WorkContext.cs b/src/Web/Grand.Web.Common/WorkContext.cs index 025bebc93..ad0493e8c 100644 --- a/src/Web/Grand.Web.Common/WorkContext.cs +++ b/src/Web/Grand.Web.Common/WorkContext.cs @@ -519,7 +519,12 @@ await _userFieldService.SaveField(CurrentCustomer, /// /// Gets the current store /// - public virtual Store CurrentStore => _storeHelper.HostStore; + public virtual Store CurrentStore => _storeHelper.StoreHost; + + /// + /// Gets the current domain host + /// + public virtual DomainHost CurrentHost => _storeHelper.DomainHost; #endregion } diff --git a/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml b/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml index 4f6edc00c..247c85814 100644 --- a/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml +++ b/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml @@ -5066,6 +5066,24 @@ The store has been deleted successfully. + + + Host name + + + Primary URL + + + URL address + + + URL address is required + + + Wrong format for URL address + + + You need to save the store before you can add values for domains. Edit store details @@ -11961,6 +11979,12 @@ Vendor settings + + Domains + + + Store info + System diff --git a/src/Web/Grand.Web/Controllers/CheckoutController.cs b/src/Web/Grand.Web/Controllers/CheckoutController.cs index fbd506677..c4580259c 100644 --- a/src/Web/Grand.Web/Controllers/CheckoutController.cs +++ b/src/Web/Grand.Web/Controllers/CheckoutController.cs @@ -1010,7 +1010,7 @@ public virtual async Task ConfirmOrder() if (paymentMethod.PaymentMethodType == PaymentMethodType.Redirection) { //Redirection will not work because it's AJAX request. - var storeLocation = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); + var storeLocation = _workContext.CurrentHost.Url.TrimEnd('/'); //redirect return Json(new { diff --git a/src/Web/Grand.Web/Features/Handlers/Catalog/GetSearchAutoCompleteHandler.cs b/src/Web/Grand.Web/Features/Handlers/Catalog/GetSearchAutoCompleteHandler.cs index e9cbba890..fc43d3caf 100644 --- a/src/Web/Grand.Web/Features/Handlers/Catalog/GetSearchAutoCompleteHandler.cs +++ b/src/Web/Grand.Web/Features/Handlers/Catalog/GetSearchAutoCompleteHandler.cs @@ -112,7 +112,7 @@ public async Task> Handle(GetSearchAutoComplete r var categories = new List(); var brands = new List(); - var storeurl = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); + var storeurl = _workContext.CurrentHost.Url.TrimEnd('/'); var displayPrices = await _permissionService.Authorize(StandardPermission.DisplayPrices, _workContext.CurrentCustomer); diff --git a/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs b/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs index ab4cea2af..b973399b2 100644 --- a/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs +++ b/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs @@ -118,7 +118,7 @@ private async Task PrepareRobotsTextFile() sb.Append("User-agent: *"); sb.Append(newLine); - var storeLocation = _workContext.CurrentStore.SslEnabled ? _workContext.CurrentStore.SecureUrl.TrimEnd('/') : _workContext.CurrentStore.Url.TrimEnd('/'); + var storeLocation = _workContext.CurrentHost.Url.TrimEnd('/'); //sitemaps sb.AppendFormat("Sitemap: {0}sitemap.xml", storeLocation); From ebf093ba4e3b03589a32d75b4fb53abf41eb1a58 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 31 Aug 2021 12:56:26 +0200 Subject: [PATCH 5/9] Fix test --- .../Extensions/AffiliateExtensions.cs | 4 ++-- .../DotLiquidDrops/LiquidCustomer.cs | 8 ++++---- .../Services/LiquidObjectBuilderTests.cs | 2 +- .../Services/MessageProviderServiceTest.cs | 9 +++++++-- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs b/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs index 3b128f443..5375edc63 100644 --- a/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs +++ b/src/Business/Grand.Business.Customers/Extensions/AffiliateExtensions.cs @@ -54,8 +54,8 @@ public static string GenerateUrl(this Affiliate affiliate, IWorkContext workCont if (workContext == null) throw new ArgumentNullException(nameof(workContext)); - var storeUrl = workContext.CurrentHost.Url.TrimEnd('/'); - var url = !String.IsNullOrEmpty(affiliate.FriendlyUrlName) ? + var storeUrl = workContext.CurrentHost == null ? workContext.CurrentStore.Url : workContext.CurrentHost.Url.TrimEnd('/'); + var url = !string.IsNullOrEmpty(affiliate.FriendlyUrlName) ? CommonExtensions.ModifyQueryString(storeUrl, "affiliate", affiliate.FriendlyUrlName) : CommonExtensions.ModifyQueryString(storeUrl, "affiliateid", affiliate.Id); return url; diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs index c2634272d..a81071b07 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidCustomer.cs @@ -14,15 +14,15 @@ public partial class LiquidCustomer : Drop private readonly Customer _customer; private readonly CustomerNote _customerNote; private readonly Store _store; - private readonly DomainHost _domainHost; + private readonly DomainHost _host; private readonly string url; - public LiquidCustomer(Customer customer, Store store, DomainHost domainHost, CustomerNote customerNote = null) + public LiquidCustomer(Customer customer, Store store, DomainHost host, CustomerNote customerNote = null) { _customer = customer; _customerNote = customerNote; _store = store; - _domainHost = domainHost; - url = _domainHost?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); + _host = host; + url = _host?.Url.Trim('/') ?? (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')); AdditionalTokens = new Dictionary(); } diff --git a/src/Tests/Grand.Business.Messages.Tests/Services/LiquidObjectBuilderTests.cs b/src/Tests/Grand.Business.Messages.Tests/Services/LiquidObjectBuilderTests.cs index bf73320bc..7c0668d29 100644 --- a/src/Tests/Grand.Business.Messages.Tests/Services/LiquidObjectBuilderTests.cs +++ b/src/Tests/Grand.Business.Messages.Tests/Services/LiquidObjectBuilderTests.cs @@ -33,7 +33,7 @@ public async Task BuilderTest() var liquidObject = await builder .AddVendorReviewTokens(vendor, vendorReview) .AddVendorTokens(vendor, new Language()) - .AddOutOfStockTokens(product, new OutOfStockSubscription(), new Store(), new Language()) + .AddOutOfStockTokens(product, new OutOfStockSubscription(), new Store(), new DomainHost() { Url = "https://localhost:44350/" }, new Language()) .BuildAsync(); diff --git a/src/Tests/Grand.Business.Messages.Tests/Services/MessageProviderServiceTest.cs b/src/Tests/Grand.Business.Messages.Tests/Services/MessageProviderServiceTest.cs index 744b1cc77..cf26afa42 100644 --- a/src/Tests/Grand.Business.Messages.Tests/Services/MessageProviderServiceTest.cs +++ b/src/Tests/Grand.Business.Messages.Tests/Services/MessageProviderServiceTest.cs @@ -11,6 +11,7 @@ using Grand.Domain.Messages; using Grand.Domain.Stores; using Grand.Domain.Vendors; +using Grand.Infrastructure; using MediatR; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -29,6 +30,7 @@ public class MessageProviderServiceTest private Mock _emailAccountServiceMock; private Mock _messageTokenProviderMock; private Mock _storeServiceMock; + private Mock _storeHelperServiceMock; private Mock _mediatorMock; private Mock _emailAccountSettingsMock; private Mock _commonSetting; @@ -56,9 +58,11 @@ public void Init() _messageTokenProviderMock = new Mock(); _storeServiceMock = new Mock(); - _storeServiceMock.Setup(x => x.GetStoreById(It.IsAny())).Returns(Task.FromResult(new Store())); + _storeServiceMock.Setup(x => x.GetStoreById(It.IsAny())).Returns(Task.FromResult(new Store() { Url = "https://localhost:44350/" })); _storeServiceMock.Setup(x => x.GetAllStores()).Returns(Task.FromResult(new List() as IList)); + _storeHelperServiceMock = new Mock(); + _mediatorMock = new Mock(); _mediatorMock.Setup(x => x.Send(It.IsAny(), default)) .Returns(Task.FromResult(new Customer { Email = "sdfsdf@mail.com" })); @@ -73,6 +77,7 @@ public void Init() _emailAccountServiceMock.Object, _messageTokenProviderMock.Object, _storeServiceMock.Object, + _storeHelperServiceMock.Object, _groupService.Object, _mediatorMock.Object, _emailAccountSettingsMock.Object, @@ -98,7 +103,7 @@ public async Task SendOutBidCustomerNotificationMethodReturnCorrectResult() [TestMethod()] public async Task SendNewVendorAccountApplyStoreOwnerNotificationRetunsCorrectResult() { - var result = await _messageService.SendNewVendorAccountApplyStoreOwnerMessage(new Customer(), new Vendor(), new Store(), "123"); + var result = await _messageService.SendNewVendorAccountApplyStoreOwnerMessage(new Customer(), new Vendor(), new Store() { Url = "https://localhost:44350/" }, "123"); Assert.AreEqual(result, 1); } From 8afef9f568900d646cb0052dfbcc60ba36b3f67a Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 31 Aug 2021 13:02:03 +0200 Subject: [PATCH 6/9] Fix install process --- .../Services/Installation/InstallDataStores.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs b/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs index 675d97ef9..a95eef5a7 100644 --- a/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs +++ b/src/Business/Grand.Business.System/Services/Installation/InstallDataStores.cs @@ -28,7 +28,7 @@ protected virtual async Task InstallStores(string companyName, string companyAdd CompanyVat = null, CompanyEmail = companyEmail, CompanyHours = "Monday - Sunday / 8:00AM - 6:00PM", - Domains = new List(){ new DomainHost() { HostName = "yourstore.com", Url = storeUrl, Primary = true } } + Domains = new List(){ new DomainHost() { HostName = httpContextAccessor.HttpContext?.Request?.Host.Host, Url = storeUrl, Primary = true } } }, }; From 7432e0c7f7df98193ac5657ba8aec3938d33974f Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 31 Aug 2021 14:03:19 +0200 Subject: [PATCH 7/9] Fix robots.txt --- .../Features/Handlers/Common/GetRobotsTextFileHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs b/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs index b973399b2..ad1a107ea 100644 --- a/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs +++ b/src/Web/Grand.Web/Features/Handlers/Common/GetRobotsTextFileHandler.cs @@ -121,7 +121,7 @@ private async Task PrepareRobotsTextFile() var storeLocation = _workContext.CurrentHost.Url.TrimEnd('/'); //sitemaps - sb.AppendFormat("Sitemap: {0}sitemap.xml", storeLocation); + sb.AppendFormat("Sitemap: {0}/sitemap.xml", storeLocation); sb.Append(newLine); //host From 98f953dce2d077c5889ee7640072543af886c512 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 31 Aug 2021 14:24:53 +0200 Subject: [PATCH 8/9] Minor changes --- .../Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs index 5ff05e511..109df5285 100644 --- a/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs +++ b/src/Business/Grand.Business.Messages/DotLiquidDrops/LiquidShipment.cs @@ -68,7 +68,7 @@ public string URLForCustomer { get { - return string.Format("{0}/orderdetails/shipment/{1}", (_store.SslEnabled ? _store.SecureUrl.Trim('/') : _store.Url.Trim('/')), _shipment.Id); + return string.Format("{0}/orderdetails/shipment/{1}", url, _shipment.Id); } } From 871af40e0ea5ac0c06d6273ee181264e7089a72e Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Tue, 31 Aug 2021 14:52:23 +0200 Subject: [PATCH 9/9] Fix contactAttribute --- .../Services/Contacts/ContactAttributeParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs b/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs index f0dbbd21c..58ebab721 100644 --- a/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs +++ b/src/Business/Grand.Business.Marketing/Services/Contacts/ContactAttributeParser.cs @@ -232,7 +232,7 @@ public virtual async Task FormatAttributes( if (allowHyperlinks) { //hyperlinks are allowed - var downloadLink = string.Format("{0}download/getfileupload/?downloadId={1}", _workContext.CurrentHost.Url.TrimEnd('/'), download.DownloadGuid); + var downloadLink = string.Format("{0}/download/getfileupload/?downloadId={1}", _workContext.CurrentHost.Url.TrimEnd('/'), download.DownloadGuid); attributeText = string.Format("{1}", downloadLink, fileName); } else