Пример #1
0
        /// <summary>
        /// Get language from the requested page URL
        /// </summary>
        /// <returns>The found language</returns>
        protected virtual async Task <Language> GetLanguageFromUrlAsync()
        {
            if (_httpContextAccessor.HttpContext?.Request == null)
            {
                return(null);
            }

            //whether the requsted URL is localized
            var path = _httpContextAccessor.HttpContext.Request.Path.Value;

            var(isLocalized, language) = await path.IsLocalizedUrlAsync(_httpContextAccessor.HttpContext.Request.PathBase, false);

            if (!isLocalized)
            {
                return(null);
            }

            //check language availability
            if (!await _storeMappingService.AuthorizeAsync(language))
            {
                return(null);
            }

            return(language);
        }
Пример #2
0
        private async Task <bool> CheckCategoryAvailabilityAsync(Category category)
        {
            var isAvailable = true;

            if (category == null || category.Deleted)
            {
                isAvailable = false;
            }

            var notAvailable =
                //published?
                !category.Published ||
                //ACL (access control list)
                !await _aclService.AuthorizeAsync(category) ||
                //Store mapping
                !await _storeMappingService.AuthorizeAsync(category);

            //Check whether the current user has a "Manage categories" permission (usually a store owner)
            //We should allows him (her) to use "Preview" functionality
            var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageCategories);

            if (notAvailable && !hasAdminAccess)
            {
                isAvailable = false;
            }

            return(isAvailable);
        }
        /// <summary>
        /// Prepare billing address model
        /// </summary>
        /// <param name="cart">Cart</param>
        /// <param name="selectedCountryId">Selected country identifier</param>
        /// <param name="prePopulateNewAddressWithCustomerFields">Pre populate new address with customer fields</param>
        /// <param name="overrideAttributesXml">Override attributes xml</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the billing address model
        /// </returns>
        public virtual async Task <CheckoutBillingAddressModel> PrepareBillingAddressModelAsync(IList <ShoppingCartItem> cart,
                                                                                                int?selectedCountryId = null,
                                                                                                bool prePopulateNewAddressWithCustomerFields = false,
                                                                                                string overrideAttributesXml = "")
        {
            var model = new CheckoutBillingAddressModel
            {
                ShipToSameAddressAllowed = _shippingSettings.ShipToSameAddress && await _shoppingCartService.ShoppingCartRequiresShippingAsync(cart),
                //allow customers to enter (choose) a shipping address if "Disable Billing address step" setting is enabled
                ShipToSameAddress = !_orderSettings.DisableBillingAddressCheckoutStep
            };

            //existing addresses
            var customer = await _workContext.GetCurrentCustomerAsync();

            var addresses = await(await _customerService.GetAddressesByCustomerIdAsync(customer.Id))
                            .WhereAwait(async a => !a.CountryId.HasValue || await _countryService.GetCountryByAddressAsync(a) is Country country &&
                                        (//published
                                            country.Published &&
                                            //allow billing
                                            country.AllowsBilling &&
                                            //enabled for the current store
                                            await _storeMappingService.AuthorizeAsync(country)))
                            .ToListAsync();

            foreach (var address in addresses)
            {
                var addressModel = new AddressModel();
                await _addressModelFactory.PrepareAddressModelAsync(addressModel,
                                                                    address : address,
                                                                    excludeProperties : false,
                                                                    addressSettings : _addressSettings);

                if (await _addressService.IsAddressValidAsync(address))
                {
                    model.ExistingAddresses.Add(addressModel);
                }
                else
                {
                    model.InvalidExistingAddresses.Add(addressModel);
                }
            }

            //new address
            model.BillingNewAddress.CountryId = selectedCountryId;
            await _addressModelFactory.PrepareAddressModelAsync(model.BillingNewAddress,
                                                                address : null,
                                                                excludeProperties : false,
                                                                addressSettings : _addressSettings,
                                                                loadCountries : async() => await _countryService.GetAllCountriesForBillingAsync((await _workContext.GetWorkingLanguageAsync()).Id),
                                                                prePopulateWithCustomerFields : prePopulateNewAddressWithCustomerFields,
                                                                customer : customer,
                                                                overrideAttributesXml : overrideAttributesXml);

            return(model);
        }
Пример #4
0
        public virtual async Task <IActionResult> Category(int categoryId, CatalogPagingFilteringModel command)
        {
            var category = await _categoryService.GetCategoryByIdAsync(categoryId);

            if (category == null || category.Deleted)
            {
                return(InvokeHttp404());
            }

            var notAvailable =
                //published?
                !category.Published ||
                //ACL (access control list)
                !await _aclService.AuthorizeAsync(category) ||
                //Store mapping
                !await _storeMappingService.AuthorizeAsync(category);

            //Check whether the current user has a "Manage categories" permission (usually a store owner)
            //We should allows him (her) to use "Preview" functionality
            var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageCategories);

            if (notAvailable && !hasAdminAccess)
            {
                return(InvokeHttp404());
            }

            //'Continue shopping' URL
            await _genericAttributeService.SaveAttributeAsync(await _workContext.GetCurrentCustomerAsync(),
                                                              NopCustomerDefaults.LastContinueShoppingPageAttribute,
                                                              _webHelper.GetThisPageUrl(false),
                                                              (await _storeContext.GetCurrentStoreAsync()).Id);

            //display "edit" (manage) link
            if (await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageCategories))
            {
                DisplayEditLink(Url.Action("Edit", "Category", new { id = category.Id, area = AreaNames.Admin }));
            }

            //activity log
            await _customerActivityService.InsertActivityAsync("PublicStore.ViewCategory",
                                                               string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.ViewCategory"), category.Name), category);

            //model
            var model = await _catalogModelFactory.PrepareCategoryModelAsync(category, command);

            //template
            var templateViewPath = await _catalogModelFactory.PrepareCategoryTemplateViewPathAsync(category.CategoryTemplateId);

            return(View(templateViewPath, model));
        }
