using System.Text; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Mvc.Rendering; using Nop.Core.Domain.Blogs; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Customers; using Nop.Services.Blogs; using Nop.Services.Customers; using Nop.Services.Helpers; using Nop.Services.Html; using Nop.Services.Localization; using Nop.Services.Seo; using Nop.Services.Stores; using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions; using Nop.Web.Areas.Admin.Models.Blogs; using Nop.Web.Framework.Extensions; using Nop.Web.Framework.Factories; using Nop.Web.Framework.Models.Extensions; namespace Nop.Web.Areas.Admin.Factories; /// /// Represents the blog model factory implementation /// public partial class BlogModelFactory : IBlogModelFactory { #region Fields protected readonly CatalogSettings _catalogSettings; protected readonly IBaseAdminModelFactory _baseAdminModelFactory; protected readonly IBlogService _blogService; protected readonly ICustomerService _customerService; protected readonly IDateTimeHelper _dateTimeHelper; protected readonly IHtmlFormatter _htmlFormatter; protected readonly ILanguageService _languageService; protected readonly ILocalizationService _localizationService; protected readonly IStoreMappingSupportedModelFactory _storeMappingSupportedModelFactory; protected readonly IStoreService _storeService; protected readonly IUrlRecordService _urlRecordService; #endregion #region Ctor public BlogModelFactory(CatalogSettings catalogSettings, IBaseAdminModelFactory baseAdminModelFactory, IBlogService blogService, ICustomerService customerService, IDateTimeHelper dateTimeHelper, IHtmlFormatter htmlFormatter, ILanguageService languageService, ILocalizationService localizationService, IStoreMappingSupportedModelFactory storeMappingSupportedModelFactory, IStoreService storeService, IUrlRecordService urlRecordService) { _catalogSettings = catalogSettings; _baseAdminModelFactory = baseAdminModelFactory; _blogService = blogService; _customerService = customerService; _dateTimeHelper = dateTimeHelper; _htmlFormatter = htmlFormatter; _languageService = languageService; _localizationService = localizationService; _storeMappingSupportedModelFactory = storeMappingSupportedModelFactory; _storeService = storeService; _urlRecordService = urlRecordService; } #endregion #region Methods /// /// Prepare blog content model /// /// Blog content model /// Blog post ID /// /// A task that represents the asynchronous operation /// The task result contains the blog content model /// public virtual async Task PrepareBlogContentModelAsync(BlogContentModel blogContentModel, int? filterByBlogPostId) { ArgumentNullException.ThrowIfNull(blogContentModel); //prepare nested search models await PrepareBlogPostSearchModelAsync(blogContentModel.BlogPosts); var blogPost = await _blogService.GetBlogPostByIdAsync(filterByBlogPostId ?? 0); await PrepareBlogCommentSearchModelAsync(blogContentModel.BlogComments, blogPost); return blogContentModel; } /// /// Prepare paged blog post list model /// /// Blog post search model /// /// A task that represents the asynchronous operation /// The task result contains the blog post list model /// public virtual async Task PrepareBlogPostListModelAsync(BlogPostSearchModel searchModel) { ArgumentNullException.ThrowIfNull(searchModel); //get blog posts var blogPosts = await _blogService.GetAllBlogPostsAsync(storeId: searchModel.SearchStoreId, showHidden: true, pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize, title: searchModel.SearchTitle); //prepare list model var model = await new BlogPostListModel().PrepareToGridAsync(searchModel, blogPosts, () => { return blogPosts.SelectAwait(async blogPost => { //fill in model values from the entity var blogPostModel = blogPost.ToModel(); //little performance optimization: ensure that "Body" is not returned blogPostModel.Body = string.Empty; //convert dates to the user time if (blogPost.StartDateUtc.HasValue) blogPostModel.StartDateUtc = await _dateTimeHelper.ConvertToUserTimeAsync(blogPost.StartDateUtc.Value, DateTimeKind.Utc); if (blogPost.EndDateUtc.HasValue) blogPostModel.EndDateUtc = await _dateTimeHelper.ConvertToUserTimeAsync(blogPost.EndDateUtc.Value, DateTimeKind.Utc); blogPostModel.CreatedOn = await _dateTimeHelper.ConvertToUserTimeAsync(blogPost.CreatedOnUtc, DateTimeKind.Utc); //fill in additional values (not existing in the entity) blogPostModel.LanguageName = (await _languageService.GetLanguageByIdAsync(blogPost.LanguageId))?.Name; blogPostModel.ApprovedComments = await _blogService.GetBlogCommentsCountAsync(blogPost, isApproved: true); blogPostModel.NotApprovedComments = await _blogService.GetBlogCommentsCountAsync(blogPost, isApproved: false); blogPostModel.SeName = await _urlRecordService.GetSeNameAsync(blogPost, blogPost.LanguageId, true, false); return blogPostModel; }); }); return model; } /// /// Prepare blog post model /// /// Blog post model /// Blog post /// Whether to exclude populating of some properties of model /// /// A task that represents the asynchronous operation /// The task result contains the blog post model /// public virtual async Task PrepareBlogPostModelAsync(BlogPostModel model, BlogPost blogPost, bool excludeProperties = false) { //fill in model values from the entity if (blogPost != null) { if (model == null) { model = blogPost.ToModel(); model.SeName = await _urlRecordService.GetSeNameAsync(blogPost, blogPost.LanguageId, true, false); } model.StartDateUtc = blogPost.StartDateUtc; model.EndDateUtc = blogPost.EndDateUtc; } //set default values for the new model if (blogPost == null) { model.AllowComments = true; model.IncludeInSitemap = true; } var blogTags = await _blogService.GetAllBlogPostTagsAsync(0, 0, true); var blogTagsSb = new StringBuilder(); blogTagsSb.Append("var initialBlogTags = ["); for (var i = 0; i < blogTags.Count; i++) { var tag = blogTags[i]; blogTagsSb.Append('\''); blogTagsSb.Append(JavaScriptEncoder.Default.Encode(tag.Name)); blogTagsSb.Append('\''); if (i != blogTags.Count - 1) blogTagsSb.Append(','); } blogTagsSb.Append(']'); model.InitialBlogTags = blogTagsSb.ToString(); //prepare available languages await _baseAdminModelFactory.PrepareLanguagesAsync(model.AvailableLanguages, false); //prepare available stores await _storeMappingSupportedModelFactory.PrepareModelStoresAsync(model, blogPost, excludeProperties); return model; } /// /// Prepare blog comment search model /// /// Blog comment search model /// Blog post /// /// A task that represents the asynchronous operation /// The task result contains the blog comment search model /// public virtual async Task PrepareBlogCommentSearchModelAsync(BlogCommentSearchModel searchModel, BlogPost blogPost) { ArgumentNullException.ThrowIfNull(searchModel); //prepare "approved" property (0 - all; 1 - approved only; 2 - disapproved only) searchModel.AvailableApprovedOptions.Add(new SelectListItem { Text = await _localizationService.GetResourceAsync("Admin.ContentManagement.Blog.Comments.List.SearchApproved.All"), Value = "0" }); searchModel.AvailableApprovedOptions.Add(new SelectListItem { Text = await _localizationService.GetResourceAsync("Admin.ContentManagement.Blog.Comments.List.SearchApproved.ApprovedOnly"), Value = "1" }); searchModel.AvailableApprovedOptions.Add(new SelectListItem { Text = await _localizationService.GetResourceAsync("Admin.ContentManagement.Blog.Comments.List.SearchApproved.DisapprovedOnly"), Value = "2" }); searchModel.BlogPostId = blogPost?.Id; //prepare page parameters searchModel.SetGridPageSize(); return searchModel; } /// /// Prepare paged blog comment list model /// /// Blog comment search model /// Blog post ID /// /// A task that represents the asynchronous operation /// The task result contains the blog comment list model /// public virtual async Task PrepareBlogCommentListModelAsync(BlogCommentSearchModel searchModel, int? blogPostId) { ArgumentNullException.ThrowIfNull(searchModel); //get parameters to filter comments var createdOnFromValue = searchModel.CreatedOnFrom == null ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.CreatedOnFrom.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()); var createdOnToValue = searchModel.CreatedOnTo == null ? null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(searchModel.CreatedOnTo.Value, await _dateTimeHelper.GetCurrentTimeZoneAsync()).AddDays(1); var isApprovedOnly = searchModel.SearchApprovedId == 0 ? null : searchModel.SearchApprovedId == 1 ? true : (bool?)false; //get comments var comments = (await _blogService.GetAllCommentsAsync(blogPostId: blogPostId, approved: isApprovedOnly, fromUtc: createdOnFromValue, toUtc: createdOnToValue, commentText: searchModel.SearchText)).ToPagedList(searchModel); //prepare store names (to avoid loading for each comment) var storeNames = (await _storeService.GetAllStoresAsync()) .ToDictionary(store => store.Id, store => store.Name); //prepare list model var model = await new BlogCommentListModel().PrepareToGridAsync(searchModel, comments, () => { return comments.SelectAwait(async blogComment => { //fill in model values from the entity var commentModel = blogComment.ToModel(); //set title from linked blog post commentModel.BlogPostTitle = (await _blogService.GetBlogPostByIdAsync(blogComment.BlogPostId))?.Title; if ((await _customerService.GetCustomerByIdAsync(blogComment.CustomerId)) is Customer customer) { commentModel.CustomerInfo = (await _customerService.IsRegisteredAsync(customer)) ? customer.Email : await _localizationService.GetResourceAsync("Admin.Customers.Guest"); } //fill in additional values (not existing in the entity) commentModel.CreatedOn = await _dateTimeHelper.ConvertToUserTimeAsync(blogComment.CreatedOnUtc, DateTimeKind.Utc); commentModel.Comment = _htmlFormatter.FormatText(blogComment.CommentText, false, true, false, false, false, false); commentModel.StoreName = storeNames.TryGetValue(blogComment.StoreId, out var value) ? value : "Deleted"; return commentModel; }); }); return model; } /// /// Prepare blog post search model /// /// Blog post search model /// /// A task that represents the asynchronous operation /// The task result contains the blog post search model /// public virtual async Task PrepareBlogPostSearchModelAsync(BlogPostSearchModel searchModel) { ArgumentNullException.ThrowIfNull(searchModel); //prepare available stores await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores); searchModel.HideStoresList = _catalogSettings.IgnoreStoreLimitations || searchModel.AvailableStores.SelectionIsNotPossible(); //prepare page parameters searchModel.SetGridPageSize(); return searchModel; } #endregion }