diff --git a/src/Tests/Grand.Web.Admin.Tests/Controllers/CreateActionPermissionTests.cs b/src/Tests/Grand.Web.Admin.Tests/Controllers/CreateActionPermissionTests.cs new file mode 100644 index 000000000..9f2a279e2 --- /dev/null +++ b/src/Tests/Grand.Web.Admin.Tests/Controllers/CreateActionPermissionTests.cs @@ -0,0 +1,40 @@ +using System.Reflection; +using Grand.Domain.Permissions; +using Grand.Web.Admin.Controllers; +using Grand.Web.AdminShared.Controllers; +using Grand.Web.Common.Security.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Grand.Web.Admin.Tests.Controllers; + +[TestClass] +public class CreateActionPermissionTests +{ + // Opening a create form and submitting it are one operation, so a form that requires + // PermissionActionName.Create has to be submitted under the same action. + [TestMethod] + public void CreateFormPost_RequiresTheSameActionAsItsForm() + { + var forms = new[] { typeof(BaseProductController).Assembly, typeof(VendorController).Assembly } + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => typeof(Controller).IsAssignableFrom(type)) + .SelectMany(type => type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) + .GroupBy(method => $"{method.DeclaringType!.Name}.{method.Name}") + .Where(action => action.Any(method => !IsPost(method) && RequiredAction(method) == PermissionActionName.Create)) + .ToList(); + + var mismatched = forms + .Where(action => action.Any(method => IsPost(method) && RequiredAction(method) != PermissionActionName.Create)) + .Select(action => action.Key) + .ToList(); + + Assert.IsTrue(forms.Any(action => action.Key == "BaseProductController.Create")); + Assert.AreEqual(0, mismatched.Count, string.Join(", ", mismatched)); + } + + private static bool IsPost(MethodInfo method) => method.IsDefined(typeof(HttpPostAttribute), false); + + private static string RequiredAction(MethodInfo method) => + method.GetCustomAttribute()?.PermissionAction; +} diff --git a/src/Web/Grand.Web.Admin/Controllers/AffiliateController.cs b/src/Web/Grand.Web.Admin/Controllers/AffiliateController.cs index 882c0ade5..211ac25f7 100644 --- a/src/Web/Grand.Web.Admin/Controllers/AffiliateController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/AffiliateController.cs @@ -72,7 +72,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(AffiliateModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.Admin/Controllers/CampaignController.cs b/src/Web/Grand.Web.Admin/Controllers/CampaignController.cs index 377bd9da3..a59367da1 100644 --- a/src/Web/Grand.Web.Admin/Controllers/CampaignController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/CampaignController.cs @@ -134,7 +134,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(CampaignModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.Admin/Controllers/CourseController.cs b/src/Web/Grand.Web.Admin/Controllers/CourseController.cs index f15c3edbe..2c8538ce2 100644 --- a/src/Web/Grand.Web.Admin/Controllers/CourseController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/CourseController.cs @@ -145,7 +145,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(CourseModel model, bool continueEditing) @@ -367,7 +367,7 @@ public async Task CreateLesson(string courseId) return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task CreateLesson(CourseLessonModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.Admin/Controllers/CustomerGroupController.cs b/src/Web/Grand.Web.Admin/Controllers/CustomerGroupController.cs index a4a3eefa8..b80f51ee6 100644 --- a/src/Web/Grand.Web.Admin/Controllers/CustomerGroupController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/CustomerGroupController.cs @@ -85,7 +85,7 @@ public IActionResult Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(CustomerGroupModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.Admin/Controllers/DocumentController.cs b/src/Web/Grand.Web.Admin/Controllers/DocumentController.cs index 53ab4bfd9..00a7aa2bb 100644 --- a/src/Web/Grand.Web.Admin/Controllers/DocumentController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/DocumentController.cs @@ -71,7 +71,7 @@ public async Task CreateDocument(SimpleDocumentModel simpleModel) return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task CreateDocument(DocumentModel model, bool continueEditing) @@ -170,7 +170,7 @@ public IActionResult CreateType() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task CreateType(DocumentTypeModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.Admin/Controllers/KnowledgebaseController.cs b/src/Web/Grand.Web.Admin/Controllers/KnowledgebaseController.cs index ec6a7e26a..336124aa1 100644 --- a/src/Web/Grand.Web.Admin/Controllers/KnowledgebaseController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/KnowledgebaseController.cs @@ -79,7 +79,7 @@ public async Task CreateCategory() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task CreateCategory(KnowledgebaseCategoryModel model, bool continueEditing) @@ -182,7 +182,7 @@ public async Task CreateArticle(string parentCategoryId) return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task CreateArticle(KnowledgebaseArticleModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.Admin/Controllers/VendorController.cs b/src/Web/Grand.Web.Admin/Controllers/VendorController.cs index f307da286..b0b0f8198 100644 --- a/src/Web/Grand.Web.Admin/Controllers/VendorController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/VendorController.cs @@ -116,7 +116,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(VendorModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseBlogController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseBlogController.cs index 3634c6c57..070ff3140 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseBlogController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseBlogController.cs @@ -91,7 +91,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(BlogPostModel model, bool continueEditing) @@ -252,7 +252,7 @@ public async Task CategoryCreate() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task CategoryCreate(BlogCategoryModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseBrandController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseBrandController.cs index 7e581678d..6d2b6b928 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseBrandController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseBrandController.cs @@ -106,7 +106,7 @@ public async Task Create([FromServices] CatalogSettings catalogSe return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(BrandModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseCategoryController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseCategoryController.cs index df2203892..e69088955 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseCategoryController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseCategoryController.cs @@ -84,7 +84,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(CategoryModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseCollectionController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseCollectionController.cs index c1fd03525..ce23f83a6 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseCollectionController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseCollectionController.cs @@ -107,7 +107,7 @@ public async Task Create([FromServices] CatalogSettings catalogSe return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(CollectionModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseNewsController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseNewsController.cs index 6acfef0a7..c9a586b84 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseNewsController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseNewsController.cs @@ -81,7 +81,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(NewsItemModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BasePageController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BasePageController.cs index 5ff9b9e1a..358d75e73 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BasePageController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BasePageController.cs @@ -90,7 +90,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(PageModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseProductController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseProductController.cs index 8b5bbc758..8d42247c9 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseProductController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseProductController.cs @@ -89,7 +89,7 @@ public async Task Create() return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task Create(ProductModel model, bool continueEditing) diff --git a/src/Web/Grand.Web.AdminShared/Controllers/BaseShipmentController.cs b/src/Web/Grand.Web.AdminShared/Controllers/BaseShipmentController.cs index af5bb6967..e0777223a 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseShipmentController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseShipmentController.cs @@ -180,7 +180,7 @@ public async Task AddShipment(string orderId) return View(model); } - [PermissionAuthorizeAction(PermissionActionName.Edit)] + [PermissionAuthorizeAction(PermissionActionName.Create)] [HttpPost] [ArgumentNameFilter(KeyName = "save-continue", Argument = "continueEditing")] public async Task AddShipment(AddShipmentModel model, bool continueEditing)