Пример #5
0
        public async Task <IActionResult> TopicDetails(int topicId, bool popup = false)
        {
            await _helper.GetBreadcrumbAsync(_breadcrumb, ControllerContext);

            var cacheKey = string.Format(ModelCacheInvalidator.TOPIC_BY_ID_KEY,
                                         topicId,
                                         Services.WorkContext.WorkingLanguage.Id,
                                         Services.StoreContext.CurrentStore.Id,
                                         Services.WorkContext.CurrentCustomer.GetRolesIdent());

            var cacheModel = await Services.CacheFactory.GetMemoryCache().GetAsync(cacheKey, async(o) =>
            {
                o.ExpiresIn(TimeSpan.FromDays(1));

                var topic = await Services.DbContext.Topics.FindByIdAsync(topicId, false);
                if (topic == null || !topic.IsPublished)
                {
                    return(null);
                }

                if (!await _storeMappingService.AuthorizeAsync(topic))
                {
                    return(null);
                }

                if (!await _aclService.AuthorizeAsync(topic))
                {
                    return(null);
                }

                return(PrepareTopicModel(topic));
            });

            if (cacheModel == null || (!popup && cacheModel.RenderAsWidget))
            {
                return(NotFound());
            }

            ViewBag.IsPopup = popup;

            if (!cacheModel.RenderAsWidget)
            {
                Services.DisplayControl.Announce(new Topic {
                    Id = cacheModel.Id
                });
            }

            return(View("TopicDetails", cacheModel));
        }
Пример #6
0
        public virtual async Task <IActionResult> Authenticate(int id, string password)
        {
            var authResult = false;
            var title      = string.Empty;
            var body       = string.Empty;
            var error      = string.Empty;

            var topic = await _topicService.GetTopicByIdAsync(id);

            if (topic != null &&
                topic.Published &&
                //password protected?
                topic.IsPasswordProtected &&
                //store mapping
                await _storeMappingService.AuthorizeAsync(topic) &&
                //ACL (access control list)
                await _aclService.AuthorizeAsync(topic))
            {
                if (topic.Password != null && topic.Password.Equals(password))
                {
                    authResult = true;
                    title      = await _localizationService.GetLocalizedAsync(topic, x => x.Title);

                    body = await _localizationService.GetLocalizedAsync(topic, x => x.Body);
                }
                else
                {
                    error = await _localizationService.GetResourceAsync("Topic.WrongPassword");
                }
            }

            return(Json(new { Authenticated = authResult, Title = title, Body = body, Error = error }));
        }
        /// <summary>
        /// Gets all categories displayed on the home page
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the categories
        /// </returns>
        public virtual async Task <IList <Category> > GetAllCategoriesDisplayedOnHomepageAsync(bool showHidden = false)
        {
            var categories = await _categoryRepository.GetAllAsync(query =>
            {
                return(from c in query
                       orderby c.DisplayOrder, c.Id
                       where c.Published &&
                       !c.Deleted &&
                       c.ShowOnHomepage
                       select c);
            }, cache => cache.PrepareKeyForDefaultCache(NopCatalogDefaults.CategoriesHomepageCacheKey));

            if (showHidden)
            {
                return(categories);
            }

            var cacheKey = _staticCacheManager.PrepareKeyForDefaultCache(NopCatalogDefaults.CategoriesHomepageWithoutHiddenCacheKey,
                                                                         await _storeContext.GetCurrentStoreAsync(), await _customerService.GetCustomerRoleIdsAsync(await _workContext.GetCurrentCustomerAsync()));

            var result = await _staticCacheManager.GetAsync(cacheKey, async() =>
            {
                return(await categories
                       .WhereAwait(async c => await _aclService.AuthorizeAsync(c) && await _storeMappingService.AuthorizeAsync(c))
                       .ToListAsync());
            });

            return(result);
        }
Пример #8
0
        /// <summary>
        /// Get language from the request
        /// </summary>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the found language
        /// </returns>
        protected virtual async Task <Language> GetLanguageFromRequestAsync()
        {
            var requestCultureFeature = _httpContextAccessor.HttpContext?.Features.Get <IRequestCultureFeature>();

            if (requestCultureFeature is null)
            {
                return(null);
            }

            //whether we should detect the current language by customer settings
            if (requestCultureFeature.Provider is not NopSeoUrlCultureProvider && !_localizationSettings.AutomaticallyDetectLanguage)
            {
                return(null);
            }

            //get request culture
            if (requestCultureFeature.RequestCulture is null)
            {
                return(null);
            }

            //try to get language by culture name
            var requestLanguage = (await _languageService.GetAllLanguagesAsync()).FirstOrDefault(language =>
                                                                                                 language.LanguageCulture.Equals(requestCultureFeature.RequestCulture.Culture.Name, StringComparison.InvariantCultureIgnoreCase));

            //check language availability
            if (requestLanguage == null || !requestLanguage.Published || !await _storeMappingService.AuthorizeAsync(requestLanguage))
            {
                return(null);
            }

            return(requestLanguage);
        }
Пример #9
0
        public async Task <IActionResult> ProductDetails(int productId, ProductVariantQuery query)
        {
            var product = await _db.Products.FindByIdAsync(productId, false);

            if (product == null || product.Deleted || product.IsSystemProduct)
            {
                return(NotFound());
            }

            // Is published? Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a product before publishing.
            if (!product.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Product.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(product))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(product))
            {
                return(NotFound());
            }

            // TODO: (mh) (core) Continue CatalogController.Category()

            var store = Services.StoreContext.CurrentStore;
            var price = store.PrimaryStoreCurrency.AsMoney(product.Price).ExchangeTo(Services.WorkContext.WorkingCurrency);

            return(Content($"Product --> Id: {product.Id}, Name: {product.Name}, Price: {price}"));
        }
