Merge pull request #9486 from Matthew-Wise/feature/8264-typefilters-OutgoingEditorModelEventAttribute

Converted  OutgoingEditorModelEventAttribute to a type filter
This commit is contained in:
Bjarke Berg
2020-12-03 19:08:46 +01:00
committed by GitHub
6 changed files with 90 additions and 76 deletions

View File

@@ -149,7 +149,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <param name="ids"></param>
/// <returns></returns>
[FilterAllowedOutgoingContent(typeof(IEnumerable<ContentItemDisplay>))]
public IEnumerable<ContentItemDisplay> GetByIds([FromQuery]int[] ids)
public IEnumerable<ContentItemDisplay> GetByIds([FromQuery] int[] ids)
{
var foundContent = _contentService.GetByIds(ids);
return foundContent.Select(MapToDisplay);
@@ -164,7 +164,8 @@ namespace Umbraco.Web.BackOffice.Controllers
/// Permission check is done for letter 'R' which is for <see cref="ActionRights"/> which the user must have access to update
/// </remarks>
public async Task<ActionResult<IEnumerable<AssignedUserGroupPermissions>>> PostSaveUserGroupPermissions(UserGroupPermissionsSave saveModel)
{ if (saveModel.ContentId <= 0) return NotFound();
{
if (saveModel.ContentId <= 0) return NotFound();
// TODO: Should non-admins be allowed to set granular permissions?
@@ -347,7 +348,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <param name="id"></param>
/// <param name="culture"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
[DetermineAmbiguousActionByPassingParameters]
public ContentItemDisplay GetById(int id)
@@ -367,7 +368,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
[DetermineAmbiguousActionByPassingParameters]
public ContentItemDisplay GetById(Guid id)
@@ -388,7 +389,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
[DetermineAmbiguousActionByPassingParameters]
public ContentItemDisplay GetById(Udi id)
@@ -407,7 +408,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <param name="parentId"></param>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[DetermineAmbiguousActionByPassingParameters]
public ContentItemDisplay GetEmpty(string contentTypeAlias, int parentId)
{
@@ -426,7 +427,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="contentTypeKey"></param>
/// <param name="parentId"></param>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public ContentItemDisplay GetEmptyByKey(Guid contentTypeKey, int parentId)
{
var contentType = _contentTypeService.Get(contentTypeKey);
@@ -454,7 +455,7 @@ namespace Umbraco.Web.BackOffice.Controllers
return mapped;
}
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[DetermineAmbiguousActionByPassingParameters]
public ContentItemDisplay GetEmpty(int blueprintId, int parentId)
{
@@ -598,7 +599,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <param name="name">The name of the blueprint</param>
/// <returns></returns>
[HttpPost]
public ActionResult<SimpleNotificationModel> CreateBlueprintFromContent([FromQuery]int contentId, [FromQuery]string name)
public ActionResult<SimpleNotificationModel> CreateBlueprintFromContent([FromQuery] int contentId, [FromQuery] string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Value cannot be null or whitespace.", nameof(name));
@@ -632,32 +633,32 @@ namespace Umbraco.Web.BackOffice.Controllers
}
}
/// <summary>
/// Saves content
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
[ContentSaveValidation]
public async Task<ContentItemDisplay> PostSaveBlueprint([ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem)
{
var contentItemDisplay = await PostSaveInternal(contentItem,
content =>
{
EnsureUniqueName(content.Name, content, "Name");
/// <summary>
/// Saves content
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
[ContentSaveValidation]
public async Task<ContentItemDisplay> PostSaveBlueprint([ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem)
{
var contentItemDisplay = await PostSaveInternal(contentItem,
content =>
{
EnsureUniqueName(content.Name, content, "Name");
_contentService.SaveBlueprint(contentItem.PersistedContent, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Id);
_contentService.SaveBlueprint(contentItem.PersistedContent, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Id);
//we need to reuse the underlying logic so return the result that it wants
return OperationResult.Succeed(new EventMessages());
},
content =>
{
var display = MapToDisplay(content);
SetupBlueprint(display, content);
return display;
});
},
content =>
{
var display = MapToDisplay(content);
SetupBlueprint(display, content);
return display;
});
return contentItemDisplay;
}
return contentItemDisplay;
}
/// <summary>
/// Saves content
@@ -665,7 +666,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <returns></returns>
[FileUploadCleanupFilter]
[ContentSaveValidation]
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public async Task<ContentItemDisplay> PostSave([ModelBinder(typeof(ContentItemBinder))] ContentItemSave contentItem)
{
var contentItemDisplay = await PostSaveInternal(
@@ -1459,7 +1460,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <returns></returns>
private string GetVariantName(string culture, string segment)
{
if(culture.IsNullOrWhiteSpace() && segment.IsNullOrWhiteSpace())
if (culture.IsNullOrWhiteSpace() && segment.IsNullOrWhiteSpace())
{
// TODO: Get name for default variant from somewhere?
return "Default";
@@ -1677,7 +1678,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="model">The content and variants to unpublish</param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public async Task<ActionResult<ContentItemDisplay>> PostUnpublish(UnpublishContent model)
{
var foundContent = _contentService.GetById(model.Id);
@@ -1685,7 +1686,7 @@ namespace Umbraco.Web.BackOffice.Controllers
if (foundContent == null)
{
HandleContentNotFound(model.Id);
}
}
// Authorize...
var resource = new ContentPermissionsResource(foundContent, ActionUnpublish.ActionLetter);
@@ -2309,7 +2310,7 @@ namespace Umbraco.Web.BackOffice.Controllers
return notifications;
}
public IActionResult PostNotificationOptions(int contentId, [FromQuery(Name="notifyOptions[]")] string[] notifyOptions)
public IActionResult PostNotificationOptions(int contentId, [FromQuery(Name = "notifyOptions[]")] string[] notifyOptions)
{
if (contentId <= 0) return NotFound();
var content = _contentService.GetById(contentId);
@@ -2459,7 +2460,7 @@ namespace Umbraco.Web.BackOffice.Controllers
// set up public access using role based access
[Authorize(Policy = AuthorizationPolicies.ContentPermissionProtectById)]
[HttpPost]
public IActionResult PostPublicAccess(int contentId, [FromQuery(Name = "groups[]")]string[] groups, [FromQuery(Name = "usernames[]")]string[] usernames, int loginPageId, int errorPageId)
public IActionResult PostPublicAccess(int contentId, [FromQuery(Name = "groups[]")] string[] groups, [FromQuery(Name = "usernames[]")] string[] usernames, int loginPageId, int errorPageId)
{
if ((groups == null || groups.Any() == false) && (usernames == null || usernames.Any() == false))
{
@@ -2520,7 +2521,7 @@ namespace Umbraco.Web.BackOffice.Controllers
}
return _publicAccessService.Save(entry).Success
? (IActionResult) Ok()
? (IActionResult)Ok()
: Problem();
}
@@ -2541,7 +2542,7 @@ namespace Umbraco.Web.BackOffice.Controllers
}
return _publicAccessService.Delete(entry).Success
? (IActionResult) Ok()
? (IActionResult)Ok()
: Problem();
}
}

View File

@@ -210,7 +210,7 @@ namespace Umbraco.Web.BackOffice.Controllers
// return IDashboardSlim - we don't need sections nor access rules
[ValidateAngularAntiForgeryToken]
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public IEnumerable<Tab<IDashboardSlim>> GetDashboard(string section)
{
var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;

View File

@@ -122,7 +122,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <param name="contentTypeAlias"></param>
/// <param name="parentId"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public MediaItemDisplay GetEmpty(string contentTypeAlias, int parentId)
{
var contentType = _mediaTypeService.Get(contentTypeAlias);
@@ -170,7 +170,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.MediaPermissionPathById)]
[DetermineAmbiguousActionByPassingParameters]
public MediaItemDisplay GetById(int id)
@@ -191,7 +191,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.MediaPermissionPathById)]
[DetermineAmbiguousActionByPassingParameters]
public MediaItemDisplay GetById(Guid id)
@@ -212,7 +212,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.MediaPermissionPathById)]
[DetermineAmbiguousActionByPassingParameters]
public MediaItemDisplay GetById(Udi id)
@@ -513,7 +513,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// <returns></returns>
[FileUploadCleanupFilter]
[MediaItemSaveValidation]
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public MediaItemDisplay PostSave(
[ModelBinder(typeof(MediaItemBinder))]
MediaItemSave contentItem)

View File

@@ -151,7 +151,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public MemberDisplay GetByKey(Guid key)
{
var foundMember = _memberService.GetByKey(key);
@@ -167,7 +167,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public MemberDisplay GetEmpty(string contentTypeAlias = null)
{
IMember emptyContent;
@@ -194,7 +194,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[MemberSaveValidation]
public async Task<ActionResult<MemberDisplay>> PostSave(
[ModelBinder(typeof(MemberBinder))]

View File

@@ -224,7 +224,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public UserDisplay GetById(int id)
{
@@ -242,7 +242,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public IEnumerable<UserDisplay> GetByIds([FromJsonPath]int[] ids)
{
@@ -577,7 +577,7 @@ namespace Umbraco.Web.BackOffice.Controllers
/// </summary>
/// <param name="userSave"></param>
/// <returns></returns>
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
[OutgoingEditorModelEvent]
public UserDisplay PostSaveUser(UserSave userSave)
{
if (userSave == null) throw new ArgumentNullException(nameof(userSave));

View File

@@ -4,47 +4,60 @@ using Microsoft.AspNetCore.Mvc.Filters;
using Umbraco.Core;
using Umbraco.Core.Security;
using Umbraco.Web.Editors;
using Umbraco.Web.Security;
namespace Umbraco.Web.BackOffice.Filters
{
/// <summary>
/// Used to emit outgoing editor model events
/// </summary>
internal sealed class OutgoingEditorModelEventAttribute : ActionFilterAttribute
internal sealed class OutgoingEditorModelEventAttribute : TypeFilterAttribute
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
public OutgoingEditorModelEventAttribute(IUmbracoContextAccessor umbracoContextAccessor, IBackOfficeSecurityAccessor backofficeSecurityAccessor)
public OutgoingEditorModelEventAttribute() : base(typeof(OutgoingEditorModelEventFilter))
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
}
public override void OnActionExecuted(ActionExecutedContext context)
private class OutgoingEditorModelEventFilter : IActionFilter
{
if (context.Result == null) return;
var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
var user = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
if (user == null) return;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
if (context.Result is ObjectResult objectContent)
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public OutgoingEditorModelEventFilter(
IUmbracoContextAccessor umbracoContextAccessor,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
var model = objectContent.Value;
if (model != null)
{
var args = new EditorModelEventArgs(
model,
umbracoContext);
EditorModelEventManager.EmitEvent(context, args);
objectContent.Value = args.Model;
}
_umbracoContextAccessor = umbracoContextAccessor
?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_backOfficeSecurityAccessor = backOfficeSecurityAccessor
?? throw new ArgumentNullException(nameof(backOfficeSecurityAccessor));
}
base.OnActionExecuted(context);
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Result == null) return;
var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
var user = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
if (user == null) return;
if (context.Result is ObjectResult objectContent)
{
var model = objectContent.Value;
if (model != null)
{
var args = new EditorModelEventArgs(model, umbracoContext);
EditorModelEventManager.EmitEvent(context, args);
objectContent.Value = args.Model;
}
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
}
}
}