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 e8671dd2d..460ca347f 100644 --- a/src/Web/Grand.Web.Admin/Controllers/AffiliateController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/AffiliateController.cs @@ -73,7 +73,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 9ccc2cc18..a5988990a 100644 --- a/src/Web/Grand.Web.Admin/Controllers/CampaignController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/CampaignController.cs @@ -133,7 +133,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 e07575649..a0963e667 100644 --- a/src/Web/Grand.Web.Admin/Controllers/CourseController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/CourseController.cs @@ -144,7 +144,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) @@ -366,7 +366,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 f770079de..550fe985d 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 a9ab6cbf2..f82cf1179 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 918ddd940..52977b06c 100644 --- a/src/Web/Grand.Web.Admin/Controllers/KnowledgebaseController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/KnowledgebaseController.cs @@ -78,7 +78,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) @@ -181,7 +181,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 f289b6064..29863d330 100644 --- a/src/Web/Grand.Web.Admin/Controllers/VendorController.cs +++ b/src/Web/Grand.Web.Admin/Controllers/VendorController.cs @@ -115,7 +115,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 49e32ed2d..8d17a48b6 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseBlogController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseBlogController.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(BlogPostModel model, bool continueEditing) @@ -251,7 +251,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 b778d4ae3..8d8736f8b 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseBrandController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseBrandController.cs @@ -104,7 +104,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 50fda8d85..aca3237d9 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseCategoryController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseCategoryController.cs @@ -82,7 +82,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 41ab27700..28badd437 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseCollectionController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseCollectionController.cs @@ -105,7 +105,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 be7eefaf7..f04f4c33d 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseNewsController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseNewsController.cs @@ -80,7 +80,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 c09115395..3c8d5934a 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BasePageController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BasePageController.cs @@ -88,7 +88,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 28c5c8b70..f7b7ce505 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseProductController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseProductController.cs @@ -96,7 +96,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 1013b42fc..4919c54bf 100644 --- a/src/Web/Grand.Web.AdminShared/Controllers/BaseShipmentController.cs +++ b/src/Web/Grand.Web.AdminShared/Controllers/BaseShipmentController.cs @@ -164,7 +164,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)