Пример #10
0
        /// <summary>
        /// Checks whether entities are accessible in a given store.
        /// </summary>
        /// <typeparam name="T">Entity type.</typeparam>
        /// <param name="service">Store mapping service.</param>
        /// <param name="entities">Entities to check.</param>
        /// <param name="storeId">Store identifier.</param>
        /// <returns>Authorized entities.</returns>
        public static IAsyncEnumerable <T> SelectAuthorizedAsync <T>(this IStoreMappingService service, IEnumerable <T> entities, int storeId)
            where T : BaseEntity, IStoreRestricted
        {
            Guard.NotNull(entities, nameof(entities));

            return(entities.WhereAsync(x => service.AuthorizeAsync(x.GetEntityName(), x.Id, storeId)));
        }
        /// <summary>
        /// Gets all languages
        /// </summary>
        /// <param name="storeId">Load records allowed only in a specified store; pass 0 to load all records</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the languages
        /// </returns>
        public virtual async Task <IList <Language> > GetAllLanguagesAsync(bool showHidden = false, int storeId = 0)
        {
            //cacheable copy
            var key = _staticCacheManager.PrepareKeyForDefaultCache(NopLocalizationDefaults.LanguagesAllCacheKey, storeId, showHidden);

            var languages = await _staticCacheManager.GetAsync(key, async() =>
            {
                var allLanguages = await _languageRepository.GetAllAsync(query =>
                {
                    if (!showHidden)
                    {
                        query = query.Where(l => l.Published);
                    }
                    query = query.OrderBy(l => l.DisplayOrder).ThenBy(l => l.Id);

                    return(query);
                });

                //store mapping
                if (storeId > 0)
                {
                    allLanguages = await allLanguages
                                   .WhereAwait(async l => await _storeMappingService.AuthorizeAsync(l, storeId))
                                   .ToListAsync();
                }

                return(allLanguages);
            });

            return(languages);
        }
Пример #12
0
        /// <summary>
        /// Get the topic model by topic identifier
        /// </summary>
        /// <param name="topicId">Topic identifier</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>Topic model</returns>
        public virtual async Task <TopicModel> PrepareTopicModelByIdAsync(int topicId, bool showHidden = false)
        {
            var topic = await _topicService.GetTopicByIdAsync(topicId);

            if (topic == null)
            {
                return(null);
            }

            if (showHidden)
            {
                return(await PrepareTopicModelAsync(topic));
            }

            if (!topic.Published ||
                //ACL (access control list)
                !await _aclService.AuthorizeAsync(topic) ||
                //store mapping
                !await _storeMappingService.AuthorizeAsync(topic))
            {
                return(null);
            }

            return(await PrepareTopicModelAsync(topic));
        }
        private async Task <int> GetDefaultStoreLangaugeIdAsync()
        {
            // Get the default language id for the current store.
            var defaultLanguageId = _storeContext.GetCurrentStore().DefaultLanguageId;

            if (defaultLanguageId == 0)
            {
                var allLanguages = await _languageService.GetAllLanguagesAsync();

                int currentStoreId = _storeContext.GetCurrentStore().Id;

                var storeLanguages = await allLanguages.WhereAwait(async l => await _storeMappingService.AuthorizeAsync(l, currentStoreId)).ToListAsync();

                // If there is no language mapped to the current store, get all of the languages,
                // and use the one with the first display order. This is a default nopCommerce workflow.
                if (storeLanguages.Count == 0)
                {
                    storeLanguages = allLanguages.ToList();
                }

                var defaultLanguage = storeLanguages.OrderBy(l => l.DisplayOrder).First();

                defaultLanguageId = defaultLanguage.Id;
            }

            return(defaultLanguageId);
        }
Пример #14
0
        public async Task <int> GetProductsCountAsync(
            DateTime?createdAtMin = null, DateTime?createdAtMax = null,
            DateTime?updatedAtMin = null, DateTime?updatedAtMax = null, bool?publishedStatus = null, string vendorName = null,
            int?categoryId        = null)
        {
            var query = GetProductsQuery(createdAtMin, createdAtMax, updatedAtMin, updatedAtMax, vendorName,
                                         publishedStatus, categoryId: categoryId);

            return(await query.WhereAwait(async p => await _storeMappingService.AuthorizeAsync(p)).CountAsync());
        }
        public async Task <int> GetCategoriesCountAsync(
            DateTime?createdAtMin = null, DateTime?createdAtMax = null,
            DateTime?updatedAtMin = null, DateTime?updatedAtMax = null,
            bool?publishedStatus  = null, int?productId         = null)
        {
            var query = GetCategoriesQuery(createdAtMin, createdAtMax, updatedAtMin, updatedAtMax,
                                           publishedStatus, productId);

            return(await query.WhereAwait(async c => await _storeMappingService.AuthorizeAsync(c)).CountAsync());
        }
Пример #16
0
        public async Task <IActionResult> Category(int categoryId, CatalogSearchQuery query)
        {
            var category = await _db.Categories.FindByIdAsync(categoryId, false);

            if (category == null || category.Deleted)
            {
                return(NotFound());
            }

            // Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a category before publishing.
            if (!category.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Category.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(category))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(category))
            {
                return(NotFound());
            }

            var customer = Services.WorkContext.CurrentCustomer;

            // 'Continue shopping' URL.
            if (!customer.IsSystemAccount)
            {
                customer.GenericAttributes.LastContinueShoppingPage = Services.WebHelper.GetCurrentPageUrl(false);
                await _db.SaveChangesAsync();
            }

            // TODO: (mh) (core) Continue CatalogController.Category()

            return(Content($"Category --> Id: {category.Id}, Name: {category.Name}"));
        }
Пример #17
0
        /// <summary>
        /// Checks whether an entity can be accessed in a given store.
        /// </summary>
        /// <typeparam name="T">Entity type.</typeparam>
        /// <param name="service">Store mapping service.</param>
        /// <param name="entity">Entity to check.</param>
        /// <param name="storeId">Store identifier.</param>
        /// <returns><c>true</c> authorized, otherwise <c>false</c>.</returns>
        public static Task <bool> AuthorizeAsync <T>(this IStoreMappingService svc, T entity, int storeId) where T : BaseEntity, IStoreRestricted
        {
            if (entity == null)
            {
                return(Task.FromResult(false));
            }

            if (!entity.LimitedToStores)
            {
                return(Task.FromResult(true));
            }

            return(svc.AuthorizeAsync(entity.GetEntityName(), entity.Id, storeId));
        }
