Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        /// <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));
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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);
        }