From c04f7a013efa28af0190d2d3cf1870af53c27e3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:24:31 +0000 Subject: [PATCH 01/15] Initial plan From c01d573dad710e1ea3fe82bbf7bf6c41a42757b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:29:47 +0000 Subject: [PATCH 02/15] Initial analysis of news management structure Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 41c9ad2ed..e9f309cde 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100", + "version": "8.0.119", "rollForward": "latestFeature", "allowPrerelease": false } From 9d386420b588918236322ae709aba542a27ccbc9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:34:58 +0000 Subject: [PATCH 03/15] Add store news limit functionality and Store news controller Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- .../Services/NewsService.cs | 64 +++++++++++ .../Interfaces/Cms/INewsService.cs | 12 ++ src/Core/Grand.Domain/News/NewsSettings.cs | 5 + .../Partials/Content.TabNewsSettings.cshtml | 9 ++ .../Models/News/NewsItemListModel.cs | 3 + .../Models/Settings/ContentSettingsModel.cs | 3 + .../Services/NewsViewModelService.cs | 2 +- .../Areas/Store/Views/News/List.cshtml | 95 ++++++++++++++++ .../Areas/Store/Views/News/Preview.cshtml | 89 +++++++++++++++ .../Controllers/NewsController.cs | 107 ++++++++++++++++++ 10 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml create mode 100644 src/Web/Grand.Web.Store/Controllers/NewsController.cs diff --git a/src/Business/Grand.Business.Cms/Services/NewsService.cs b/src/Business/Grand.Business.Cms/Services/NewsService.cs index 567b7a9d1..31fedc699 100644 --- a/src/Business/Grand.Business.Cms/Services/NewsService.cs +++ b/src/Business/Grand.Business.Cms/Services/NewsService.cs @@ -100,6 +100,70 @@ public virtual async Task> GetAllNews(string storeId = "", return await PagedList.Create(query, pageIndex, pageSize); } + /// + /// Gets news for store with configurable limit + /// + /// Store identifier + /// Page index + /// Page size + /// Maximum number of news items to return (0 for unlimited) + /// News title filter + /// News items + public virtual async Task> GetStoreNews(string storeId = "", + int pageIndex = 0, int pageSize = int.MaxValue, int storeNewsLimit = 0, string newsTitle = "") + { + var query = from p in _newsItemRepository.Table + select p; + + if (!string.IsNullOrWhiteSpace(newsTitle)) + query = query.Where(n => n.Title != null && n.Title.ToLower().Contains(newsTitle.ToLower())); + + // Store news should only show published and current items + var utcNow = DateTime.UtcNow; + query = query.Where(n => n.Published); + query = query.Where(n => !n.StartDateUtc.HasValue || n.StartDateUtc <= utcNow); + query = query.Where(n => !n.EndDateUtc.HasValue || n.EndDateUtc >= utcNow); + + // Apply ACL and store limitations for store context + if (!_accessControlConfig.IgnoreAcl) + { + var allowedCustomerGroupsIds = _contextAccessor.WorkContext.CurrentCustomer.GetCustomerGroupIds(); + query = from p in query + where !p.LimitedToGroups || allowedCustomerGroupsIds.Any(x => p.CustomerGroups.Contains(x)) + select p; + } + + // Store acl + if (!string.IsNullOrEmpty(storeId) && !_accessControlConfig.IgnoreStoreLimitations) + query = from p in query + where !p.LimitedToStores || p.Stores.Contains(storeId) + select p; + + query = query.OrderByDescending(n => n.CreatedOnUtc); + + // Apply store news limit if specified + if (storeNewsLimit > 0) + { + // Take only the limited number of items before pagination + query = query.Take(storeNewsLimit); + + // Adjust page size if it would exceed the limit + var remainingItems = storeNewsLimit - (pageIndex * pageSize); + if (remainingItems <= 0) + { + // No items left for this page + return new PagedList(new List(), pageIndex, pageSize, 0); + } + + if (pageSize > remainingItems) + { + pageSize = remainingItems; + } + } + + return await PagedList.Create(query, pageIndex, pageSize); + } + /// /// Inserts a news item /// diff --git a/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs b/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs index a74736595..2dc8a0894 100644 --- a/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs +++ b/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs @@ -53,4 +53,16 @@ Task> GetAllNews(string storeId = "", /// Customer identifier; "" to load all records /// Comments Task> GetAllComments(string customerId); + + /// + /// Gets news for store with configurable limit + /// + /// Store identifier + /// Page index + /// Page size + /// Maximum number of news items to return (0 for unlimited) + /// News title filter + /// News items + Task> GetStoreNews(string storeId = "", + int pageIndex = 0, int pageSize = int.MaxValue, int storeNewsLimit = 0, string newsTitle = ""); } \ No newline at end of file diff --git a/src/Core/Grand.Domain/News/NewsSettings.cs b/src/Core/Grand.Domain/News/NewsSettings.cs index 9c75ab564..f8b26866b 100644 --- a/src/Core/Grand.Domain/News/NewsSettings.cs +++ b/src/Core/Grand.Domain/News/NewsSettings.cs @@ -33,4 +33,9 @@ public class NewsSettings : ISettings /// Gets or sets the page size for news archive /// public int NewsArchivePageSize { get; set; } + + /// + /// Gets or sets the maximum number of news items to display in store (0 for unlimited) + /// + public int StoreNewsLimit { get; set; } } \ No newline at end of file diff --git a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml index 580e0d861..441d78404 100644 --- a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml +++ b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml @@ -68,5 +68,14 @@ +
+
+ +
+
+ + +
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.AdminShared/Models/News/NewsItemListModel.cs b/src/Web/Grand.Web.AdminShared/Models/News/NewsItemListModel.cs index 14e25b1c6..97f8f8856 100644 --- a/src/Web/Grand.Web.AdminShared/Models/News/NewsItemListModel.cs +++ b/src/Web/Grand.Web.AdminShared/Models/News/NewsItemListModel.cs @@ -9,5 +9,8 @@ public class NewsItemListModel : BaseModel [GrandResourceDisplayName("Admin.Content.News.NewsItems.List.SearchStore")] public string SearchStoreId { get; set; } + [GrandResourceDisplayName("Admin.Content.News.NewsItems.List.SearchTitle")] + public string SearchNewsTitle { get; set; } + public IList AvailableStores { get; set; } = new List(); } \ No newline at end of file diff --git a/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs b/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs index c3a0f18af..f26774a9a 100644 --- a/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs +++ b/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs @@ -59,6 +59,9 @@ public class NewsSettingsModel : BaseModel [GrandResourceDisplayName("Admin.Settings.News.NewsArchivePageSize")] public int NewsArchivePageSize { get; set; } + + [GrandResourceDisplayName("Admin.Settings.News.StoreNewsLimit")] + public int StoreNewsLimit { get; set; } } public class KnowledgebaseSettingsModel : BaseModel diff --git a/src/Web/Grand.Web.AdminShared/Services/NewsViewModelService.cs b/src/Web/Grand.Web.AdminShared/Services/NewsViewModelService.cs index a58b1d3df..e4c6eede6 100644 --- a/src/Web/Grand.Web.AdminShared/Services/NewsViewModelService.cs +++ b/src/Web/Grand.Web.AdminShared/Services/NewsViewModelService.cs @@ -49,7 +49,7 @@ public NewsViewModelService(INewsService newsService, public virtual async Task<(IEnumerable newsItemModels, int totalCount)> PrepareNewsItemModel( NewsItemListModel model, int pageIndex, int pageSize) { - var news = await _newsService.GetAllNews(model.SearchStoreId, pageIndex - 1, pageSize, true, true); + var news = await _newsService.GetAllNews(model.SearchStoreId, pageIndex - 1, pageSize, true, true, model.SearchNewsTitle); return (news.Select(x => { var m = x.ToModel(_dateTimeService); diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml new file mode 100644 index 000000000..bfc844612 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml @@ -0,0 +1,95 @@ +@model NewsItemListModel +@{ + ViewBag.Title = T("Admin.Content.News.NewsItems"); + Layout = Constants.LayoutStore; +} + +
+
+
+
+

+ + @T("Admin.Content.News.NewsItems") +

+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml new file mode 100644 index 000000000..7e8fa20d2 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml @@ -0,0 +1,89 @@ +@model NewsItemModel +@{ + ViewBag.Title = Model.Title; + Layout = Constants.LayoutStore; +} + +
+
+
+
+

+ + @T("Admin.Content.News.NewsItems.Preview") +

+ +
+
+
+
+
+
+ @T("Admin.Content.News.NewsItems.Fields.Title"): +
+
+ @Model.Title +
+
+ +
+
+ @T("Admin.Content.News.NewsItems.Fields.Published"): +
+
+ @(Model.Published ? T("Admin.Common.Yes") : T("Admin.Common.No")) +
+
+ +
+
+ @T("Admin.Content.News.NewsItems.Fields.CreatedOn"): +
+
+ @Model.CreatedOn.ToString("G") +
+
+ + @if (!string.IsNullOrEmpty(Model.Short)) + { +
+
+ @T("Admin.Content.News.NewsItems.Fields.Short"): +
+
+ @Html.Raw(Model.Short) +
+
+ } + + @if (!string.IsNullOrEmpty(Model.Full)) + { +
+
+ @T("Admin.Content.News.NewsItems.Fields.Full"): +
+
+ @Html.Raw(Model.Full) +
+
+ } + +
+
+ @T("Admin.Content.News.NewsItems.Fields.Comments"): +
+
+ @Model.Comments +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs new file mode 100644 index 000000000..8df7f635d --- /dev/null +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -0,0 +1,107 @@ +using Grand.Business.Core.Interfaces.Cms; +using Grand.Business.Core.Interfaces.Common.Configuration; +using Grand.Business.Core.Interfaces.Common.Directory; +using Grand.Business.Core.Interfaces.Common.Localization; +using Grand.Domain.News; +using Grand.Domain.Permissions; +using Grand.Infrastructure; +using Grand.Web.AdminShared.Extensions; +using Grand.Web.AdminShared.Extensions.Mapping; +using Grand.Web.AdminShared.Interfaces; +using Grand.Web.AdminShared.Models.News; +using Grand.Web.Common.DataSource; +using Grand.Web.Common.Filters; +using Grand.Web.Common.Security.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Grand.Web.Store.Controllers; + +[PermissionAuthorize(PermissionSystemName.News)] +public class NewsController : BaseStoreController +{ + #region Constructors + + public NewsController( + INewsViewModelService newsViewModelService, + INewsService newsService, + ILanguageService languageService, + ITranslationService translationService, + ISettingService settingService, + IDateTimeService dateTimeService, + IContextAccessor contextAccessor) + { + _newsViewModelService = newsViewModelService; + _newsService = newsService; + _languageService = languageService; + _translationService = translationService; + _settingService = settingService; + _dateTimeService = dateTimeService; + _contextAccessor = contextAccessor; + } + + #endregion + + #region Fields + + private readonly INewsViewModelService _newsViewModelService; + private readonly INewsService _newsService; + private readonly ILanguageService _languageService; + private readonly ITranslationService _translationService; + private readonly ISettingService _settingService; + private readonly IDateTimeService _dateTimeService; + private readonly IContextAccessor _contextAccessor; + + #endregion + + #region News items + + public IActionResult Index() + { + return RedirectToAction("List"); + } + + public async Task List() + { + var model = new NewsItemListModel(); + return View(model); + } + + [PermissionAuthorizeAction(PermissionActionName.List)] + [HttpPost] + public async Task List(DataSourceRequest command, NewsItemListModel model) + { + var newsSettings = await _settingService.LoadSettingAsync(_contextAccessor.StoreContext.CurrentStore.Id); + var storeId = _contextAccessor.StoreContext.CurrentStore.Id; + + // Use the store-specific news service method with limit + var news = await _newsService.GetStoreNews(storeId, command.Page - 1, command.PageSize, + newsSettings.StoreNewsLimit, model.SearchNewsTitle); + + var gridModel = new DataSourceResult + { + Data = news.Select(x => + { + var m = x.ToModel(_dateTimeService); + m.Full = ""; + m.CreatedOn = _dateTimeService.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc); + m.Comments = x.CommentCount; + return m; + }).ToList(), + Total = news.TotalCount + }; + return Json(gridModel); + } + + [PermissionAuthorizeAction(PermissionActionName.Preview)] + public async Task Preview(string id) + { + var newsItem = await _newsService.GetNewsById(id); + if (newsItem == null) + return RedirectToAction("List"); + + var model = newsItem.ToModel(_dateTimeService); + return View(model); + } + + #endregion +} \ No newline at end of file From 9dfe3bcdc31c28e0617039298226ef69984d323f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:38:18 +0000 Subject: [PATCH 04/15] Add comprehensive tests and fix pagination logic for store news limits Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- .../Services/NewsService.cs | 10 +-- .../Services/NewsServiceTests.cs | 70 +++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/Business/Grand.Business.Cms/Services/NewsService.cs b/src/Business/Grand.Business.Cms/Services/NewsService.cs index 31fedc699..fed6262c3 100644 --- a/src/Business/Grand.Business.Cms/Services/NewsService.cs +++ b/src/Business/Grand.Business.Cms/Services/NewsService.cs @@ -144,10 +144,7 @@ public virtual async Task> GetStoreNews(string storeId = "" // Apply store news limit if specified if (storeNewsLimit > 0) { - // Take only the limited number of items before pagination - query = query.Take(storeNewsLimit); - - // Adjust page size if it would exceed the limit + // First check if the requested page would exceed our limit var remainingItems = storeNewsLimit - (pageIndex * pageSize); if (remainingItems <= 0) { @@ -155,10 +152,15 @@ public virtual async Task> GetStoreNews(string storeId = "" return new PagedList(new List(), pageIndex, pageSize, 0); } + // Adjust page size if it would exceed the limit on this page if (pageSize > remainingItems) { pageSize = remainingItems; } + + // Limit the total query to the store limit and let PagedList handle pagination + var limitedQuery = query.Take(storeNewsLimit); + return await PagedList.Create(limitedQuery, pageIndex, pageSize); } return await PagedList.Create(query, pageIndex, pageSize); diff --git a/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs b/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs index fc3cf2889..5b0a6caaf 100644 --- a/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs +++ b/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs @@ -108,4 +108,74 @@ public async Task GetAllCommentsTest() //Assert Assert.IsTrue(result.Any()); } + + [TestMethod] + public async Task GetStoreNews_NoLimit_ReturnsAllPublishedNews() + { + //Arrange + await _repository.InsertAsync(new NewsItem { Published = true, Title = "News 1" }); + await _repository.InsertAsync(new NewsItem { Published = true, Title = "News 2" }); + await _repository.InsertAsync(new NewsItem { Published = false, Title = "News 3" }); // Should be excluded + //Act + var result = await _newsService.GetStoreNews("", 0, 10, 0); // No limit (storeNewsLimit = 0) + //Assert + Assert.AreEqual(2, result.Count); // Only published news + Assert.IsTrue(result.All(x => x.Published)); + } + + [TestMethod] + public async Task GetStoreNews_WithLimit_ReturnsLimitedNews() + { + //Arrange + for (int i = 1; i <= 10; i++) + { + await _repository.InsertAsync(new NewsItem { Published = true, Title = $"News {i}" }); + } + //Act + var result = await _newsService.GetStoreNews("", 0, 10, 5); // Limit to 5 items + //Assert + Assert.AreEqual(5, result.Count); + Assert.AreEqual(5, result.TotalCount); // Total should respect the limit + } + + [TestMethod] + public async Task GetStoreNews_WithLimitAndPagination_ReturnsCorrectPage() + { + //Arrange + for (int i = 1; i <= 15; i++) + { + await _repository.InsertAsync(new NewsItem { Published = true, Title = $"News {i}" }); + } + //Act - Request page 2 (index 1) with page size 5, but limit to 8 total items + var result = await _newsService.GetStoreNews("", 1, 5, 8); // Page 2, size 5, limit 8 + //Assert + Assert.AreEqual(3, result.Count); // Should have 3 items (8 total - 5 on first page = 3 remaining) + } + + [TestMethod] + public async Task GetStoreNews_PageExceedsLimit_ReturnsEmptyResult() + { + //Arrange + for (int i = 1; i <= 10; i++) + { + await _repository.InsertAsync(new NewsItem { Published = true, Title = $"News {i}" }); + } + //Act - Request page 3 (index 2) with page size 5, but limit to 8 total items + var result = await _newsService.GetStoreNews("", 2, 5, 8); // Page 3, size 5, limit 8 (no items left) + //Assert + Assert.AreEqual(0, result.Count); + } + + [TestMethod] + public async Task GetStoreNews_ExcludesUnpublishedNews() + { + //Arrange + await _repository.InsertAsync(new NewsItem { Published = true, Title = "Published News" }); + await _repository.InsertAsync(new NewsItem { Published = false, Title = "Unpublished News" }); + //Act + var result = await _newsService.GetStoreNews("", 0, 10, 0); + //Assert + Assert.AreEqual(1, result.Count); + Assert.AreEqual("Published News", result.First().Title); + } } \ No newline at end of file From 2d70f68ce3bc67582068b227e101975c08ffc04f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 15:47:31 +0000 Subject: [PATCH 05/15] Revert global.json SDK version back to 9.0.100 Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index e9f309cde..41c9ad2ed 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.119", + "version": "9.0.100", "rollForward": "latestFeature", "allowPrerelease": false } From e2b6f0b964fb8ea502ee6a80bd50d1d80c4584ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:00:29 +0000 Subject: [PATCH 06/15] Add comprehensive news management (CRUD) to Store area Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- .../Areas/Store/Views/News/Create.cshtml | 38 +++++ .../Areas/Store/Views/News/Edit.cshtml | 70 ++++++++++ .../Areas/Store/Views/News/List.cshtml | 38 ++++- .../Partials/CreateOrUpdate.TabInfo.cshtml | 75 ++++++++++ .../Partials/CreateOrUpdate.TabSeo.cshtml | 57 ++++++++ .../Views/News/Partials/CreateOrUpdate.cshtml | 30 ++++ .../Controllers/NewsController.cs | 131 ++++++++++++++++++ 7 files changed, 436 insertions(+), 3 deletions(-) create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml new file mode 100644 index 000000000..13220b1bf --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml @@ -0,0 +1,38 @@ +@model NewsItemModel +@{ + ViewBag.Title = T("Admin.Content.News.NewsItems.AddNew"); + Layout = Constants.LayoutStore; +} + +
+
+
+
+
+

+ + @T("Admin.Content.News.NewsItems.AddNew") +

+ +
+
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml new file mode 100644 index 000000000..33a612641 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml @@ -0,0 +1,70 @@ +@model NewsItemModel +@{ + ViewBag.Title = T("Admin.Content.News.NewsItems.EditNewsItemDetails"); + Layout = Constants.LayoutStore; +} + +
+
+
+
+
+

+ + @T("Admin.Content.News.NewsItems.EditNewsItemDetails") - @Model.Title +

+ +
+
+ +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml index bfc844612..a64fd719a 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/List.cshtml @@ -12,6 +12,11 @@ @T("Admin.Content.News.NewsItems") +
@@ -84,12 +89,39 @@ attributes: { style: "text-align:center" } }, { field: "Id", - title: "@T("Admin.Common.View")", - width: 100, + title: "@T("Admin.Common.Actions")", + width: 150, headerAttributes: { style: "text-align:center" }, attributes: { style: "text-align:center" }, - template: '' + template: '
' + + '' + + '' + + '' + + '
' }] }); }); + + function deleteNews(id) { + if (confirm('@T("Admin.Common.AreYouSure")')) { + var postData = { + id: id + }; + addAntiForgeryToken(postData); + + $.ajax({ + cache: false, + type: "POST", + url: "@(Url.Action("Delete", "News"))", + data: postData, + success: function (data) { + var grid = $('#news-grid').data('kendoGrid'); + grid.dataSource.read(); + }, + error: function (xhr, ajaxOptions, thrownError) { + alert('Failed to delete news item'); + } + }); + } + } \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml new file mode 100644 index 000000000..2bd2067f2 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml @@ -0,0 +1,75 @@ +@using Microsoft.AspNetCore.Mvc.Razor +@model NewsItemModel + +@{ + Func + template = @
+ + + + + + + + + + + + + +
; +} + +
+
+
+ +
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml new file mode 100644 index 000000000..4043aefab --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml @@ -0,0 +1,57 @@ +@using Microsoft.AspNetCore.Mvc.Razor +@model NewsItemModel + +@{ + Func + template = @
+ + + + + + + + + + + + + + + + + +
; +} + +
+
+
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml new file mode 100644 index 000000000..7748d7e57 --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml @@ -0,0 +1,30 @@ +@model NewsItemModel + +
+ + +
+
+
+
+

@T("Admin.Content.News.NewsItems.Info")

+
+
+ +
+
+
+
+ +
+
+
+
+

@T("Admin.Common.SEO")

+
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs index 8df7f635d..c8aef3ae9 100644 --- a/src/Web/Grand.Web.Store/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -1,3 +1,4 @@ +using Grand.Business.Core.Extensions; using Grand.Business.Core.Interfaces.Cms; using Grand.Business.Core.Interfaces.Common.Configuration; using Grand.Business.Core.Interfaces.Common.Directory; @@ -92,6 +93,132 @@ public async Task List(DataSourceRequest command, NewsItemListMod return Json(gridModel); } + [PermissionAuthorizeAction(PermissionActionName.Create)] + public async Task Create() + { + ViewBag.AllLanguages = _languageService.GetAllLanguages(true); + var model = new NewsItemModel { + //default values + Published = true, + AllowComments = true + }; + + //locales + await AddLocales(_languageService, model.Locales); + return View(model); + } + + [PermissionAuthorizeAction(PermissionActionName.Edit)] + [HttpPost] + [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] + public async Task Create(NewsItemModel model, bool continueEditing) + { + if (ModelState.IsValid) + { + var newsItem = await _newsViewModelService.InsertNewsItemModel(model); + // Store-specific: Set the current store as the store for this news item + newsItem.Stores.Clear(); + newsItem.Stores.Add(_contextAccessor.StoreContext.CurrentStore.Id); + await _newsService.UpdateNews(newsItem); + + Success(_translationService.GetResource("Admin.Content.News.NewsItems.Added")); + return continueEditing ? RedirectToAction("Edit", new { id = newsItem.Id }) : RedirectToAction("List"); + } + + //If we got this far, something failed, redisplay form + ViewBag.AllLanguages = _languageService.GetAllLanguages(true); + return View(model); + } + + [PermissionAuthorizeAction(PermissionActionName.Preview)] + public async Task Edit(string id) + { + var newsItem = await _newsService.GetNewsById(id); + if (newsItem == null) + //No news item found with the specified id + return RedirectToAction("List"); + + // Store-specific: Ensure news item belongs to current store + if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) + return RedirectToAction("List"); + + ViewBag.AllLanguages = await _languageService.GetAllLanguages(true); + var model = newsItem.ToModel(_dateTimeService); + //locales + await AddLocales(_languageService, model.Locales, (locale, languageId) => + { + locale.Title = newsItem.GetTranslation(x => x.Title, languageId, false); + locale.Short = newsItem.GetTranslation(x => x.Short, languageId, false); + locale.Full = newsItem.GetTranslation(x => x.Full, languageId, false); + locale.MetaKeywords = newsItem.GetTranslation(x => x.MetaKeywords, languageId, false); + locale.MetaDescription = newsItem.GetTranslation(x => x.MetaDescription, languageId, false); + locale.MetaTitle = newsItem.GetTranslation(x => x.MetaTitle, languageId, false); + locale.SeName = newsItem.GetSeName(languageId, false); + }); + return View(model); + } + + [PermissionAuthorizeAction(PermissionActionName.Edit)] + [HttpPost] + [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] + public async Task Edit(NewsItemModel model, bool continueEditing) + { + var newsItem = await _newsService.GetNewsById(model.Id); + if (newsItem == null) + //No news item found with the specified id + return RedirectToAction("List"); + + // Store-specific: Ensure news item belongs to current store + if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) + return RedirectToAction("List"); + + if (ModelState.IsValid) + { + newsItem = await _newsViewModelService.UpdateNewsItemModel(newsItem, model); + Success(_translationService.GetResource("Admin.Content.News.NewsItems.Updated")); + + if (continueEditing) + { + //selected tab + await SaveSelectedTabIndex(); + + return RedirectToAction("Edit", new { id = newsItem.Id }); + } + + return RedirectToAction("List"); + } + + //If we got this far, something failed, redisplay form + ViewBag.AllLanguages = await _languageService.GetAllLanguages(true); + + return View(model); + } + + [PermissionAuthorizeAction(PermissionActionName.Delete)] + [HttpPost] + public async Task Delete(string id) + { + var newsItem = await _newsService.GetNewsById(id); + if (newsItem == null) + //No news item found with the specified id + return RedirectToAction("List"); + + // Store-specific: Ensure news item belongs to current store + if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) + return RedirectToAction("List"); + + if (ModelState.IsValid) + { + await _newsService.DeleteNews(newsItem); + + Success(_translationService.GetResource("Admin.Content.News.NewsItems.Deleted")); + return RedirectToAction("List"); + } + + Error(ModelState); + return RedirectToAction("Edit", new { id = newsItem.Id }); + } + [PermissionAuthorizeAction(PermissionActionName.Preview)] public async Task Preview(string id) { @@ -99,6 +226,10 @@ public async Task Preview(string id) if (newsItem == null) return RedirectToAction("List"); + // Store-specific: Ensure news item belongs to current store (for preview) + if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) + return RedirectToAction("List"); + var model = newsItem.ToModel(_dateTimeService); return View(model); } From 643a791938a5a9cefaa251de5e130aeae23f5e2f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:15:14 +0000 Subject: [PATCH 07/15] Fix NewsItemModel namespace import for Store area news views Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml index baff7dc33..d9c332025 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/_ViewImports.cshtml @@ -29,6 +29,7 @@ @using Grand.Web.AdminShared.Models.Common @using Grand.Web.AdminShared.Models.Customers @using Grand.Web.AdminShared.Models.Cms +@using Grand.Web.AdminShared.Models.News @inject LocService Loc @inject IEnumTranslationService EnumTranslationService \ No newline at end of file From 5e4fa42c7d7d1e37cbc150721a5ce0efa4b58a78 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Sun, 7 Sep 2025 18:30:55 +0200 Subject: [PATCH 08/15] Refactor NewsController for settings loading and localization Updated the method for loading news settings from `LoadSettingAsync` to `LoadSetting`, improving efficiency. Added a limit for the number of news items retrieved based on store settings. Enhanced the success message for adding news items to utilize a translation service, improving localization support. --- .../Grand.Web.Store/Controllers/NewsController.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs index c8aef3ae9..f54f5360f 100644 --- a/src/Web/Grand.Web.Store/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -6,7 +6,6 @@ using Grand.Domain.News; using Grand.Domain.Permissions; using Grand.Infrastructure; -using Grand.Web.AdminShared.Extensions; using Grand.Web.AdminShared.Extensions.Mapping; using Grand.Web.AdminShared.Interfaces; using Grand.Web.AdminShared.Models.News; @@ -71,15 +70,14 @@ public async Task List() [HttpPost] public async Task List(DataSourceRequest command, NewsItemListModel model) { - var newsSettings = await _settingService.LoadSettingAsync(_contextAccessor.StoreContext.CurrentStore.Id); + var newsSettings = await _settingService.LoadSetting(_contextAccessor.StoreContext.CurrentStore.Id); var storeId = _contextAccessor.StoreContext.CurrentStore.Id; - + // Use the store-specific news service method with limit - var news = await _newsService.GetStoreNews(storeId, command.Page - 1, command.PageSize, + var news = await _newsService.GetStoreNews(storeId, command.Page - 1, command.PageSize, newsSettings.StoreNewsLimit, model.SearchNewsTitle); - - var gridModel = new DataSourceResult - { + + var gridModel = new DataSourceResult { Data = news.Select(x => { var m = x.ToModel(_dateTimeService); @@ -120,7 +118,7 @@ public async Task Create(NewsItemModel model, bool continueEditin newsItem.Stores.Clear(); newsItem.Stores.Add(_contextAccessor.StoreContext.CurrentStore.Id); await _newsService.UpdateNews(newsItem); - + Success(_translationService.GetResource("Admin.Content.News.NewsItems.Added")); return continueEditing ? RedirectToAction("Edit", new { id = newsItem.Id }) : RedirectToAction("List"); } From a2f3a2921cb7881402414d973791ef33d21e68ca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 7 Sep 2025 16:34:05 +0000 Subject: [PATCH 09/15] Fix localization syntax: Replace @T() with @Loc[] in Store news views Co-authored-by: KrzysztofPajak <16772986+KrzysztofPajak@users.noreply.github.com> --- .../Areas/Store/Views/News/Create.cshtml | 10 +++++----- .../Areas/Store/Views/News/Edit.cshtml | 16 ++++++++-------- .../Areas/Store/Views/News/List.cshtml | 18 +++++++++--------- .../Partials/CreateOrUpdate.TabInfo.cshtml | 6 +++--- .../News/Partials/CreateOrUpdate.TabSeo.cshtml | 8 ++++---- .../Views/News/Partials/CreateOrUpdate.cshtml | 4 ++-- .../Areas/Store/Views/News/Preview.cshtml | 18 +++++++++--------- 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml index 13220b1bf..cc7b080c1 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml @@ -1,6 +1,6 @@ @model NewsItemModel @{ - ViewBag.Title = T("Admin.Content.News.NewsItems.AddNew"); + ViewBag.Title = Loc["Admin.Content.News.NewsItems.AddNew"]; Layout = Constants.LayoutStore; } @@ -11,11 +11,11 @@

- @T("Admin.Content.News.NewsItems.AddNew") + @Loc["Admin.Content.News.NewsItems.AddNew"]

@@ -25,10 +25,10 @@ diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml index 33a612641..cad212fd6 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml @@ -1,6 +1,6 @@ @model NewsItemModel @{ - ViewBag.Title = T("Admin.Content.News.NewsItems.EditNewsItemDetails"); + ViewBag.Title = Loc["Admin.Content.News.NewsItems.EditNewsItemDetails"]; Layout = Constants.LayoutStore; } @@ -11,14 +11,14 @@

- @T("Admin.Content.News.NewsItems.EditNewsItemDetails") - @Model.Title + @Loc["Admin.Content.News.NewsItems.EditNewsItemDetails"] - @Model.Title

@@ -28,15 +28,15 @@ @@ -47,7 +47,7 @@ + \ No newline at end of file From 0619ac1f262dc142facd27e13b897a329e8d22ec Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Mon, 8 Sep 2025 20:11:25 +0200 Subject: [PATCH 12/15] Enhance news management features and UI improvements - Added new permission for managing news items in `PermissionExtensions.cs`. - Refactored `Create.cshtml` and `Edit.cshtml` to use a new panel layout and updated button structures. - Introduced `CreateOrUpdate.TabComments.cshtml` with a Kendo Grid for comment management. - Updated `CreateOrUpdate.TabInfo.cshtml` and `CreateOrUpdate.TabSeo.cshtml` to use custom components for better consistency. - Implemented a tabbed interface in `CreateOrUpdate.cshtml` for improved navigation. - Simplified layout in `Preview.cshtml` for displaying news item details. - Enhanced store-specific logic in `NewsController.cs` to enforce access permissions based on user stores. - Modified `DefaultLanguage.xml` (binary file changes). --- .../Extensions/PermissionExtensions.cs | 3 +- .../Areas/Store/Views/News/Create.cshtml | 44 +++--- .../Areas/Store/Views/News/Edit.cshtml | 84 ++++------- .../CreateOrUpdate.TabComments.cshtml | 96 +++++++++++++ .../Partials/CreateOrUpdate.TabInfo.cshtml | 136 +++++++++++------- .../Partials/CreateOrUpdate.TabSeo.cshtml | 108 ++++++++------ .../Views/News/Partials/CreateOrUpdate.cshtml | 54 +++---- .../Areas/Store/Views/News/Preview.cshtml | 89 ------------ .../Controllers/NewsController.cs | 32 +++-- .../App_Data/Resources/DefaultLanguage.xml | Bin 1536216 -> 1536538 bytes 10 files changed, 340 insertions(+), 306 deletions(-) create mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabComments.cshtml delete mode 100644 src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml diff --git a/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs b/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs index 729f88c5b..0638e318d 100644 --- a/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs +++ b/src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs @@ -212,7 +212,8 @@ public static IEnumerable DefaultPermissions() StandardPermission.ManageShipments, StandardPermission.ManageMerchandiseReturns, StandardPermission.ManageCheckoutAttribute, - StandardPermission.ManageReports + StandardPermission.ManageReports, + StandardPermission.ManageNews ] }, diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml index cc7b080c1..53e393735 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Create.cshtml @@ -1,37 +1,37 @@ -@model NewsItemModel +@model NewsItemModel @{ + //page title ViewBag.Title = Loc["Admin.Content.News.NewsItems.AddNew"]; Layout = Constants.LayoutStore; } +
-
-
-
-

- +
+
+
+ @Loc["Admin.Content.News.NewsItems.AddNew"] -

-
- - @Loc["Admin.Content.News.NewsItems.BackToList"] - + + @Html.ActionLink(Loc["Admin.Content.News.NewsItems.BackToList"], "List") + +
+
+
+ + + +
-
+
-
diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml index cad212fd6..2e2ea0f40 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Edit.cshtml @@ -1,70 +1,46 @@ -@model NewsItemModel +@model NewsItemModel @{ + //page title ViewBag.Title = Loc["Admin.Content.News.NewsItems.EditNewsItemDetails"]; Layout = Constants.LayoutStore; } + -
-
-
-

- +
+
+
+ @Loc["Admin.Content.News.NewsItems.EditNewsItemDetails"] - @Model.Title -

-
- - @Loc["Admin.Content.News.NewsItems.BackToList"] - - - @Loc["Admin.Common.Preview"] - + + @Html.ActionLink(Loc["Admin.Content.News.NewsItems.BackToList"], "List") + +
+
+
+ + + + + @Loc["Admin.Common.Delete"] + + +
-
+
-
- - \ No newline at end of file + \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabComments.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabComments.cshtml new file mode 100644 index 000000000..266dc45ae --- /dev/null +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabComments.cshtml @@ -0,0 +1,96 @@ +@model NewsItemModel +@inject AdminAreaSettings adminAreaSettings + +@if (!string.IsNullOrEmpty(Model.Id)) +{ +
+ +
+
+
+ +
+ +} +else +{ +
+ @Loc["Admin.Content.News.NewsItems.SaveBeforeEdit"] +
+} \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml index 0b7b04cdd..c0a489daa 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabInfo.cshtml @@ -1,75 +1,101 @@ -@using Microsoft.AspNetCore.Mvc.Razor +@using Microsoft.AspNetCore.Mvc.Razor @model NewsItemModel @{ Func - template = @
- - - - - - - - - - - - + template = @
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
; }
-
-
- -
- - - -
-
- - - + +
+ +
+ +
+ +
-
- - - +
+
+ +
+ +
- - +
- - - + +
+ + +
- -
- - - + +
+ +
+ +
- -
- - - +
+
+ +
+ +
- -
- - - +
+
+ +
+ +
- -
- - - +
+
+ +
+ +
+
+ +
+ + +
+
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml index 9e1229fe4..2f504cbfe 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.TabSeo.cshtml @@ -1,57 +1,75 @@ -@using Microsoft.AspNetCore.Mvc.Razor +@using Microsoft.AspNetCore.Mvc.Razor @model NewsItemModel + @{ Func - template = @
- - - - - - - - - - - - - - - - - -
; + template = @
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+ +
; }
-
-
- -
- - - + +
+
+ +
+ +
- -
- - - +
+
+ +
+ +
- -
- - - +
+
+ +
+ +
- -
- - - +
+
+ +
+ +
- +
-
-
\ No newline at end of file + + +
+ \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml index b5a5650ec..9e3c8074e 100644 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml +++ b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Partials/CreateOrUpdate.cshtml @@ -1,30 +1,30 @@ -@model NewsItemModel +@model NewsItemModel
- -
-
-
-
-

@Loc["Admin.Content.News.NewsItems.Info"]

-
-
- -
-
-
-
- -
-
-
-
-

@Loc["Admin.Common.SEO"]

-
-
- -
-
-
-
\ No newline at end of file + + + + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ +
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml b/src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml deleted file mode 100644 index 40d5582d5..000000000 --- a/src/Web/Grand.Web.Store/Areas/Store/Views/News/Preview.cshtml +++ /dev/null @@ -1,89 +0,0 @@ -@model NewsItemModel -@{ - ViewBag.Title = Model.Title; - Layout = Constants.LayoutStore; -} - -
-
-
-
-

- - @Loc["Admin.Content.News.NewsItems.Preview"] -

- -
-
-
-
-
-
- @Loc["Admin.Content.News.NewsItems.Fields.Title"]: -
-
- @Model.Title -
-
- -
-
- @Loc["Admin.Content.News.NewsItems.Fields.Published"]: -
-
- @(Model.Published ? Loc["Admin.Common.Yes"] : Loc["Admin.Common.No"]) -
-
- -
-
- @Loc["Admin.Content.News.NewsItems.Fields.CreatedOn"]: -
-
- @Model.CreatedOn.ToString("G") -
-
- - @if (!string.IsNullOrEmpty(Model.Short)) - { -
-
- @Loc["Admin.Content.News.NewsItems.Fields.Short"]: -
-
- @Html.Raw(Model.Short) -
-
- } - - @if (!string.IsNullOrEmpty(Model.Full)) - { -
-
- @Loc["Admin.Content.News.NewsItems.Fields.Full"]: -
-
- @Html.Raw(Model.Full) -
-
- } - -
-
- @Loc["Admin.Content.News.NewsItems.Fields.Comments"]: -
-
- @Model.Comments -
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs index fdf40fd7b..e6cbbec83 100644 --- a/src/Web/Grand.Web.Store/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -3,9 +3,11 @@ using Grand.Business.Core.Interfaces.Common.Configuration; using Grand.Business.Core.Interfaces.Common.Directory; using Grand.Business.Core.Interfaces.Common.Localization; +using Grand.Domain.Catalog; using Grand.Domain.News; using Grand.Domain.Permissions; using Grand.Infrastructure; +using Grand.Web.AdminShared.Extensions; using Grand.Web.AdminShared.Extensions.Mapping; using Grand.Web.AdminShared.Interfaces; using Grand.Web.AdminShared.Models.News; @@ -113,10 +115,8 @@ public async Task Create(NewsItemModel model, bool continueEditin { if (ModelState.IsValid) { + model.Stores = [_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId]; var newsItem = await _newsViewModelService.InsertNewsItemModel(model); - // Store-specific: Set the current store as the store for this news item - newsItem.Stores.Clear(); - newsItem.Stores.Add(_contextAccessor.StoreContext.CurrentStore.Id); await _newsService.UpdateNews(newsItem); Success(_translationService.GetResource("Admin.Content.News.NewsItems.Added")); @@ -136,9 +136,17 @@ public async Task Edit(string id) //No news item found with the specified id return RedirectToAction("List"); - // Store-specific: Ensure news item belongs to current store - if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) - return RedirectToAction("List"); + if (!newsItem.LimitedToStores || (newsItem.LimitedToStores && + newsItem.Stores.Contains(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId) && + newsItem.Stores.Count > 1)) + { + Warning(_translationService.GetResource("Admin.Content.News.Permissions")); + } + else + { + if (!newsItem.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return RedirectToAction("List"); + } ViewBag.AllLanguages = await _languageService.GetAllLanguages(true); var model = newsItem.ToModel(_dateTimeService); @@ -166,12 +174,12 @@ public async Task Edit(NewsItemModel model, bool continueEditing) //No news item found with the specified id return RedirectToAction("List"); - // Store-specific: Ensure news item belongs to current store - if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) - return RedirectToAction("List"); + if (!newsItem.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) + return RedirectToAction("Edit", new { id = newsItem.Id }); if (ModelState.IsValid) { + model.Stores = [_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId]; newsItem = await _newsViewModelService.UpdateNewsItemModel(newsItem, model); Success(_translationService.GetResource("Admin.Content.News.NewsItems.Updated")); @@ -201,8 +209,7 @@ public async Task Delete(string id) //No news item found with the specified id return RedirectToAction("List"); - // Store-specific: Ensure news item belongs to current store - if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) + if (!newsItem.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) return RedirectToAction("List"); if (ModelState.IsValid) @@ -224,8 +231,7 @@ public async Task Preview(string id) if (newsItem == null) return RedirectToAction("List"); - // Store-specific: Ensure news item belongs to current store (for preview) - if (!newsItem.Stores.Contains(_contextAccessor.StoreContext.CurrentStore.Id)) + if (!newsItem.AccessToEntityByStore(_contextAccessor.WorkContext.CurrentCustomer.StaffStoreId)) return RedirectToAction("List"); var model = newsItem.ToModel(_dateTimeService); diff --git a/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml b/src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml index 8b59be237692351cb60b7182b85bb79774b9a587..3b37fcbdf7e86da862c8d3382c48cf5acac70499 100644 GIT binary patch delta 126 zcmccdFm~3H*oGFy7N!>F7M2#)7Pc+y8SAGn=wauYZnm1Sh&_)Xm7$!WczS;%*ZOJO z*rlfTT;nvEeqk;z>_E%`#GF9P1;pGy%mc){K+Ffk{6H)K#DYL91jNEXECR%$ L+t;iY(>VwL^k6py delta 104 zcmbRBB=*L`*oGFy7N!>F7M2#)7Pc+y8SAGPY-Hz}e(pM_$@B|z+1c9PZD0pt4j|?P oVlE)&24Wr{<^^ItAm#^R0U#CxVj& Date: Sun, 14 Sep 2025 18:08:49 +0200 Subject: [PATCH 13/15] Further changes --- .../Services/NewsService.cs | 25 +--------- .../Interfaces/Cms/INewsService.cs | 4 +- src/Core/Grand.Domain/News/NewsSettings.cs | 5 -- .../Services/NewsServiceTests.cs | 47 +------------------ .../Partials/Content.TabNewsSettings.cshtml | 11 +---- .../Controllers/NewsController.cs | 3 +- .../Models/Settings/ContentSettingsModel.cs | 3 -- .../Controllers/NewsController.cs | 3 +- 8 files changed, 7 insertions(+), 94 deletions(-) diff --git a/src/Business/Grand.Business.Cms/Services/NewsService.cs b/src/Business/Grand.Business.Cms/Services/NewsService.cs index fed6262c3..d4d714546 100644 --- a/src/Business/Grand.Business.Cms/Services/NewsService.cs +++ b/src/Business/Grand.Business.Cms/Services/NewsService.cs @@ -106,11 +106,10 @@ public virtual async Task> GetAllNews(string storeId = "", /// Store identifier /// Page index /// Page size - /// Maximum number of news items to return (0 for unlimited) /// News title filter /// News items public virtual async Task> GetStoreNews(string storeId = "", - int pageIndex = 0, int pageSize = int.MaxValue, int storeNewsLimit = 0, string newsTitle = "") + int pageIndex = 0, int pageSize = int.MaxValue, string newsTitle = "") { var query = from p in _newsItemRepository.Table select p; @@ -141,28 +140,6 @@ public virtual async Task> GetStoreNews(string storeId = "" query = query.OrderByDescending(n => n.CreatedOnUtc); - // Apply store news limit if specified - if (storeNewsLimit > 0) - { - // First check if the requested page would exceed our limit - var remainingItems = storeNewsLimit - (pageIndex * pageSize); - if (remainingItems <= 0) - { - // No items left for this page - return new PagedList(new List(), pageIndex, pageSize, 0); - } - - // Adjust page size if it would exceed the limit on this page - if (pageSize > remainingItems) - { - pageSize = remainingItems; - } - - // Limit the total query to the store limit and let PagedList handle pagination - var limitedQuery = query.Take(storeNewsLimit); - return await PagedList.Create(limitedQuery, pageIndex, pageSize); - } - return await PagedList.Create(query, pageIndex, pageSize); } diff --git a/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs b/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs index 2dc8a0894..be93e4c98 100644 --- a/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs +++ b/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs @@ -60,9 +60,7 @@ Task> GetAllNews(string storeId = "", /// Store identifier /// Page index /// Page size - /// Maximum number of news items to return (0 for unlimited) /// News title filter /// News items - Task> GetStoreNews(string storeId = "", - int pageIndex = 0, int pageSize = int.MaxValue, int storeNewsLimit = 0, string newsTitle = ""); + Task> GetStoreNews(string storeId = "", int pageIndex = 0, int pageSize = int.MaxValue, string newsTitle = ""); } \ No newline at end of file diff --git a/src/Core/Grand.Domain/News/NewsSettings.cs b/src/Core/Grand.Domain/News/NewsSettings.cs index f8b26866b..9c75ab564 100644 --- a/src/Core/Grand.Domain/News/NewsSettings.cs +++ b/src/Core/Grand.Domain/News/NewsSettings.cs @@ -33,9 +33,4 @@ public class NewsSettings : ISettings /// Gets or sets the page size for news archive /// public int NewsArchivePageSize { get; set; } - - /// - /// Gets or sets the maximum number of news items to display in store (0 for unlimited) - /// - public int StoreNewsLimit { get; set; } } \ No newline at end of file diff --git a/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs b/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs index 5b0a6caaf..c31382200 100644 --- a/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs +++ b/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs @@ -117,55 +117,12 @@ public async Task GetStoreNews_NoLimit_ReturnsAllPublishedNews() await _repository.InsertAsync(new NewsItem { Published = true, Title = "News 2" }); await _repository.InsertAsync(new NewsItem { Published = false, Title = "News 3" }); // Should be excluded //Act - var result = await _newsService.GetStoreNews("", 0, 10, 0); // No limit (storeNewsLimit = 0) + var result = await _newsService.GetStoreNews("", 0, 10); // No limit (storeNewsLimit = 0) //Assert Assert.AreEqual(2, result.Count); // Only published news Assert.IsTrue(result.All(x => x.Published)); } - [TestMethod] - public async Task GetStoreNews_WithLimit_ReturnsLimitedNews() - { - //Arrange - for (int i = 1; i <= 10; i++) - { - await _repository.InsertAsync(new NewsItem { Published = true, Title = $"News {i}" }); - } - //Act - var result = await _newsService.GetStoreNews("", 0, 10, 5); // Limit to 5 items - //Assert - Assert.AreEqual(5, result.Count); - Assert.AreEqual(5, result.TotalCount); // Total should respect the limit - } - - [TestMethod] - public async Task GetStoreNews_WithLimitAndPagination_ReturnsCorrectPage() - { - //Arrange - for (int i = 1; i <= 15; i++) - { - await _repository.InsertAsync(new NewsItem { Published = true, Title = $"News {i}" }); - } - //Act - Request page 2 (index 1) with page size 5, but limit to 8 total items - var result = await _newsService.GetStoreNews("", 1, 5, 8); // Page 2, size 5, limit 8 - //Assert - Assert.AreEqual(3, result.Count); // Should have 3 items (8 total - 5 on first page = 3 remaining) - } - - [TestMethod] - public async Task GetStoreNews_PageExceedsLimit_ReturnsEmptyResult() - { - //Arrange - for (int i = 1; i <= 10; i++) - { - await _repository.InsertAsync(new NewsItem { Published = true, Title = $"News {i}" }); - } - //Act - Request page 3 (index 2) with page size 5, but limit to 8 total items - var result = await _newsService.GetStoreNews("", 2, 5, 8); // Page 3, size 5, limit 8 (no items left) - //Assert - Assert.AreEqual(0, result.Count); - } - [TestMethod] public async Task GetStoreNews_ExcludesUnpublishedNews() { @@ -173,7 +130,7 @@ public async Task GetStoreNews_ExcludesUnpublishedNews() await _repository.InsertAsync(new NewsItem { Published = true, Title = "Published News" }); await _repository.InsertAsync(new NewsItem { Published = false, Title = "Unpublished News" }); //Act - var result = await _newsService.GetStoreNews("", 0, 10, 0); + var result = await _newsService.GetStoreNews("", 0, 10); //Assert Assert.AreEqual(1, result.Count); Assert.AreEqual("Published News", result.First().Title); diff --git a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml index 441d78404..1defad5c8 100644 --- a/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml +++ b/src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml @@ -67,15 +67,6 @@
-
-
-
- -
-
- - -
-
+
\ No newline at end of file diff --git a/src/Web/Grand.Web.Admin/Controllers/NewsController.cs b/src/Web/Grand.Web.Admin/Controllers/NewsController.cs index 4c4e9b8d3..e84b124b7 100644 --- a/src/Web/Grand.Web.Admin/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/NewsController.cs @@ -203,8 +203,7 @@ public IActionResult Comments(string filterByNewsItemId) [HttpPost] public async Task Comments(string filterByNewsItemId, DataSourceRequest command) { - var comments = - await _newsViewModelService.PrepareNewsCommentModel(filterByNewsItemId, command.Page, command.PageSize); + var comments = await _newsViewModelService.PrepareNewsCommentModel(filterByNewsItemId, command.Page, command.PageSize); var gridModel = new DataSourceResult { Data = comments.newsCommentModels.ToList(), diff --git a/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs b/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs index f26774a9a..c3a0f18af 100644 --- a/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs +++ b/src/Web/Grand.Web.AdminShared/Models/Settings/ContentSettingsModel.cs @@ -59,9 +59,6 @@ public class NewsSettingsModel : BaseModel [GrandResourceDisplayName("Admin.Settings.News.NewsArchivePageSize")] public int NewsArchivePageSize { get; set; } - - [GrandResourceDisplayName("Admin.Settings.News.StoreNewsLimit")] - public int StoreNewsLimit { get; set; } } public class KnowledgebaseSettingsModel : BaseModel diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs index e6cbbec83..9b950a7a8 100644 --- a/src/Web/Grand.Web.Store/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -76,8 +76,7 @@ public async Task List(DataSourceRequest command, NewsItemListMod var storeId = _contextAccessor.StoreContext.CurrentStore.Id; // Use the store-specific news service method with limit - var news = await _newsService.GetStoreNews(storeId, command.Page - 1, command.PageSize, - newsSettings.StoreNewsLimit, model.SearchNewsTitle); + var news = await _newsService.GetStoreNews(storeId, command.Page - 1, command.PageSize, model.SearchNewsTitle); var gridModel = new DataSourceResult { Data = news.Select(x => From 15a246cc1f8b51f97492d84e7b6c9d93878f9d69 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Sun, 14 Sep 2025 18:14:28 +0200 Subject: [PATCH 14/15] Remove GetStoreNews method and related tests This commit removes the `GetStoreNews` method from the `INewsService` interface and the `NewsService` class, along with its associated XML documentation. The removal includes two test methods from `NewsServiceTests` that validated the behavior of `GetStoreNews`. Additionally, the `NewsController` class has been updated to replace the call to `GetStoreNews` with a new method, `GetAllNews`, reflecting a shift towards a more general news retrieval approach. --- .../Services/NewsService.cs | 43 ------------------- .../Interfaces/Cms/INewsService.cs | 10 ----- .../Services/NewsServiceTests.cs | 27 ------------ .../Controllers/NewsController.cs | 3 +- 4 files changed, 1 insertion(+), 82 deletions(-) diff --git a/src/Business/Grand.Business.Cms/Services/NewsService.cs b/src/Business/Grand.Business.Cms/Services/NewsService.cs index d4d714546..567b7a9d1 100644 --- a/src/Business/Grand.Business.Cms/Services/NewsService.cs +++ b/src/Business/Grand.Business.Cms/Services/NewsService.cs @@ -100,49 +100,6 @@ public virtual async Task> GetAllNews(string storeId = "", return await PagedList.Create(query, pageIndex, pageSize); } - /// - /// Gets news for store with configurable limit - /// - /// Store identifier - /// Page index - /// Page size - /// News title filter - /// News items - public virtual async Task> GetStoreNews(string storeId = "", - int pageIndex = 0, int pageSize = int.MaxValue, string newsTitle = "") - { - var query = from p in _newsItemRepository.Table - select p; - - if (!string.IsNullOrWhiteSpace(newsTitle)) - query = query.Where(n => n.Title != null && n.Title.ToLower().Contains(newsTitle.ToLower())); - - // Store news should only show published and current items - var utcNow = DateTime.UtcNow; - query = query.Where(n => n.Published); - query = query.Where(n => !n.StartDateUtc.HasValue || n.StartDateUtc <= utcNow); - query = query.Where(n => !n.EndDateUtc.HasValue || n.EndDateUtc >= utcNow); - - // Apply ACL and store limitations for store context - if (!_accessControlConfig.IgnoreAcl) - { - var allowedCustomerGroupsIds = _contextAccessor.WorkContext.CurrentCustomer.GetCustomerGroupIds(); - query = from p in query - where !p.LimitedToGroups || allowedCustomerGroupsIds.Any(x => p.CustomerGroups.Contains(x)) - select p; - } - - // Store acl - if (!string.IsNullOrEmpty(storeId) && !_accessControlConfig.IgnoreStoreLimitations) - query = from p in query - where !p.LimitedToStores || p.Stores.Contains(storeId) - select p; - - query = query.OrderByDescending(n => n.CreatedOnUtc); - - return await PagedList.Create(query, pageIndex, pageSize); - } - /// /// Inserts a news item /// diff --git a/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs b/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs index be93e4c98..a74736595 100644 --- a/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs +++ b/src/Business/Grand.Business.Core/Interfaces/Cms/INewsService.cs @@ -53,14 +53,4 @@ Task> GetAllNews(string storeId = "", /// Customer identifier; "" to load all records /// Comments Task> GetAllComments(string customerId); - - /// - /// Gets news for store with configurable limit - /// - /// Store identifier - /// Page index - /// Page size - /// News title filter - /// News items - Task> GetStoreNews(string storeId = "", int pageIndex = 0, int pageSize = int.MaxValue, string newsTitle = ""); } \ No newline at end of file diff --git a/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs b/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs index c31382200..fc3cf2889 100644 --- a/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs +++ b/src/Tests/Grand.Business.Cms.Tests/Services/NewsServiceTests.cs @@ -108,31 +108,4 @@ public async Task GetAllCommentsTest() //Assert Assert.IsTrue(result.Any()); } - - [TestMethod] - public async Task GetStoreNews_NoLimit_ReturnsAllPublishedNews() - { - //Arrange - await _repository.InsertAsync(new NewsItem { Published = true, Title = "News 1" }); - await _repository.InsertAsync(new NewsItem { Published = true, Title = "News 2" }); - await _repository.InsertAsync(new NewsItem { Published = false, Title = "News 3" }); // Should be excluded - //Act - var result = await _newsService.GetStoreNews("", 0, 10); // No limit (storeNewsLimit = 0) - //Assert - Assert.AreEqual(2, result.Count); // Only published news - Assert.IsTrue(result.All(x => x.Published)); - } - - [TestMethod] - public async Task GetStoreNews_ExcludesUnpublishedNews() - { - //Arrange - await _repository.InsertAsync(new NewsItem { Published = true, Title = "Published News" }); - await _repository.InsertAsync(new NewsItem { Published = false, Title = "Unpublished News" }); - //Act - var result = await _newsService.GetStoreNews("", 0, 10); - //Assert - Assert.AreEqual(1, result.Count); - Assert.AreEqual("Published News", result.First().Title); - } } \ No newline at end of file diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs index 9b950a7a8..b62cbd9e5 100644 --- a/src/Web/Grand.Web.Store/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -75,8 +75,7 @@ public async Task List(DataSourceRequest command, NewsItemListMod var newsSettings = await _settingService.LoadSetting(_contextAccessor.StoreContext.CurrentStore.Id); var storeId = _contextAccessor.StoreContext.CurrentStore.Id; - // Use the store-specific news service method with limit - var news = await _newsService.GetStoreNews(storeId, command.Page - 1, command.PageSize, model.SearchNewsTitle); + var news = await _newsService.GetAllNews(storeId, command.Page - 1, command.PageSize, newsTitle: model.SearchNewsTitle); var gridModel = new DataSourceResult { Data = news.Select(x => From c9afc87015cdd16abae4efe86ab06b22650b2459 Mon Sep 17 00:00:00 2001 From: KrzysztofPajak Date: Sun, 14 Sep 2025 18:16:46 +0200 Subject: [PATCH 15/15] Simplify newsSettings initialization in NewsController --- src/Web/Grand.Web.Store/Controllers/NewsController.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Web/Grand.Web.Store/Controllers/NewsController.cs b/src/Web/Grand.Web.Store/Controllers/NewsController.cs index b62cbd9e5..4f16e8a2c 100644 --- a/src/Web/Grand.Web.Store/Controllers/NewsController.cs +++ b/src/Web/Grand.Web.Store/Controllers/NewsController.cs @@ -3,7 +3,6 @@ using Grand.Business.Core.Interfaces.Common.Configuration; using Grand.Business.Core.Interfaces.Common.Directory; using Grand.Business.Core.Interfaces.Common.Localization; -using Grand.Domain.Catalog; using Grand.Domain.News; using Grand.Domain.Permissions; using Grand.Infrastructure; @@ -72,8 +71,8 @@ public IActionResult List() [HttpPost] public async Task List(DataSourceRequest command, NewsItemListModel model) { - var newsSettings = await _settingService.LoadSetting(_contextAccessor.StoreContext.CurrentStore.Id); var storeId = _contextAccessor.StoreContext.CurrentStore.Id; + var newsSettings = await _settingService.LoadSetting(storeId); var news = await _newsService.GetAllNews(storeId, command.Page - 1, command.PageSize, newsTitle: model.SearchNewsTitle);