Пример #18
0
        public virtual async Task <IActionResult> Vote(int pollAnswerId)
        {
            var pollAnswer = await _pollService.GetPollAnswerByIdAsync(pollAnswerId);

            if (pollAnswer == null)
            {
                return(Json(new { error = "No poll answer found with the specified id" }));
            }

            var poll = await _pollService.GetPollByIdAsync(pollAnswer.PollId);

            if (!poll.Published || !await _storeMappingService.AuthorizeAsync(poll))
            {
                return(Json(new { error = "Poll is not available" }));
            }

            var customer = await _workContext.GetCurrentCustomerAsync();

            if (await _customerService.IsGuestAsync(customer) && !poll.AllowGuestsToVote)
            {
                return(Json(new { error = await _localizationService.GetResourceAsync("Polls.OnlyRegisteredUsersVote") }));
            }

            var alreadyVoted = await _pollService.AlreadyVotedAsync(poll.Id, customer.Id);

            if (!alreadyVoted)
            {
                //vote
                await _pollService.InsertPollVotingRecordAsync(new PollVotingRecord
                {
                    PollAnswerId = pollAnswer.Id,
                    CustomerId   = customer.Id,
                    CreatedOnUtc = DateTime.UtcNow
                });

                //update totals
                pollAnswer.NumberOfVotes = (await _pollService.GetPollVotingRecordsByPollAnswerAsync(pollAnswer.Id)).Count;
                await _pollService.UpdatePollAnswerAsync(pollAnswer);

                await _pollService.UpdatePollAsync(poll);
            }

            return(Json(new
            {
                html = await RenderPartialViewToStringAsync("_Poll", await _pollModelFactory.PreparePollModelAsync(poll, true)),
            }));
        }
Пример #19
0
        public virtual async Task <IActionResult> NewsItem(int newsItemId)
        {
            if (!_newsSettings.Enabled)
            {
                return(RedirectToRoute("Homepage"));
            }

            var newsItem = await _newsService.GetNewsByIdAsync(newsItemId);

            if (newsItem == null)
            {
                return(InvokeHttp404());
            }

            var notAvailable =
                //published?
                !newsItem.Published ||
                //availability dates
                !_newsService.IsNewsAvailable(newsItem) ||
                //Store mapping
                !await _storeMappingService.AuthorizeAsync(newsItem);

            //Check whether the current user has a "Manage news" permission (usually a store owner)
            //We should allows him (her) to use "Preview" functionality
            var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageNews);

            if (notAvailable && !hasAdminAccess)
            {
                return(InvokeHttp404());
            }

            var model = new NewsItemModel();

            model = await _newsModelFactory.PrepareNewsItemModelAsync(model, newsItem, true);

            //display "edit" (manage) link
            if (hasAdminAccess)
            {
                DisplayEditLink(Url.Action("NewsItemEdit", "News", new { id = newsItem.Id, area = AreaNames.Admin }));
            }

            return(View(model));
        }
Пример #20
0
        public async Task <IActionResult> ProductDetails(int productId, ProductVariantQuery query)
        {
            var product = await _db.Products.FindByIdAsync(productId, false);

            if (product == null || product.Deleted || product.IsSystemProduct)
            {
                return(NotFound());
            }

            // Is published? Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a product before publishing.
            if (!product.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Product.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(product))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(product))
            {
                return(NotFound());
            }

            // Save as recently viewed
            _recentlyViewedProductsService.AddProductToRecentlyViewedList(product.Id);

            // Activity log
            Services.ActivityLogger.LogActivity("PublicStore.ViewProduct", T("ActivityLog.PublicStore.ViewProduct"), product.Name);

            // TODO: (mh) (core) Continue CatalogController.Category()

            var store = Services.StoreContext.CurrentStore;
            var price = Services.CurrencyService.ConvertToWorkingCurrency(product.Price);

            return(Content($"Product --> Id: {product.Id}, Name: {product.Name}, Price: {price}"));
        }
        public virtual async Task <IActionResult> BlogPost(int blogPostId)
        {
            if (!_blogSettings.Enabled)
            {
                return(RedirectToRoute("Homepage"));
            }

            var blogPost = await _blogService.GetBlogPostByIdAsync(blogPostId);

            if (blogPost == null)
            {
                return(InvokeHttp404());
            }

            var notAvailable =
                //availability dates
                !_blogService.BlogPostIsAvailable(blogPost) ||
                //Store mapping
                !await _storeMappingService.AuthorizeAsync(blogPost);

            //Check whether the current user has a "Manage blog" permission (usually a store owner)
            //We should allows him (her) to use "Preview" functionality
            var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageBlog);

            if (notAvailable && !hasAdminAccess)
            {
                return(InvokeHttp404());
            }

            //display "edit" (manage) link
            if (hasAdminAccess)
            {
                DisplayEditLink(Url.Action("BlogPostEdit", "Blog", new { id = blogPost.Id, area = AreaNames.Admin }));
            }

            var model = new BlogPostModel();
            await _blogModelFactory.PrepareBlogPostModelAsync(model, blogPost, true);

            return(View(model));
        }
Пример #22
0
        /// <summary>
        /// Gets all currencies
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <param name="storeId">Load records allowed only in a specified store; pass 0 to load all records</param>
        /// <returns>
        /// A task that represents the asynchronous operation
        /// The task result contains the currencies
        /// </returns>
        public virtual async Task <IList <Currency> > GetAllCurrenciesAsync(bool showHidden = false, int storeId = 0)
        {
            var currencies = await _currencyRepository.GetAllAsync(query =>
            {
                if (!showHidden)
                {
                    query = query.Where(c => c.Published);
                }

                query = query.OrderBy(c => c.DisplayOrder).ThenBy(c => c.Id);

                return(query);
            }, cache => cache.PrepareKeyForDefaultCache(NopDirectoryDefaults.CurrenciesAllCacheKey, showHidden));

            //store mapping
            if (storeId > 0)
            {
                currencies = await currencies
                             .WhereAwait(async c => await _storeMappingService.AuthorizeAsync(c, storeId))
                             .ToListAsync();
            }

            return(currencies);
        }
