Merge pull request #1709 from umbraco/temp-U4-9435-2

U4-9435 Fix breaking change made in U4-9312
This commit is contained in:
Claus
2017-01-27 09:05:47 +01:00
committed by GitHub
5 changed files with 208 additions and 51 deletions

View File

@@ -262,7 +262,7 @@ namespace Umbraco.Web.Editors
},
{
"mediaTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaTypeController>(
controller => controller.GetAllowedChildren("0"))
controller => controller.GetAllowedChildren(0))
},
{
"macroApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MacroController>(

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Http;
@@ -27,6 +28,7 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using System.Linq;
using System.Runtime.Serialization;
using System.Web.Http.Controllers;
using Umbraco.Web.WebApi.Binders;
using Umbraco.Web.WebApi.Filters;
using umbraco;
@@ -45,9 +47,22 @@ namespace Umbraco.Web.Editors
/// access to ALL of the methods on this controller will need access to the media application.
/// </remarks>
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Media)]
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
[MediaControllerControllerConfiguration]
public class MediaController : ContentControllerBase
{
/// <summary>
/// Configures this controller with a custom action selector
/// </summary>
private class MediaControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetChildren", "id", typeof(int), typeof(Guid), typeof(string))));
}
}
/// <summary>
/// Constructor
/// </summary>
@@ -173,40 +188,10 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Returns the child media objects
/// Returns the child media objects - using the entity INT id
/// </summary>
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(string id,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
int idInt; Guid idGuid;
if (Guid.TryParse(id, out idGuid))
{
var entity = Services.EntityService.GetByKey(idGuid);
if (entity != null)
{
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
else if (int.TryParse(id, out idInt))
{
return GetChildren(idInt, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
private PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(int id,
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(int id,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
@@ -240,6 +225,58 @@ namespace Umbraco.Web.Editors
return pagedResult;
}
/// <summary>
/// Returns the child media objects - using the entity GUID id
/// </summary>
/// <param name="id"></param>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="orderBySystemField"></param>
/// <param name="filter"></param>
/// <returns></returns>
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(Guid id,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
var entity = Services.EntityService.GetByKey(id);
if (entity != null)
{
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
[Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(string id,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
foreach (var type in new[] { typeof(int), typeof(Guid) })
{
var parsed = id.TryConvertTo(type);
if (parsed)
{
//oooh magic! will auto select the right overload
return GetChildren((dynamic)parsed.Result);
}
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
/// <summary>
/// Moves an item to the recycle bin, if it is already there then it will permanently delete it
/// </summary>

View File

@@ -13,6 +13,9 @@ using Umbraco.Web.WebApi;
using Umbraco.Core.Services;
using Umbraco.Core.Models.EntityBase;
using System;
using System.ComponentModel;
using System.Web.Http.Controllers;
using Umbraco.Core;
namespace Umbraco.Web.Editors
{
@@ -26,8 +29,21 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes)]
[EnableOverrideAuthorization]
[MediaTypeControllerControllerConfigurationAttribute]
public class MediaTypeController : ContentTypeControllerBase
{
/// <summary>
/// Configures this controller with a custom action selector
/// </summary>
private class MediaTypeControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetAllowedChildren", "contentId", typeof(int), typeof(Guid), typeof(string))));
}
}
/// <summary>
/// Constructor
/// </summary>
@@ -172,26 +188,11 @@ namespace Umbraco.Web.Editors
/// <summary>
/// Returns the allowed child content type objects for the content item id passed in
/// Returns the allowed child content type objects for the content item id passed in - based on an INT id
/// </summary>
/// <param name="contentId"></param>
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public IEnumerable<ContentTypeBasic> GetAllowedChildren(string contentId)
{
Guid idGuid = Guid.Empty;
int idInt;
if (Guid.TryParse(contentId, out idGuid)) {
var entity = ApplicationContext.Services.EntityService.GetByKey(idGuid);
return GetAllowedChildrenInternal(entity.Id);
} else if (int.TryParse(contentId, out idInt))
{
return GetAllowedChildrenInternal(idInt);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
private IEnumerable<ContentTypeBasic> GetAllowedChildrenInternal(int contentId)
public IEnumerable<ContentTypeBasic> GetAllowedChildren(int contentId)
{
if (contentId == Constants.System.RecycleBinContent)
return Enumerable.Empty<ContentTypeBasic>();
@@ -231,6 +232,40 @@ namespace Umbraco.Web.Editors
return basics;
}
/// <summary>
/// Returns the allowed child content type objects for the content item id passed in - based on a GUID id
/// </summary>
/// <param name="contentId"></param>
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public IEnumerable<ContentTypeBasic> GetAllowedChildren(Guid contentId)
{
var entity = ApplicationContext.Services.EntityService.GetByKey(contentId);
if (entity != null)
{
return GetAllowedChildren(entity.Id);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
[Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public IEnumerable<ContentTypeBasic> GetAllowedChildren(string contentId)
{
foreach (var type in new[] { typeof(int), typeof(Guid) })
{
var parsed = contentId.TryConvertTo(type);
if (parsed)
{
//oooh magic! will auto select the right overload
return GetAllowedChildren((dynamic)parsed.Result);
}
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
/// <summary>
/// Move the media type
/// </summary>

View File

@@ -0,0 +1,84 @@
using System;
using System.Linq;
using System.Web;
using System.Web.Http.Controllers;
using Umbraco.Core;
namespace Umbraco.Web.Editors
{
/// <summary>
/// This is used to auto-select specific actions on controllers that would otherwise be ambiguous based on a single parameter type
/// </summary>
/// <remarks>
/// As an example, lets say we have 2 methods: GetChildren(int id) and GetChildren(Guid id), by default Web Api won't allow this since
/// it won't know what to select, but if this Tuple is passed in new Tuple{string, string}("GetChildren", "id")
/// </remarks>
internal class ParameterSwapControllerActionSelector : ApiControllerActionSelector
{
private readonly ParameterSwapInfo[] _actions;
/// <summary>
/// Constructor accepting a list of action name + parameter name
/// </summary>
/// <param name="actions"></param>
public ParameterSwapControllerActionSelector(params ParameterSwapInfo[] actions)
{
_actions = actions;
}
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var found = _actions.FirstOrDefault(x => controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Path).InvariantEndsWith(x.ActionName));
if (found != null)
{
var id = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).Get(found.ParamName);
if (id != null)
{
var idTypes = found.SupportedTypes;
foreach (var idType in idTypes)
{
var converted = id.TryConvertTo(idType);
if (converted)
{
var method = MatchByType(idType, controllerContext, found);
if (method != null)
return method;
}
}
}
}
return base.SelectAction(controllerContext);
}
private static ReflectedHttpActionDescriptor MatchByType(Type idType, HttpControllerContext controllerContext, ParameterSwapInfo found)
{
var controllerType = controllerContext.Controller.GetType();
var methods = controllerType.GetMethods().Where(info => info.Name == found.ActionName).ToArray();
if (methods.Length > 1)
{
//choose the one that has the parameter with the T type
var method = methods.FirstOrDefault(x => x.GetParameters().FirstOrDefault(p => p.Name == found.ParamName && p.ParameterType == idType) != null);
return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method);
}
return null;
}
internal class ParameterSwapInfo
{
public string ActionName { get; private set; }
public string ParamName { get; private set; }
public Type[] SupportedTypes { get; private set; }
public ParameterSwapInfo(string actionName, string paramName, params Type[] supportedTypes)
{
ActionName = actionName;
ParamName = paramName;
SupportedTypes = supportedTypes;
}
}
}
}

View File

@@ -278,6 +278,7 @@
<Compile Include="Editors\EditorValidationResolver.cs" />
<Compile Include="Editors\EditorValidator.cs" />
<Compile Include="Editors\GravatarController.cs" />
<Compile Include="Editors\ParameterSwapControllerActionSelector.cs" />
<Compile Include="HealthCheck\Checks\Config\AbstractConfigCheck.cs" />
<Compile Include="HealthCheck\Checks\Config\AcceptableConfiguration.cs" />
<Compile Include="HealthCheck\Checks\Config\ConfigurationService.cs" />