OrchardCMS / OrchardCore

Orchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.
https://orchardcore.net
BSD 3-Clause "New" or "Revised" License
7.36k stars 2.37k forks source link

add short-circuit to handlers (removing, unpublishing etc.) #14589

Open lampersky opened 10 months ago

lampersky commented 10 months ago

There are many cases where you could need prevent some DefaultContentManager actions. Using some custom logic. Currently, we can only control the execution of code in a binary way via Permission.

Use case 1: Let's say you have some items selected in many ContentPickerFields, and you would like to prevent user to remove those ContentItems with some user friendly message, like: "you can't remove this ContentItem becasue it is used in at least one ContentPickerField".

Use case 2: Suppose we want to check if a similar ContentItem already exists before creating new one. To avoid duplicates.

I think it would be good to have an option to cancel any of those operations from within those handlers: DraftSavingAsync, PublishingAsync, UnpublishingAsync, CreatingAsync, UpdatingAsync, RestoringAsync, RemovingAsync, CloningAsync.

I'm thinking about something like this (pseudo code):

(change in DefaultContentManger) image

(change in AdminController) image

(example use) image

(example of short-circuit on RemovingAsync) image image

Of course, there are much more places to change, but I just wanted to better explain my idea.

/cc: @jtkech I am curious about your opinion.

sebastienros commented 10 months ago

It's like the behavior for UpdateAsync where we manage errors with the ModelState: https://github.com/OrchardCMS/OrchardCore/blob/5a472d483fc360d1e1aa69dc7e098be6a038e62c/src/OrchardCore.Modules/OrchardCore.ContentFields/Drivers/TextFieldDisplayDriver.cs#L56C101-L56C101

So maybe not return a result type, but use a custom context object to add errors on it. The error messages should not come from the controller (like it's done in your examples).

To make it a non-breaking change it could be on new overloads.