Пример #23
0
        public async Task <IViewComponentResult> InvokeAsync(int productId, int?productThumbPictureSize)
        {
            if (!_catalogSettings.ProductsAlsoPurchasedEnabled)
            {
                return(Content(""));
            }

            //load and cache report
            var store = await _storeContext.GetCurrentStoreAsync();

            var productIds = await _staticCacheManager.GetAsync(_staticCacheManager.PrepareKeyForDefaultCache(NopModelCacheDefaults.ProductsAlsoPurchasedIdsKey, productId, store),
                                                                async() => await _orderReportService.GetAlsoPurchasedProductsIdsAsync(store.Id, productId, _catalogSettings.ProductsAlsoPurchasedNumber)
                                                                );

            //load products
            var products = await(await _productService.GetProductsByIdsAsync(productIds))
                           //ACL and store mapping
                           .WhereAwait(async p => await _aclService.AuthorizeAsync(p) && await _storeMappingService.AuthorizeAsync(p))
                           //availability dates
                           .Where(p => _productService.ProductIsAvailable(p)).ToListAsync();

            if (!products.Any())
            {
                return(Content(""));
            }

            var model = (await _productModelFactory.PrepareProductOverviewModelsAsync(products, true, true, productThumbPictureSize)).ToList();

            return(View(model));
        }
Пример #24
0
        public async Task <IActionResult> Category(int categoryId, CatalogSearchQuery query)
        {
            var category = await _db.Categories
                           .Include(x => x.MediaFile)
                           .FindByIdAsync(categoryId, false);

            if (category == null || category.Deleted)
            {
                return(NotFound());
            }

            // Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a category before publishing.
            if (!category.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Category.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(category))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(category))
            {
                return(NotFound());
            }

            var customer = Services.WorkContext.CurrentCustomer;
            var storeId  = Services.StoreContext.CurrentStore.Id;

            // 'Continue shopping' URL.
            if (!customer.IsSystemAccount)
            {
                customer.GenericAttributes.LastContinueShoppingPage = Services.WebHelper.GetCurrentPageUrl(false);
            }

            var model = await _helper.PrepareCategoryModelAsync(category);

            if (_seoSettings.CanonicalUrlsEnabled)
            {
                model.CanonicalUrl = _urlHelper.Value.RouteUrl("Category", new { model.SeName }, Request.Scheme);
            }

            if (query.IsSubPage && !_catalogSettings.ShowDescriptionInSubPages)
            {
                model.Description.ChangeValue(string.Empty);
                model.BottomDescription.ChangeValue(string.Empty);
            }

            model.Image = await _helper.PrepareCategoryImageModelAsync(category, model.Name);

            // Category breadcrumb.
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                await _helper.GetBreadcrumbAsync(_breadcrumb, ControllerContext);
            }

            // Products.
            var catIds = new int[] { categoryId };

            if (_catalogSettings.ShowProductsFromSubcategories)
            {
                // Include subcategories.
                catIds = catIds.Concat(await _helper.GetChildCategoryIdsAsync(categoryId)).ToArray();
            }

            query.WithCategoryIds(_catalogSettings.IncludeFeaturedProductsInNormalLists ? null : false, catIds);

            var searchResult = await _catalogSearchService.SearchAsync(query);

            model.SearchResult = searchResult;

            var viewMode        = _helper.GetSearchQueryViewMode(query);
            var mappingSettings = _helper.GetBestFitProductSummaryMappingSettings(viewMode);

            model.Products = await _helper.MapProductSummaryModelAsync(searchResult, mappingSettings);

            model.SubCategoryDisplayType = _catalogSettings.SubCategoryDisplayType;

            var pictureSize  = _mediaSettings.CategoryThumbPictureSize;
            var fallbackType = _catalogSettings.HideCategoryDefaultPictures ? FallbackPictureType.NoFallback : FallbackPictureType.Entity;

            var hideSubCategories = _catalogSettings.SubCategoryDisplayType == SubCategoryDisplayType.Hide ||
                                    (_catalogSettings.SubCategoryDisplayType == SubCategoryDisplayType.AboveProductList && query.IsSubPage && !_catalogSettings.ShowSubCategoriesInSubPages);
            var hideFeaturedProducts = _catalogSettings.IgnoreFeaturedProducts || (query.IsSubPage && !_catalogSettings.IncludeFeaturedProductsInSubPages);

            // Subcategories.
            if (!hideSubCategories)
            {
                var subCategories = await _categoryService.GetCategoriesByParentCategoryIdAsync(categoryId);

                model.SubCategories = await _helper.MapCategorySummaryModelAsync(subCategories, pictureSize);
            }

            // Featured Products.
            if (!hideFeaturedProducts)
            {
                CatalogSearchResult featuredProductsResult = null;

                string cacheKey = ModelCacheInvalidator.CATEGORY_HAS_FEATURED_PRODUCTS_KEY.FormatInvariant(categoryId, string.Join(",", customer.GetRoleIds()), storeId);
                var    hasFeaturedProductsCache = await Services.Cache.GetAsync <bool?>(cacheKey);

                var featuredProductsQuery = new CatalogSearchQuery()
                                            .VisibleOnly(customer)
                                            .WithVisibility(ProductVisibility.Full)
                                            .WithCategoryIds(true, categoryId)
                                            .HasStoreId(storeId)
                                            .WithLanguage(Services.WorkContext.WorkingLanguage)
                                            .WithCurrency(Services.WorkContext.WorkingCurrency);

                if (!hasFeaturedProductsCache.HasValue)
                {
                    featuredProductsResult = await _catalogSearchService.SearchAsync(featuredProductsQuery);

                    hasFeaturedProductsCache = featuredProductsResult.TotalHitsCount > 0;
                    await Services.Cache.PutAsync(cacheKey, hasFeaturedProductsCache);
                }

                if (hasFeaturedProductsCache.Value && featuredProductsResult == null)
                {
                    featuredProductsResult = await _catalogSearchService.SearchAsync(featuredProductsQuery);
                }

                if (featuredProductsResult != null)
                {
                    var featuredProductsMappingSettings = _helper.GetBestFitProductSummaryMappingSettings(ProductSummaryViewMode.Grid);
                    model.FeaturedProducts = await _helper.MapProductSummaryModelAsync(featuredProductsResult, featuredProductsMappingSettings);
                }
            }

            // Prepare paging/sorting/mode stuff.
            _helper.MapListActions(model.Products, category, _catalogSettings.DefaultPageSizeOptions);

            // Template.
            var templateCacheKey = string.Format(ModelCacheInvalidator.CATEGORY_TEMPLATE_MODEL_KEY, category.CategoryTemplateId);
            var templateViewPath = await Services.Cache.GetAsync(templateCacheKey, async() =>
            {
                var template = await _db.CategoryTemplates.FindByIdAsync(category.CategoryTemplateId, false)
                               ?? await _db.CategoryTemplates.FirstOrDefaultAsync();

                return(template.ViewPath);
            });

            // Activity log.
            Services.ActivityLogger.LogActivity("PublicStore.ViewCategory", T("ActivityLog.PublicStore.ViewCategory"), category.Name);

            Services.DisplayControl.Announce(category);

            return(View(templateViewPath, model));
        }
