private async Task PrepareTopicModelAsync(Topic topic, TopicModel model) { model.Url = await GetTopicUrlAsync(topic); model.SelectedStoreIds = await _storeMappingService.GetAuthorizedStoreIdsAsync(topic); model.SelectedCustomerRoleIds = await _aclService.GetAuthorizedCustomerRoleIdsAsync(topic); AddCookieTypes(model, model.CookieType); }
/// <summary> /// Finds store identifiers with granted access (mapped to the entity). /// </summary> /// <typeparam name="T">Entity type.</typeparam> /// <param name="entity">Entity to check.</param> /// <returns>Store identifiers.</returns> public static Task <int[]> GetAuthorizedStoreIdsAsync <T>(this IStoreMappingService svc, T entity) where T : BaseEntity, IStoreRestricted { if (entity == null) { return(Task.FromResult(Array.Empty <int>())); } return(svc.GetAuthorizedStoreIdsAsync(entity.GetEntityName(), entity.Id)); }
public virtual async Task <int> SendCampaignAsync(Campaign campaign, CancellationToken cancelToken = default) { Guard.NotNull(campaign, nameof(campaign)); var totalEmailsSent = 0; var pageIndex = -1; int[] storeIds = null; int[] roleIds = null; var alreadyProcessedEmails = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); if (campaign.LimitedToStores) { storeIds = await _storeMappingService.GetAuthorizedStoreIdsAsync(campaign); } if (campaign.SubjectToAcl) { roleIds = await _db.AclRecords .ApplyEntityFilter(campaign) .Select(x => x.CustomerRoleId) .Distinct() .ToArrayAsync(); } while (true) { cancelToken.ThrowIfCancellationRequested(); var subscribers = _db.NewsletterSubscriptions .ApplyStandardFilter(null, false, storeIds, roleIds) .ToPagedList(++pageIndex, 500); await foreach (var subscriber in subscribers) { // Create only one message per subscription email. if (alreadyProcessedEmails.Contains(subscriber.Subscription.Email)) { continue; } if (subscriber.Customer != null && !subscriber.Customer.Active) { continue; } var result = await CreateCampaignMessageAsync(campaign, subscriber); if ((result?.Email?.Id ?? 0) != 0) { alreadyProcessedEmails.Add(subscriber.Subscription.Email); ++totalEmailsSent; // Publish event so that integrators can add attachments, alter the email etc. await _eventPublisher.PublishAsync(new MessageQueuingEvent { QueuedEmail = result.Email, MessageContext = result.MessageContext, MessageModel = result.MessageContext.Model }); // Queue emails so they can be saved later in one go. _db.QueuedEmails.Add(result.Email); } } // Save all queued emails now. await _db.SaveChangesAsync(cancelToken); if (!subscribers.HasNextPage) { break; } } return(totalEmailsSent); }
public virtual async Task <Product> CloneProductAsync( Product product, string cloneName, bool isPublished, bool copyAssociatedProducts = true) { Guard.NotNull(product, nameof(product)); Guard.NotEmpty(cloneName, nameof(cloneName)); var localizedKeySelectors = new List <Expression <Func <Product, string> > > { x => x.Name, x => x.ShortDescription, x => x.FullDescription, x => x.MetaKeywords, x => x.MetaDescription, x => x.MetaTitle, x => x.BundleTitleText }; var clone = new Product(); var utcNow = DateTime.UtcNow; var languages = await _languageService.GetAllLanguagesAsync(true); int?sampleDownloadId = null; // Enable hooks for slugs cache invalidation. using (_chronometer.Step("Clone product " + product.Id)) using (var scope = new DbContextScope(_db, autoDetectChanges: false, hooksEnabled: true, deferCommit: true, forceNoTracking: true)) { if (product.HasSampleDownload && product.SampleDownload != null) { var sampleDownloadClone = product.SampleDownload.Clone(); _db.Downloads.Add(sampleDownloadClone); await scope.CommitAsync(); sampleDownloadId = sampleDownloadClone.Id; } var props = FastProperty.GetProperties(typeof(Product), PropertyCachingStrategy.EagerCached); foreach (var prop in props.Values) { if (prop.IsComplexType) { continue; } if (!prop.IsPublicSettable) { continue; } prop.SetValue(clone, prop.GetValue(product)); } clone.Id = 0; clone.Name = cloneName; clone.SampleDownloadId = sampleDownloadId; clone.Published = isPublished; clone.CreatedOnUtc = utcNow; clone.UpdatedOnUtc = utcNow; // Category mappings. clone.ProductCategories.AddRange(product.ProductCategories.Select(x => new ProductCategory { CategoryId = x.CategoryId, IsFeaturedProduct = x.IsFeaturedProduct, DisplayOrder = x.DisplayOrder })); // Manufacturer mappings. clone.ProductManufacturers.AddRange(product.ProductManufacturers.Select(x => new ProductManufacturer { ManufacturerId = x.ManufacturerId, IsFeaturedProduct = x.IsFeaturedProduct, DisplayOrder = x.DisplayOrder })); // Media file mappings. clone.ProductPictures.AddRange(product.ProductPictures.Select(x => new ProductMediaFile { MediaFileId = x.MediaFileId, DisplayOrder = x.DisplayOrder })); if (clone.MainPictureId == null) { clone.MainPictureId = product.ProductPictures.FirstOrDefault()?.MediaFileId; } // Product specification attributes. clone.ProductSpecificationAttributes.AddRange(product.ProductSpecificationAttributes.Select(x => new ProductSpecificationAttribute { SpecificationAttributeOptionId = x.SpecificationAttributeOptionId, AllowFiltering = x.AllowFiltering, ShowOnProductPage = x.ShowOnProductPage, DisplayOrder = x.DisplayOrder })); // Tier prices. clone.TierPrices.AddRange(product.TierPrices.Select(x => new TierPrice { StoreId = x.StoreId, CustomerRoleId = x.CustomerRoleId, Quantity = x.Quantity, Price = x.Price, CalculationMethod = x.CalculationMethod })); clone.HasTierPrices = clone.TierPrices.Any(); // Discount mappings. foreach (var discount in product.AppliedDiscounts) { clone.AppliedDiscounts.Add(discount); clone.HasDiscountsApplied = true; } // Tags. foreach (var tag in product.ProductTags) { clone.ProductTags.Add(tag); } // >>>>>>> Put clone to db (from here on we need the product clone's ID). _db.Products.Add(clone); await scope.CommitAsync(); // Store mappings. var selectedStoreIds = await _storeMappingService.GetAuthorizedStoreIdsAsync(product); selectedStoreIds.Each(id => _storeMappingService.AddStoreMapping(clone, id)); await ProcessPromotions(product, clone); await ProcessSlugs(product, clone, languages); await ProcessLocalizations(product, clone, localizedKeySelectors, languages); await ProcessDownloads(product, clone); // >>>>>>> Put to db. await scope.CommitAsync(); await ProcessBundleItems(scope, product, clone, languages); // Attributes and attribute combinations. await ProcessAttributes(scope, product, clone, languages); // Update computed properties. clone.LowestAttributeCombinationPrice = await _db.ProductVariantAttributeCombinations .ApplyLowestPriceFilter(clone.Id) .Select(x => x.Price) .FirstOrDefaultAsync(); // Associated products. if (copyAssociatedProducts && product.ProductType != ProductType.BundledProduct) { await ProcessAssociatedProducts(product, clone, isPublished); } // >>>>>>> Our final commit. await scope.CommitAsync(); } return(clone); }