Skip to content

Commit 88acb8b

Browse files
authored
Extend news management from Admin to Store with full CRUD operations and configurable per-store limits (#617)
1 parent 5ab5e84 commit 88acb8b

File tree

15 files changed

+765
-5
lines changed

15 files changed

+765
-5
lines changed

src/Modules/Grand.Module.Installer/Extensions/PermissionExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ public static IEnumerable<DefaultPermission> DefaultPermissions()
212212
StandardPermission.ManageShipments,
213213
StandardPermission.ManageMerchandiseReturns,
214214
StandardPermission.ManageCheckoutAttribute,
215-
StandardPermission.ManageReports
215+
StandardPermission.ManageReports,
216+
StandardPermission.ManageNews
216217
]
217218
},
218219

src/Web/Grand.Web.Admin/Areas/Admin/Views/Setting/Partials/Content.TabNewsSettings.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,6 @@
6767
<admin-input asp-for="NewsSettings.NewsArchivePageSize"/>
6868
<span asp-validation-for="NewsSettings.NewsArchivePageSize"></span>
6969
</div>
70-
</div>
70+
</div>
7171
</div>
7272
</div>

src/Web/Grand.Web.Admin/Controllers/NewsController.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,7 @@ public IActionResult Comments(string filterByNewsItemId)
203203
[HttpPost]
204204
public async Task<IActionResult> Comments(string filterByNewsItemId, DataSourceRequest command)
205205
{
206-
var comments =
207-
await _newsViewModelService.PrepareNewsCommentModel(filterByNewsItemId, command.Page, command.PageSize);
206+
var comments = await _newsViewModelService.PrepareNewsCommentModel(filterByNewsItemId, command.Page, command.PageSize);
208207

209208
var gridModel = new DataSourceResult {
210209
Data = comments.newsCommentModels.ToList(),

src/Web/Grand.Web.AdminShared/Models/News/NewsItemListModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ public class NewsItemListModel : BaseModel
99
[GrandResourceDisplayName("Admin.Content.News.NewsItems.List.SearchStore")]
1010
public string SearchStoreId { get; set; }
1111

12+
[GrandResourceDisplayName("Admin.Content.News.NewsItems.List.SearchTitle")]
13+
public string SearchNewsTitle { get; set; }
14+
1215
public IList<SelectListItem> AvailableStores { get; set; } = new List<SelectListItem>();
1316
}

src/Web/Grand.Web.AdminShared/Services/NewsViewModelService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public NewsViewModelService(INewsService newsService,
4949
public virtual async Task<(IEnumerable<NewsItemModel> newsItemModels, int totalCount)> PrepareNewsItemModel(
5050
NewsItemListModel model, int pageIndex, int pageSize)
5151
{
52-
var news = await _newsService.GetAllNews(model.SearchStoreId, pageIndex - 1, pageSize, true, true);
52+
var news = await _newsService.GetAllNews(model.SearchStoreId, pageIndex - 1, pageSize, true, true, model.SearchNewsTitle);
5353
return (news.Select(x =>
5454
{
5555
var m = x.ToModel(_dateTimeService);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@model NewsItemModel
2+
@{
3+
//page title
4+
ViewBag.Title = Loc["Admin.Content.News.NewsItems.AddNew"];
5+
Layout = Constants.LayoutStore;
6+
}
7+
<form asp-area="@Constants.AreaStore" asp-controller="News" asp-action="Create" method="post">
8+
9+
<div class="row">
10+
<div class="col-md-12">
11+
<div class="x_panel light form-fit">
12+
<div class="x_title">
13+
<div class="caption">
14+
<i class="fa fa-hacker-news"></i>
15+
@Loc["Admin.Content.News.NewsItems.AddNew"]
16+
<small>
17+
<i class="fa fa-arrow-circle-left"></i>@Html.ActionLink(Loc["Admin.Content.News.NewsItems.BackToList"], "List")
18+
</small>
19+
</div>
20+
<div class="actions">
21+
<div class="btn-group btn-group-devided">
22+
<button class="btn btn-success" type="submit" name="save">
23+
<i class="fa fa-check"></i> @Loc["Admin.Common.Save"]
24+
</button>
25+
<button class="btn btn-success" type="submit" name="save-continue">
26+
<i class="fa fa-check-circle"></i> @Loc["Admin.Common.SaveContinue"]
27+
</button>
28+
<vc:admin-widget widget-zone="news_details_buttons" additional-data="null"/>
29+
</div>
30+
</div>
31+
</div>
32+
<div class="x_content form">
33+
<partial name="Partials/CreateOrUpdate" model="Model"/>
34+
</div>
35+
</div>
36+
</div>
37+
</div>
38+
</form>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@model NewsItemModel
2+
@{
3+
//page title
4+
ViewBag.Title = Loc["Admin.Content.News.NewsItems.EditNewsItemDetails"];
5+
Layout = Constants.LayoutStore;
6+
}
7+
<form asp-area="@Constants.AreaStore" asp-controller="News" asp-action="Edit" method="post">
8+
9+
<div class="row">
10+
<div class="col-md-12">
11+
<div class="x_panel light form-fit">
12+
<div class="x_title">
13+
<div class="caption">
14+
<i class="fa fa-hacker-news"></i>
15+
@Loc["Admin.Content.News.NewsItems.EditNewsItemDetails"] - @Model.Title
16+
<small>
17+
<i class="fa fa-arrow-circle-left"></i>@Html.ActionLink(Loc["Admin.Content.News.NewsItems.BackToList"], "List")
18+
</small>
19+
</div>
20+
<div class="actions">
21+
<div class="btn-group btn-group-devided">
22+
<button type="button" onclick="window.open('@Url.RouteUrl("NewsItem", new { Model.SeName })','_blank');" class="btn purple">
23+
<i class="fa fa-eye"></i>
24+
@Loc["Admin.Common.Preview"]
25+
</button>
26+
<button class="btn btn-success" type="submit" name="save">
27+
<i class="fa fa-check"></i> @Loc["Admin.Common.Save"]
28+
</button>
29+
<button class="btn btn-success" type="submit" name="save-continue">
30+
<i class="fa fa-check-circle"></i> @Loc["Admin.Common.SaveContinue"]
31+
</button>
32+
<span id="newsitem-delete" class="btn red">
33+
<i class="fa fa-trash-o"></i> @Loc["Admin.Common.Delete"]
34+
</span>
35+
<vc:admin-widget widget-zone="news_details_buttons" additional-data="Model"/>
36+
</div>
37+
</div>
38+
</div>
39+
<div class="x_content form">
40+
<partial name="Partials/CreateOrUpdate" model="Model"/>
41+
</div>
42+
</div>
43+
</div>
44+
</div>
45+
</form>
46+
<admin-delete-confirmation button-id="newsitem-delete"/>
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
@model NewsItemListModel
2+
@inject AdminAreaSettings adminAreaSettings
3+
@{
4+
//page title
5+
ViewBag.Title = Loc["Admin.Content.News.NewsItems"];
6+
Layout = Constants.LayoutStore;
7+
}
8+
9+
<div class="row">
10+
<div class="col-md-12">
11+
<div class="x_panel light form-fit">
12+
<div class="x_title">
13+
<div class="caption">
14+
<i class="fa fa-hacker-news"></i>
15+
@Loc["Admin.Content.News.NewsItems"]
16+
</div>
17+
<div class="actions btn-group btn-group-devided">
18+
<a href="@Url.Action("Create", new { area = Constants.AreaStore })" class="btn green">
19+
<i class="fa fa-plus"></i><span class="d-none d-sm-inline"> @Loc["Admin.Common.AddNew"] </span>
20+
</a>
21+
<vc:admin-widget widget-zone="news_list_buttons" additional-data="null" />
22+
</div>
23+
</div>
24+
<div class="x_content">
25+
<div class="form-horizontal">
26+
<div class="form-body">
27+
<div class="x_content">
28+
<div id="newsitem-grid"></div>
29+
</div>
30+
</div>
31+
</div>
32+
</div>
33+
</div>
34+
</div>
35+
</div>
36+
<script>
37+
$(document).ready(function () {
38+
$("#newsitem-grid").kendoGrid({
39+
dataSource: {
40+
transport: {
41+
read: {
42+
url: "@Html.Raw(Url.Action("List", "News", new { area = Constants.AreaStore }))",
43+
type: "POST",
44+
dataType: "json",
45+
data: additionalData
46+
}
47+
},
48+
schema: {
49+
data: "Data",
50+
total: "Total",
51+
errors: "Errors"
52+
},
53+
error: function(e) {
54+
display_kendoui_grid_error(e);
55+
// Cancel the changes
56+
this.cancelChanges();
57+
},
58+
pageSize: @(adminAreaSettings.DefaultGridPageSize),
59+
serverPaging: true,
60+
serverFiltering: true,
61+
serverSorting: true
62+
},
63+
pageable: {
64+
refresh: true,
65+
pageSizes: [@(adminAreaSettings.GridPageSizes)]
66+
},
67+
editable: {
68+
confirmation: false,
69+
mode: "inline"
70+
},
71+
scrollable: false,
72+
columns: [{
73+
field: "Title",
74+
width: 300,
75+
title: "@Loc["Admin.Content.News.NewsItems.Fields.Title"]",
76+
template: '<a class="k-link" href="Edit/#=Id#">#=kendo.htmlEncode(Title)#</a>',
77+
}, {
78+
field: "Comments",
79+
title: "@Loc["Admin.Content.News.NewsItems.Fields.Comments"]",
80+
width: 200,
81+
template: '<a class="k-link" href="Edit/#=Id#">@Loc["Admin.Content.News.NewsItems.Fields.Comments"] - #=Comments# </a>'
82+
}, {
83+
field: "StartDate",
84+
title: "@Loc["Admin.Content.News.NewsItems.Fields.StartDate"]",
85+
width: 150,
86+
type: "date",
87+
format: "{0:G}"
88+
}, {
89+
field: "EndDate",
90+
title: "@Loc["Admin.Content.News.NewsItems.Fields.EndDate"]",
91+
width: 150,
92+
type: "date",
93+
format: "{0:G}"
94+
}, {
95+
field: "Published",
96+
title: "@Loc["Admin.Content.News.NewsItems.Fields.Published"]",
97+
width: 100,
98+
headerAttributes: { style: "text-align:center" },
99+
attributes: { style: "text-align:center" },
100+
template: '# if(Published) {# <i class="fa fa-check" aria-hidden="true" style="color:green"></i> #} else {# <i class="fa fa-times" aria-hidden="true" style="color:red"></i> #} #'
101+
}, {
102+
field: "CreatedOn",
103+
title: "@Loc["Admin.Content.News.NewsItems.Fields.CreatedOn"]",
104+
width: 200,
105+
type: "date",
106+
format: "{0:G}"
107+
}]
108+
});
109+
});
110+
</script>
111+
<script>
112+
113+
$(document).ready(function () {
114+
//search button
115+
$('#search-newsitem').click(function () {
116+
//search
117+
var grid = $('#newsitem-grid').data('kendoGrid');
118+
grid.dataSource.page(1); //new search. Set page size to 1
119+
//grid.dataSource.read(); we already loaded the grid above using "page" function
120+
return false;
121+
});
122+
});
123+
124+
function additionalData() {
125+
var data = {
126+
SearchNewsTitle: ''
127+
};
128+
addAntiForgeryToken(data);
129+
return data;
130+
}
131+
</script>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
@model NewsItemModel
2+
@inject AdminAreaSettings adminAreaSettings
3+
<vc:admin-widget widget-zone="news_details_comments_list" additional-data="Model"/>
4+
@if (!string.IsNullOrEmpty(Model.Id))
5+
{
6+
<div class="panel panel-default">
7+
<vc:admin-widget widget-zone="news_details_comments_top" additional-data="Model"/>
8+
<div class="panel-body">
9+
<div id="comments-grid"></div>
10+
</div>
11+
<vc:admin-widget widget-zone="news_details_comments_bottom" additional-data="Model"/>
12+
</div>
13+
<script>
14+
$(document).ready(function () {
15+
$("#comments-grid").kendoGrid({
16+
dataSource: {
17+
transport: {
18+
read: {
19+
url: "@Url.Action("Comments", "News", new { filterByNewsItemId = Model.Id, area = Constants.AreaStore })",
20+
type: "POST",
21+
dataType: "json",
22+
data: addAntiForgeryToken
23+
},
24+
destroy: {
25+
url: "@Html.Raw(Url.Action("CommentDelete", "News", new { area = Constants.AreaStore }))",
26+
type: "POST",
27+
dataType: "json",
28+
data: addAntiForgeryToken
29+
}
30+
},
31+
schema: {
32+
data: "Data",
33+
total: "Total",
34+
errors: "Errors",
35+
model: {
36+
id: "Id",
37+
fields: {
38+
//do not implicitly specify all fields
39+
//we do it only for fields which implicitly require it
40+
//otherwise, they'll be formatted wrong way
41+
CreatedOn: {type: "date" }
42+
}
43+
}
44+
},
45+
error: function(e) {
46+
display_kendoui_grid_error(e);
47+
// Cancel the changes
48+
this.cancelChanges();
49+
},
50+
pageSize: @(adminAreaSettings.DefaultGridPageSize),
51+
serverPaging: true,
52+
serverFiltering: true,
53+
serverSorting: true
54+
},
55+
pageable: {
56+
refresh: true,
57+
pageSizes: [@(adminAreaSettings.GridPageSizes)]
58+
},
59+
editable: {
60+
confirmation: true,
61+
mode: "inline"
62+
},
63+
scrollable: false,
64+
columns: [{
65+
field: "CustomerId",
66+
title: "@Loc["Admin.Content.News.Comments.Fields.Customer"]",
67+
width: 200,
68+
template: '<a class="k-link" href="@Url.Action("Edit", "Customer", new { area = Constants.AreaStore })/#=CustomerId#">#:kendo.htmlEncode(CustomerInfo)#</a>'
69+
}, {
70+
field: "CommentTitle",
71+
title: "@Loc["Admin.Content.News.Comments.Fields.CommentTitle"]"
72+
}, {
73+
field: "CommentText",
74+
title: "@Loc["Admin.Content.News.Comments.Fields.CommentText"]",
75+
encoded: false
76+
}, {
77+
field: "CreatedOn",
78+
title: "@Loc["Admin.Content.News.Comments.Fields.CreatedOn"]",
79+
width: 200,
80+
type: "date",
81+
format: "{0:G}"
82+
}, {
83+
command: { name: "destroy", text: "@Loc["Admin.Common.Delete"]" },
84+
title: "@Loc["Admin.Common.Delete"]",
85+
width: 100
86+
}]
87+
});
88+
});
89+
</script>
90+
}
91+
else
92+
{
93+
<div class="note note-info">
94+
@Loc["Admin.Content.News.NewsItems.SaveBeforeEdit"]
95+
</div>
96+
}

0 commit comments

Comments
 (0)