Пример #25
0
        /// <returns>A task that represents the asynchronous operation</returns>
        public async Task <IViewComponentResult> InvokeAsync(int?productThumbPictureSize)
        {
            if (!_catalogSettings.ShowBestsellersOnHomepage || _catalogSettings.NumberOfBestsellersOnHomepage == 0)
            {
                return(Content(""));
            }

            //load and cache report
            var report = (await _staticCacheManager.GetAsync(_staticCacheManager.PrepareKeyForDefaultCache(NopModelCacheDefaults.HomepageBestsellersIdsKey, await _storeContext.GetCurrentStoreAsync()),
                                                             async() => await _orderReportService.BestSellersReportAsync(
                                                                 storeId: (await _storeContext.GetCurrentStoreAsync()).Id,
                                                                 pageSize: _catalogSettings.NumberOfBestsellersOnHomepage)))
                         .ToList();

            //load products
            var products = await(await _productService.GetProductsByIdsAsync(report.Select(x => x.ProductId).ToArray()))
                           //ACL and store mapping
                           .WhereAwait(async p => await _aclService.AuthorizeAsync(p) && await _storeMappingService.AuthorizeAsync(p))
                           //availability dates
                           .Where(p => _productService.ProductIsAvailable(p)).ToListAsync();

            if (!products.Any())
            {
                return(Content(""));
            }

            //prepare model
            var model = (await _productModelFactory.PrepareProductOverviewModelsAsync(products, true, true, productThumbPictureSize)).ToList();

            return(View(model));
        }
Пример #26
0
        public async Task <IActionResult> ProductDetails(int productId, ProductVariantQuery query)
        {
            var product = await _db.Products
                          .IncludeMedia()
                          .IncludeManufacturers()
                          .Where(x => x.Id == productId)
                          .FirstOrDefaultAsync();

            if (product == null || product.IsSystemProduct)
            {
                return(NotFound());
            }

            // Is published? Check whether the current user has a "Manage catalog" permission.
            // It allows him to preview a product before publishing.
            if (!product.Published && !await Services.Permissions.AuthorizeAsync(Permissions.Catalog.Product.Read))
            {
                return(NotFound());
            }

            // ACL (access control list).
            if (!await _aclService.AuthorizeAsync(product))
            {
                return(NotFound());
            }

            // Store mapping.
            if (!await _storeMappingService.AuthorizeAsync(product))
            {
                return(NotFound());
            }

            // Is product individually visible?
            if (product.Visibility == ProductVisibility.Hidden)
            {
                // Find parent grouped product.
                var parentGroupedProduct = await _db.Products.FindByIdAsync(product.ParentGroupedProductId, false);

                if (parentGroupedProduct == null)
                {
                    return(NotFound());
                }

                var seName = await parentGroupedProduct.GetActiveSlugAsync();

                if (seName.IsEmpty())
                {
                    return(NotFound());
                }

                var routeValues = new RouteValueDictionary
                {
                    { "SeName", seName }
                };

                // Add query string parameters.
                Request.Query.Each(x => routeValues.Add(x.Key, Request.Query[x.Value].ToString()));

                return(RedirectToRoute("Product", routeValues));
            }

            // Prepare the view model
            var model = await _helper.MapProductDetailsPageModelAsync(product, query);

            // Some cargo data
            model.PictureSize            = _mediaSettings.ProductDetailsPictureSize;
            model.HotlineTelephoneNumber = _contactDataSettings.HotlineTelephoneNumber.NullEmpty();
            if (_seoSettings.CanonicalUrlsEnabled)
            {
                model.CanonicalUrl = _urlHelper.Value.RouteUrl("Product", new { model.SeName }, Request.Scheme);
            }

            // Save as recently viewed
            _recentlyViewedProductsService.AddProductToRecentlyViewedList(product.Id);

            // Activity log
            Services.ActivityLogger.LogActivity("PublicStore.ViewProduct", T("ActivityLog.PublicStore.ViewProduct"), product.Name);

            // Breadcrumb
            if (_catalogSettings.CategoryBreadcrumbEnabled)
            {
                await _helper.GetBreadcrumbAsync(_breadcrumb, ControllerContext, product);

                _breadcrumb.Track(new MenuItem
                {
                    Text     = model.Name,
                    Rtl      = model.Name.CurrentLanguage.Rtl,
                    EntityId = product.Id,
                    Url      = Url.RouteUrl("Product", new { model.SeName })
                });
            }

            return(View(model.ProductTemplateViewPath, model));
        }
        public async Task <IViewComponentResult> InvokeAsync(int?productThumbPictureSize, bool?preparePriceModel)
        {
            if (!_catalogSettings.RecentlyViewedProductsEnabled)
            {
                return(Content(""));
            }

            var preparePictureModel = productThumbPictureSize.HasValue;
            var products            = await(await _recentlyViewedProductsService.GetRecentlyViewedProductsAsync(_catalogSettings.RecentlyViewedProductsNumber))
                                      //ACL and store mapping
                                      .WhereAwait(async p => await _aclService.AuthorizeAsync(p) && await _storeMappingService.AuthorizeAsync(p))
                                      //availability dates
                                      .Where(p => _productService.ProductIsAvailable(p)).ToListAsync();

            if (!products.Any())
            {
                return(Content(""));
            }

            //prepare model
            var model = new List <ProductOverviewModel>();

            model.AddRange(await _productModelFactory.PrepareProductOverviewModelsAsync(products,
                                                                                        preparePriceModel.GetValueOrDefault(),
                                                                                        preparePictureModel,
                                                                                        productThumbPictureSize));

            return(View(model));
        }
