using Microsoft.AspNetCore.Mvc; using Nop.Core.Domain.Blogs; using Nop.Core.Events; using Nop.Services.Blogs; using Nop.Services.Localization; using Nop.Services.Logging; using Nop.Services.Messages; using Nop.Services.Security; using Nop.Services.Seo; using Nop.Services.Stores; using Nop.Web.Areas.Admin.Factories; using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions; using Nop.Web.Areas.Admin.Models.Blogs; using Nop.Web.Framework.Mvc; using Nop.Web.Framework.Mvc.Filters; namespace Nop.Web.Areas.Admin.Controllers; public partial class BlogController : BaseAdminController { #region Fields protected readonly IBlogModelFactory _blogModelFactory; protected readonly IBlogService _blogService; protected readonly ICustomerActivityService _customerActivityService; protected readonly IEventPublisher _eventPublisher; protected readonly ILocalizationService _localizationService; protected readonly INotificationService _notificationService; protected readonly IPermissionService _permissionService; protected readonly IStoreMappingService _storeMappingService; protected readonly IStoreService _storeService; protected readonly IUrlRecordService _urlRecordService; #endregion #region Ctor public BlogController(IBlogModelFactory blogModelFactory, IBlogService blogService, ICustomerActivityService customerActivityService, IEventPublisher eventPublisher, ILocalizationService localizationService, INotificationService notificationService, IPermissionService permissionService, IStoreMappingService storeMappingService, IStoreService storeService, IUrlRecordService urlRecordService) { _blogModelFactory = blogModelFactory; _blogService = blogService; _customerActivityService = customerActivityService; _eventPublisher = eventPublisher; _localizationService = localizationService; _notificationService = notificationService; _permissionService = permissionService; _storeMappingService = storeMappingService; _storeService = storeService; _urlRecordService = urlRecordService; } #endregion #region Utilities protected virtual async Task SaveStoreMappingsAsync(BlogPost blogPost, BlogPostModel model) { blogPost.LimitedToStores = model.SelectedStoreIds.Any(); await _blogService.UpdateBlogPostAsync(blogPost); var existingStoreMappings = await _storeMappingService.GetStoreMappingsAsync(blogPost); var allStores = await _storeService.GetAllStoresAsync(); foreach (var store in allStores) { if (model.SelectedStoreIds.Contains(store.Id)) { //new store if (!existingStoreMappings.Any(sm => sm.StoreId == store.Id)) await _storeMappingService.InsertStoreMappingAsync(blogPost, store.Id); } else { //remove store var storeMappingToDelete = existingStoreMappings.FirstOrDefault(sm => sm.StoreId == store.Id); if (storeMappingToDelete != null) await _storeMappingService.DeleteStoreMappingAsync(storeMappingToDelete); } } } #endregion #region Methods #region Blog posts public virtual IActionResult Index() { return RedirectToAction("BlogPosts"); } [CheckPermission(StandardPermission.ContentManagement.BLOG_VIEW)] public virtual async Task BlogPosts(int? filterByBlogPostId) { //prepare model var model = await _blogModelFactory.PrepareBlogContentModelAsync(new BlogContentModel(), filterByBlogPostId); return View(model); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_VIEW)] public virtual async Task List(BlogPostSearchModel searchModel) { //prepare model var model = await _blogModelFactory.PrepareBlogPostListModelAsync(searchModel); return Json(model); } [CheckPermission(StandardPermission.ContentManagement.BLOG_CREATE_EDIT_DELETE)] public virtual async Task BlogPostCreate() { //prepare model var model = await _blogModelFactory.PrepareBlogPostModelAsync(new BlogPostModel(), null); return View(model); } [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] [CheckPermission(StandardPermission.ContentManagement.BLOG_CREATE_EDIT_DELETE)] public virtual async Task BlogPostCreate(BlogPostModel model, bool continueEditing) { if (ModelState.IsValid) { var blogPost = model.ToEntity(); blogPost.CreatedOnUtc = DateTime.UtcNow; await _blogService.InsertBlogPostAsync(blogPost); //activity log await _customerActivityService.InsertActivityAsync("AddNewBlogPost", string.Format(await _localizationService.GetResourceAsync("ActivityLog.AddNewBlogPost"), blogPost.Id), blogPost); //search engine name var seName = await _urlRecordService.ValidateSeNameAsync(blogPost, model.SeName, model.Title, true); await _urlRecordService.SaveSlugAsync(blogPost, seName, blogPost.LanguageId); //Stores await SaveStoreMappingsAsync(blogPost, model); _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.ContentManagement.Blog.BlogPosts.Added")); if (!continueEditing) return RedirectToAction("BlogPosts"); return RedirectToAction("BlogPostEdit", new { id = blogPost.Id }); } //prepare model model = await _blogModelFactory.PrepareBlogPostModelAsync(model, null, true); //if we got this far, something failed, redisplay form return View(model); } [CheckPermission(StandardPermission.ContentManagement.BLOG_VIEW)] public virtual async Task BlogPostEdit(int id) { //try to get a blog post with the specified id var blogPost = await _blogService.GetBlogPostByIdAsync(id); if (blogPost == null) return RedirectToAction("BlogPosts"); //prepare model var model = await _blogModelFactory.PrepareBlogPostModelAsync(null, blogPost); return View(model); } [HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")] [CheckPermission(StandardPermission.ContentManagement.BLOG_CREATE_EDIT_DELETE)] public virtual async Task BlogPostEdit(BlogPostModel model, bool continueEditing) { //try to get a blog post with the specified id var blogPost = await _blogService.GetBlogPostByIdAsync(model.Id); if (blogPost == null) return RedirectToAction("BlogPosts"); if (ModelState.IsValid) { blogPost = model.ToEntity(blogPost); await _blogService.UpdateBlogPostAsync(blogPost); //activity log await _customerActivityService.InsertActivityAsync("EditBlogPost", string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditBlogPost"), blogPost.Id), blogPost); //search engine name var seName = await _urlRecordService.ValidateSeNameAsync(blogPost, model.SeName, model.Title, true); await _urlRecordService.SaveSlugAsync(blogPost, seName, blogPost.LanguageId); //Stores await SaveStoreMappingsAsync(blogPost, model); _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.ContentManagement.Blog.BlogPosts.Updated")); if (!continueEditing) return RedirectToAction("BlogPosts"); return RedirectToAction("BlogPostEdit", new { id = blogPost.Id }); } //prepare model model = await _blogModelFactory.PrepareBlogPostModelAsync(model, blogPost, true); //if we got this far, something failed, redisplay form return View(model); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_CREATE_EDIT_DELETE)] public virtual async Task Delete(int id) { //try to get a blog post with the specified id var blogPost = await _blogService.GetBlogPostByIdAsync(id); if (blogPost == null) return RedirectToAction("BlogPosts"); await _blogService.DeleteBlogPostAsync(blogPost); //activity log await _customerActivityService.InsertActivityAsync("DeleteBlogPost", string.Format(await _localizationService.GetResourceAsync("ActivityLog.DeleteBlogPost"), blogPost.Id), blogPost); _notificationService.SuccessNotification(await _localizationService.GetResourceAsync("Admin.ContentManagement.Blog.BlogPosts.Deleted")); return RedirectToAction("BlogPosts"); } #endregion #region Comments [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_VIEW)] public virtual async Task BlogComments(int? filterByBlogPostId) { //try to get a blog post with the specified id var blogPost = await _blogService.GetBlogPostByIdAsync(filterByBlogPostId ?? 0); if (blogPost == null && filterByBlogPostId.HasValue) return RedirectToAction("BlogComments"); //prepare model var model = await _blogModelFactory.PrepareBlogCommentSearchModelAsync(new BlogCommentSearchModel(), blogPost); return View(model); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_VIEW)] public virtual async Task Comments(BlogCommentSearchModel searchModel) { //prepare model var model = await _blogModelFactory.PrepareBlogCommentListModelAsync(searchModel, searchModel.BlogPostId); return Json(model); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_CREATE_EDIT_DELETE)] public virtual async Task CommentUpdate(BlogCommentModel model) { //try to get a blog comment with the specified id var comment = await _blogService.GetBlogCommentByIdAsync(model.Id) ?? throw new ArgumentException("No comment found with the specified id"); var previousIsApproved = comment.IsApproved; //fill entity from model comment = model.ToEntity(comment); await _blogService.UpdateBlogCommentAsync(comment); //raise event (only if it wasn't approved before and is approved now) if (!previousIsApproved && comment.IsApproved) await _eventPublisher.PublishAsync(new BlogCommentApprovedEvent(comment)); //activity log await _customerActivityService.InsertActivityAsync("EditBlogComment", string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditBlogComment"), comment.Id), comment); return new NullJsonResult(); } [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_CREATE_EDIT_DELETE)] public virtual async Task CommentDelete(int id) { //try to get a blog comment with the specified id var comment = await _blogService.GetBlogCommentByIdAsync(id) ?? throw new ArgumentException("No comment found with the specified id", nameof(id)); await _blogService.DeleteBlogCommentAsync(comment); //activity log await _customerActivityService.InsertActivityAsync("DeleteBlogPostComment", string.Format(await _localizationService.GetResourceAsync("ActivityLog.DeleteBlogPostComment"), comment.Id), comment); return new NullJsonResult(); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_CREATE_EDIT_DELETE)] public virtual async Task DeleteSelectedComments(ICollection selectedIds) { if (selectedIds == null || !selectedIds.Any()) return NoContent(); var comments = await _blogService.GetBlogCommentsByIdsAsync(selectedIds.ToArray()); await _blogService.DeleteBlogCommentsAsync(comments); //activity log foreach (var blogComment in comments) { await _customerActivityService.InsertActivityAsync("DeleteBlogPostComment", string.Format(await _localizationService.GetResourceAsync("ActivityLog.DeleteBlogPostComment"), blogComment.Id), blogComment); } return Json(new { Result = true }); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_CREATE_EDIT_DELETE)] public virtual async Task ApproveSelected(ICollection selectedIds) { if (selectedIds == null || !selectedIds.Any()) return NoContent(); //filter not approved comments var blogComments = (await _blogService.GetBlogCommentsByIdsAsync(selectedIds.ToArray())).Where(comment => !comment.IsApproved); foreach (var blogComment in blogComments) { blogComment.IsApproved = true; await _blogService.UpdateBlogCommentAsync(blogComment); //raise event await _eventPublisher.PublishAsync(new BlogCommentApprovedEvent(blogComment)); //activity log await _customerActivityService.InsertActivityAsync("EditBlogComment", string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditBlogComment"), blogComment.Id), blogComment); } return Json(new { Result = true }); } [HttpPost] [CheckPermission(StandardPermission.ContentManagement.BLOG_COMMENTS_CREATE_EDIT_DELETE)] public virtual async Task DisapproveSelected(ICollection selectedIds) { if (selectedIds == null || !selectedIds.Any()) return NoContent(); //filter approved comments var blogComments = (await _blogService.GetBlogCommentsByIdsAsync(selectedIds.ToArray())).Where(comment => comment.IsApproved); foreach (var blogComment in blogComments) { blogComment.IsApproved = false; await _blogService.UpdateBlogCommentAsync(blogComment); //activity log await _customerActivityService.InsertActivityAsync("EditBlogComment", string.Format(await _localizationService.GetResourceAsync("ActivityLog.EditBlogComment"), blogComment.Id), blogComment); } return Json(new { Result = true }); } #endregion #endregion }