Пример #28
0
        public async Task <IViewComponentResult> InvokeAsync(int?productThumbPictureSize)
        {
            var cart = await _shoppingCartService.GetShoppingCartAsync(await _workContext.GetCurrentCustomerAsync(), ShoppingCartType.ShoppingCart, (await _storeContext.GetCurrentStoreAsync()).Id);

            var products = await(await _productService.GetCrossSellProductsByShoppingCartAsync(cart, _shoppingCartSettings.CrossSellsNumber))
                           //ACL and store mapping
                           .WhereAwait(async p => await _aclService.AuthorizeAsync(p) && await _storeMappingService.AuthorizeAsync(p))
                           //availability dates
                           .Where(p => _productService.ProductIsAvailable(p))
                           //visible individually
                           .Where(p => p.VisibleIndividually).ToListAsync();

            if (!products.Any())
            {
                return(Content(""));
            }

            //Cross-sell products are displayed on the shopping cart page.
            //We know that the entire shopping cart page is not refresh
            //even if "ShoppingCartSettings.DisplayCartAfterAddingProduct" setting  is enabled.
            //That's why we force page refresh (redirect) in this case
            var model = (await _productModelFactory.PrepareProductOverviewModelsAsync(products,
                                                                                      productThumbPictureSize: productThumbPictureSize, forceRedirectionAfterAddingToCart: true))
                        .ToList();

            return(View(model));
        }
        /// <returns>A task that represents the asynchronous operation</returns>
        public virtual async Task <IActionResult> ProductDetails(int productId, int updatecartitemid = 0)
        {
            var product = await _productService.GetProductByIdAsync(productId);

            if (product == null || product.Deleted)
            {
                return(InvokeHttp404());
            }

            var notAvailable =
                //published?
                (!product.Published && !_catalogSettings.AllowViewUnpublishedProductPage) ||
                //ACL (access control list)
                !await _aclService.AuthorizeAsync(product) ||
                //Store mapping
                !await _storeMappingService.AuthorizeAsync(product) ||
                //availability dates
                !_productService.ProductIsAvailable(product);

            //Check whether the current user has a "Manage products" permission (usually a store owner)
            //We should allows him (her) to use "Preview" functionality
            var hasAdminAccess = await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) && await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts);

            if (notAvailable && !hasAdminAccess)
            {
                return(InvokeHttp404());
            }

            //visible individually?
            if (!product.VisibleIndividually)
            {
                //is this one an associated products?
                var parentGroupedProduct = await _productService.GetProductByIdAsync(product.ParentGroupedProductId);

                if (parentGroupedProduct == null)
                {
                    return(RedirectToRoute("Homepage"));
                }

                return(RedirectToRoutePermanent("Product", new { SeName = await _urlRecordService.GetSeNameAsync(parentGroupedProduct) }));
            }

            //update existing shopping cart or wishlist  item?
            ShoppingCartItem updatecartitem = null;

            if (_shoppingCartSettings.AllowCartItemEditing && updatecartitemid > 0)
            {
                var cart = await _shoppingCartService.GetShoppingCartAsync(await _workContext.GetCurrentCustomerAsync(), storeId : (await _storeContext.GetCurrentStoreAsync()).Id);

                updatecartitem = cart.FirstOrDefault(x => x.Id == updatecartitemid);
                //not found?
                if (updatecartitem == null)
                {
                    return(RedirectToRoute("Product", new { SeName = await _urlRecordService.GetSeNameAsync(product) }));
                }
                //is it this product?
                if (product.Id != updatecartitem.ProductId)
                {
                    return(RedirectToRoute("Product", new { SeName = await _urlRecordService.GetSeNameAsync(product) }));
                }
            }

            //save as recently viewed
            await _recentlyViewedProductsService.AddProductToRecentlyViewedListAsync(product.Id);

            //display "edit" (manage) link
            if (await _permissionService.AuthorizeAsync(StandardPermissionProvider.AccessAdminPanel) &&
                await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
            {
                //a vendor should have access only to his products
                if (await _workContext.GetCurrentVendorAsync() == null || (await _workContext.GetCurrentVendorAsync()).Id == product.VendorId)
                {
                    DisplayEditLink(Url.Action("Edit", "Product", new { id = product.Id, area = AreaNames.Admin }));
                }
            }

            //activity log
            await _customerActivityService.InsertActivityAsync("PublicStore.ViewProduct",
                                                               string.Format(await _localizationService.GetResourceAsync("ActivityLog.PublicStore.ViewProduct"), product.Name), product);

            //model
            var model = await _productModelFactory.PrepareProductDetailsModelAsync(product, updatecartitem, false);

            //template
            var productTemplateViewPath = await _productModelFactory.PrepareProductTemplateViewPathAsync(product);

            return(View(productTemplateViewPath, model));
        }
Пример #30
0
        public virtual async Task <IList <string> > ValidateProductAsync(AddToCartContext ctx, IEnumerable <OrganizedShoppingCartItem> shoppingCart)
        {
            Guard.NotNull(ctx, nameof(ctx));

            var warnings = new List <string>();
            var product  = ctx.Product;
            var cartType = ctx.CartType;

            if (product.Deleted)
            {
                warnings.Add(T("ShoppingCart.ProductDeleted"));
                ctx.Warnings.AddRange(warnings);
                return(ctx.Warnings);
            }

            // Grouped products are not available for order
            if (product.ProductType == ProductType.GroupedProduct)
            {
                warnings.Add(T("ShoppingCart.ProductNotAvailableForOrder"));
            }

            // Validate product bundle, no customer entered price allowed
            if (product.ProductType == ProductType.BundledProduct &&
                product.BundlePerItemPricing &&
                ctx.CustomerEnteredPrice != decimal.Zero)
            {
                warnings.Add(T("ShoppingCart.Bundle.NoCustomerEnteredPrice"));
            }

            // Not published or no permissions for customer or store
            if (!product.Published ||
                !await _aclService.AuthorizeAsync(product, ctx.Customer) ||
                !await _storeMappingService.AuthorizeAsync(product.Name, product.Id, ctx.StoreId ?? _storeContext.CurrentStore.Id))
            {
                warnings.Add(T("ShoppingCart.ProductUnpublished"));
            }

            // Disabled buy button
            if (cartType == ShoppingCartType.ShoppingCart && product.DisableBuyButton)
            {
                warnings.Add(T("ShoppingCart.BuyingDisabled"));
            }

            // Disabled wishlist button
            if (cartType == ShoppingCartType.Wishlist && product.DisableWishlistButton)
            {
                warnings.Add(T("ShoppingCart.WishlistDisabled"));
            }

            // Call for price
            if (cartType == ShoppingCartType.ShoppingCart && product.CallForPrice)
            {
                warnings.Add(T("Products.CallForPrice"));
            }

            // Customer entered price
            if (product.CustomerEntersPrice &&
                (ctx.CustomerEnteredPrice < product.MinimumCustomerEnteredPrice || ctx.CustomerEnteredPrice > product.MaximumCustomerEnteredPrice))
            {
                var minimum = _currencyService.ConvertFromPrimaryStoreCurrency(product.MinimumCustomerEnteredPrice, _workContext.WorkingCurrency);
                var maximum = _currencyService.ConvertFromPrimaryStoreCurrency(product.MaximumCustomerEnteredPrice, _workContext.WorkingCurrency);

                var moneyMin = _currencyService.CreateMoney(minimum, true, displayTax: false);
                var moneyMax = _currencyService.CreateMoney(maximum, true, displayTax: false);

                warnings.Add(T("ShoppingCart.CustomerEnteredPrice.RangeError", moneyMin.ToString(), moneyMax.ToString()));
            }

            // Quantity validation
            if (ctx.Quantity <= 0)
            {
                warnings.Add(T("ShoppingCart.QuantityShouldPositive"));
            }

            if (ctx.Quantity < product.OrderMinimumQuantity)
            {
                warnings.Add(T("ShoppingCart.MinimumQuantity", product.OrderMinimumQuantity));
            }

            if (ctx.Quantity > product.OrderMaximumQuantity)
            {
                warnings.Add(T("ShoppingCart.MaximumQuantity", product.OrderMaximumQuantity));
            }

            var allowedQuantities = product.ParseAllowedQuantities();

            if (allowedQuantities.Length > 0 && !allowedQuantities.Contains(ctx.Quantity))
            {
                warnings.Add(T("ShoppingCart.AllowedQuantities", string.Join(", ", allowedQuantities)));
            }

            // Stock validation
            var validateOutOfStock = ctx.CartType == ShoppingCartType.ShoppingCart || !_cartSettings.AllowOutOfStockItemsToBeAddedToWishlist;

            if (validateOutOfStock)
            {
                switch (product.ManageInventoryMethod)
                {
                case ManageInventoryMethod.ManageStock:
                {
                    if (product.BackorderMode != BackorderMode.NoBackorders || product.StockQuantity >= ctx.Quantity)
                    {
                        break;
                    }

                    var warning = product.StockQuantity > 0
                                ? T("ShoppingCart.QuantityExceedsStock", product.StockQuantity)
                                : T("ShoppingCart.OutOfStock");

                    warnings.Add(warning);
                }
                break;

                case ManageInventoryMethod.ManageStockByAttributes:
                {
                    var combination = await _productAttributeMaterializer.FindAttributeCombinationAsync(product.Id, ctx.AttributeSelection);

                    if (combination == null || combination.AllowOutOfStockOrders || combination.StockQuantity >= ctx.Quantity)
                    {
                        break;
                    }

                    var warning = combination.StockQuantity > 0
                                ? T("ShoppingCart.QuantityExceedsStock", combination.StockQuantity)
                                : T("ShoppingCart.OutOfStock");

                    warnings.Add(warning);
                }
                break;

                case ManageInventoryMethod.DontManageStock:
                default:
                    break;
                }
            }

            // Validate availability
            var availableStartDateError = false;

            if (ctx.Product.AvailableStartDateTimeUtc.HasValue)
            {
                var availableStartDate = DateTime.SpecifyKind(ctx.Product.AvailableStartDateTimeUtc.Value, DateTimeKind.Utc);
                if (availableStartDate.CompareTo(DateTime.UtcNow) > 0)
                {
                    warnings.Add(T("ShoppingCart.NotAvailable"));
                    availableStartDateError = true;
                }
            }

            if (ctx.Product.AvailableEndDateTimeUtc.HasValue && !availableStartDateError)
            {
                var availableEndDate = DateTime.SpecifyKind(ctx.Product.AvailableEndDateTimeUtc.Value, DateTimeKind.Utc);
                if (availableEndDate.CompareTo(DateTime.UtcNow) < 0)
                {
                    warnings.Add(T("ShoppingCart.NotAvailable"));
                }
            }

            ctx.Warnings.AddRange(warnings);
            return(warnings);
        }