2018-06-29 19:52:40 +02:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2019-12-20 17:36:44 +01:00
using System.Linq ;
2018-06-29 19:52:40 +02:00
using System.Net ;
using System.Net.Http ;
using System.Text ;
using System.Threading.Tasks ;
2020-06-12 15:58:53 +02:00
using Microsoft.AspNetCore.Mvc ;
2018-06-29 19:52:40 +02:00
using Umbraco.Core ;
using Umbraco.Core.IO ;
using Umbraco.Core.Logging ;
using Umbraco.Core.Models ;
using Umbraco.Core.Models.Membership ;
using Umbraco.Core.Services ;
using Umbraco.Web.Models.ContentEditing ;
using Umbraco.Core.Configuration.UmbracoSettings ;
2019-12-20 17:36:44 +01:00
using Umbraco.Core.Dictionary ;
2020-06-12 15:58:53 +02:00
using Umbraco.Core.Events ;
2018-09-20 17:22:39 +02:00
using Umbraco.Core.Models.ContentEditing ;
2018-06-29 19:52:40 +02:00
using Umbraco.Core.Models.Editors ;
2019-12-20 17:36:44 +01:00
using Umbraco.Core.Models.Entities ;
2018-06-29 19:52:40 +02:00
using Umbraco.Core.Models.Validation ;
2019-12-20 17:36:44 +01:00
using Umbraco.Core.Persistence ;
using Umbraco.Core.Persistence.Querying ;
2018-07-17 14:23:07 +10:00
using Umbraco.Core.PropertyEditors ;
2018-09-20 17:22:39 +02:00
using Umbraco.Web.ContentApps ;
2019-12-20 17:36:44 +01:00
using Umbraco.Web.WebApi.Filters ;
2019-11-05 13:45:42 +01:00
using Constants = Umbraco . Core . Constants ;
2020-01-20 14:15:54 -08:00
using Umbraco.Core.Mapping ;
2020-06-12 15:58:53 +02:00
using Umbraco.Core.Strings ;
using Umbraco.Extensions ;
using Umbraco.Web.BackOffice.Controllers ;
using Umbraco.Web.BackOffice.Filters ;
using Umbraco.Web.Common.Attributes ;
using Umbraco.Web.Common.Exceptions ;
using Umbraco.Web.Editors.Binders ;
using Umbraco.Web.Security ;
2018-06-29 19:52:40 +02:00
namespace Umbraco.Web.Editors
{
/// <remarks>
/// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
/// access to ALL of the methods on this controller will need access to the media application.
/// </remarks>
[PluginController("UmbracoApi")]
2019-11-05 13:45:42 +01:00
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
2018-06-29 19:52:40 +02:00
public class MediaController : ContentControllerBase
{
2020-03-12 15:30:22 +01:00
private readonly IContentSettings _contentSettings ;
2020-02-10 11:23:23 +01:00
private readonly IIOHelper _ioHelper ;
2020-06-12 15:58:53 +02:00
private readonly IMediaTypeService _mediaTypeService ;
private readonly IMediaService _mediaService ;
private readonly IEntityService _entityService ;
private readonly IWebSecurity _webSecurity ;
private readonly UmbracoMapper _umbracoMapper ;
private readonly IDataTypeService _dataTypeService ;
private readonly ILocalizedTextService _localizedTextService ;
private readonly ISqlContext _sqlContext ;
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider ;
private readonly IRelationService _relationService ;
2019-12-18 13:38:03 +01:00
public MediaController (
ICultureDictionary cultureDictionary ,
2020-06-12 15:58:53 +02:00
ILogger logger ,
2020-01-20 14:15:54 -08:00
IShortStringHelper shortStringHelper ,
2020-06-12 15:58:53 +02:00
IEventMessagesFactory eventMessages ,
ILocalizedTextService localizedTextService ,
2020-03-12 15:30:22 +01:00
IContentSettings contentSettings ,
2020-02-14 13:04:49 +01:00
IIOHelper ioHelper ,
2020-06-12 15:58:53 +02:00
IMediaTypeService mediaTypeService ,
IMediaService mediaService ,
IEntityService entityService ,
IWebSecurity webSecurity ,
UmbracoMapper umbracoMapper ,
IDataTypeService dataTypeService ,
ISqlContext sqlContext ,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider ,
IRelationService relationService ,
PropertyEditorCollection propertyEditors ,
IMediaFileSystem mediaFileSystem )
: base ( cultureDictionary , logger , shortStringHelper , eventMessages , localizedTextService )
2018-07-17 14:23:07 +10:00
{
2020-06-12 15:58:53 +02:00
_contentSettings = contentSettings ;
_ioHelper = ioHelper ;
_mediaTypeService = mediaTypeService ;
_mediaService = mediaService ;
_entityService = entityService ;
_webSecurity = webSecurity ;
_umbracoMapper = umbracoMapper ;
_dataTypeService = dataTypeService ;
_localizedTextService = localizedTextService ;
_sqlContext = sqlContext ;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider ;
_relationService = relationService ;
_propertyEditors = propertyEditors ;
2019-12-18 13:38:03 +01:00
_mediaFileSystem = mediaFileSystem ;
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets an empty content item for the
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <param name="parentId"></param>
/// <returns></returns>
2020-05-20 08:39:27 +02:00
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
2018-06-29 19:52:40 +02:00
public MediaItemDisplay GetEmpty ( string contentTypeAlias , int parentId )
{
2020-06-12 15:58:53 +02:00
var contentType = _mediaTypeService . Get ( contentTypeAlias ) ;
2018-06-29 19:52:40 +02:00
if ( contentType = = null )
{
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
2020-06-12 15:58:53 +02:00
var emptyContent = _mediaService . CreateMedia ( "" , parentId , contentType . Alias , _webSecurity . GetUserId ( ) . ResultOr ( Constants . Security . SuperUserId ) ) ;
var mapped = _umbracoMapper . Map < MediaItemDisplay > ( emptyContent ) ;
2018-06-29 19:52:40 +02:00
2018-07-13 12:45:04 +10:00
//remove the listview app if it exists
2018-09-14 10:53:59 +01:00
mapped . ContentApps = mapped . ContentApps . Where ( x = > x . Alias ! = "umbListView" ) . ToList ( ) ;
2018-07-13 12:45:04 +10:00
2018-06-29 19:52:40 +02:00
return mapped ;
}
/// <summary>
/// Returns an item to be used to display the recycle bin for media
/// </summary>
/// <returns></returns>
2018-07-13 12:45:04 +10:00
public MediaItemDisplay GetRecycleBin ( )
2018-06-29 19:52:40 +02:00
{
2018-07-17 14:23:07 +10:00
var apps = new List < ContentApp > ( ) ;
2020-06-12 15:58:53 +02:00
apps . Add ( ListViewContentAppFactory . CreateContentApp ( _dataTypeService , _propertyEditors , "recycleBin" , "media" , Core . Constants . DataTypes . DefaultMediaListView ) ) ;
2018-07-17 14:23:07 +10:00
apps [ 0 ] . Active = true ;
2018-07-13 12:45:04 +10:00
var display = new MediaItemDisplay
2018-06-29 19:52:40 +02:00
{
2019-11-05 13:45:42 +01:00
Id = Constants . System . RecycleBinMedia ,
2018-06-29 19:52:40 +02:00
Alias = "recycleBin" ,
ParentId = - 1 ,
2020-06-12 15:58:53 +02:00
Name = _localizedTextService . Localize ( "general/recycleBin" ) ,
2018-06-29 19:52:40 +02:00
ContentTypeAlias = "recycleBin" ,
CreateDate = DateTime . Now ,
IsContainer = true ,
2019-11-05 13:45:42 +01:00
Path = "-1," + Constants . System . RecycleBinMedia ,
2018-07-17 14:23:07 +10:00
ContentApps = apps
2018-06-29 19:52:40 +02:00
} ;
return display ;
}
/// <summary>
/// Gets the media item by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
2020-05-20 08:39:27 +02:00
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
2018-06-29 19:52:40 +02:00
[EnsureUserPermissionForMedia("id")]
2020-06-12 15:58:53 +02:00
[DetermineAmbiguousActionByPassingParameters]
2018-06-29 19:52:40 +02:00
public MediaItemDisplay GetById ( int id )
{
2020-06-12 15:58:53 +02:00
var foundContent = GetObjectFromRequest ( ( ) = > _mediaService . GetById ( id ) ) ;
2018-06-29 19:52:40 +02:00
if ( foundContent = = null )
{
HandleContentNotFound ( id ) ;
//HandleContentNotFound will throw an exception
return null ;
}
2020-06-12 15:58:53 +02:00
return _umbracoMapper . Map < MediaItemDisplay > ( foundContent ) ;
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the media item by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
2020-05-20 08:39:27 +02:00
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
2018-06-29 19:52:40 +02:00
[EnsureUserPermissionForMedia("id")]
2020-06-12 15:58:53 +02:00
[DetermineAmbiguousActionByPassingParameters]
2018-06-29 19:52:40 +02:00
public MediaItemDisplay GetById ( Guid id )
{
2020-06-12 15:58:53 +02:00
var foundContent = GetObjectFromRequest ( ( ) = > _mediaService . GetById ( id ) ) ;
2018-06-29 19:52:40 +02:00
if ( foundContent = = null )
{
HandleContentNotFound ( id ) ;
//HandleContentNotFound will throw an exception
return null ;
}
2020-06-12 15:58:53 +02:00
return _umbracoMapper . Map < MediaItemDisplay > ( foundContent ) ;
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Gets the media item by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
2020-05-20 08:39:27 +02:00
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
2018-06-29 19:52:40 +02:00
[EnsureUserPermissionForMedia("id")]
2020-06-12 15:58:53 +02:00
[DetermineAmbiguousActionByPassingParameters]
2018-06-29 19:52:40 +02:00
public MediaItemDisplay GetById ( Udi id )
{
var guidUdi = id as GuidUdi ;
if ( guidUdi ! = null )
{
return GetById ( guidUdi . Guid ) ;
}
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
/// <summary>
/// Return media for the specified ids
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
2020-06-09 13:48:50 +02:00
//[FilterAllowedOutgoingMedia(typeof(IEnumerable<MediaItemDisplay>))] // TODO introduce when moved to .NET Core
2020-06-12 15:58:53 +02:00
public IEnumerable < MediaItemDisplay > GetByIds ( [ FromQuery ] int [ ] ids )
2018-06-29 19:52:40 +02:00
{
2020-06-12 15:58:53 +02:00
var foundMedia = _mediaService . GetByIds ( ids ) ;
return foundMedia . Select ( media = > _umbracoMapper . Map < MediaItemDisplay > ( media ) ) ;
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Returns a paged result of media items known to be of a "Folder" type
/// </summary>
/// <param name="id"></param>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
2018-08-01 15:40:54 +10:00
public PagedResult < ContentItemBasic < ContentPropertyBasic > > GetChildFolders ( int id , int pageNumber = 1 , int pageSize = 1000 )
2018-06-29 19:52:40 +02:00
{
//Suggested convention for folder mediatypes - we can make this more or less complicated as long as we document it...
//if you create a media type, which has an alias that ends with ...Folder then its a folder: ex: "secureFolder", "bannerFolder", "Folder"
2020-06-12 15:58:53 +02:00
var folderTypes = _mediaTypeService
2018-06-29 19:52:40 +02:00
. GetAll ( )
. Where ( x = > x . Alias . EndsWith ( "Folder" ) )
. Select ( x = > x . Id )
. ToArray ( ) ;
if ( folderTypes . Length = = 0 )
{
2018-08-01 15:40:54 +10:00
return new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( 0 , pageNumber , pageSize ) ;
2018-06-29 19:52:40 +02:00
}
long total ;
2020-06-12 15:58:53 +02:00
var children = _mediaService . GetPagedChildren ( id , pageNumber - 1 , pageSize , out total ,
2018-11-01 00:21:52 +11:00
//lookup these content types
2020-06-12 15:58:53 +02:00
_sqlContext . Query < IMedia > ( ) . Where ( x = > folderTypes . Contains ( x . ContentTypeId ) ) ,
2018-11-01 00:21:52 +11:00
Ordering . By ( "Name" , Direction . Ascending ) ) ;
2018-06-29 19:52:40 +02:00
2018-08-01 15:40:54 +10:00
return new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( total , pageNumber , pageSize )
2018-06-29 19:52:40 +02:00
{
2020-06-12 15:58:53 +02:00
Items = children . Select ( _umbracoMapper . Map < IMedia , ContentItemBasic < ContentPropertyBasic > > )
2018-06-29 19:52:40 +02:00
} ;
}
/// <summary>
/// Returns the root media objects
/// </summary>
2020-06-09 13:48:50 +02:00
//[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>))] // TODO introduce when moved to .NET Core
2018-08-01 15:40:54 +10:00
public IEnumerable < ContentItemBasic < ContentPropertyBasic > > GetRootMedia ( )
2018-06-29 19:52:40 +02:00
{
2019-01-27 01:17:32 -05:00
// TODO: Add permissions check!
2018-06-29 19:52:40 +02:00
2020-06-12 15:58:53 +02:00
return _mediaService . GetRootMedia ( )
. Select ( _umbracoMapper . Map < IMedia , ContentItemBasic < ContentPropertyBasic > > ) ;
2018-06-29 19:52:40 +02:00
}
#region GetChildren
private int [ ] _userStartNodes ;
2018-07-17 14:23:07 +10:00
private readonly PropertyEditorCollection _propertyEditors ;
2019-12-18 13:38:03 +01:00
private readonly IMediaFileSystem _mediaFileSystem ;
2019-12-18 18:55:00 +01:00
2018-07-17 14:23:07 +10:00
2018-06-29 19:52:40 +02:00
protected int [ ] UserStartNodes
{
2020-06-12 15:58:53 +02:00
get { return _userStartNodes ? ? ( _userStartNodes = _webSecurity . CurrentUser . CalculateMediaStartNodeIds ( _entityService ) ) ; }
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Returns the child media objects - using the entity INT id
/// </summary>
2020-06-12 15:58:53 +02:00
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")] // TODO introduce when moved to .NET Core//[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")]
[DetermineAmbiguousActionByPassingParameters]
2018-08-01 15:40:54 +10:00
public PagedResult < ContentItemBasic < ContentPropertyBasic > > GetChildren ( int id ,
2018-06-29 19:52:40 +02:00
int pageNumber = 0 ,
int pageSize = 0 ,
string orderBy = "SortOrder" ,
Direction orderDirection = Direction . Ascending ,
bool orderBySystemField = true ,
string filter = "" )
{
//if a request is made for the root node data but the user's start node is not the default, then
// we need to return their start nodes
2019-11-05 13:45:42 +01:00
if ( id = = Constants . System . Root & & UserStartNodes . Length > 0 & & UserStartNodes . Contains ( Constants . System . Root ) = = false )
2018-06-29 19:52:40 +02:00
{
if ( pageNumber > 0 )
2018-08-01 15:40:54 +10:00
return new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( 0 , 0 , 0 ) ;
2020-06-12 15:58:53 +02:00
var nodes = _mediaService . GetByIds ( UserStartNodes ) . ToArray ( ) ;
2018-06-29 19:52:40 +02:00
if ( nodes . Length = = 0 )
2018-08-01 15:40:54 +10:00
return new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( 0 , 0 , 0 ) ;
2018-06-29 19:52:40 +02:00
if ( pageSize < nodes . Length ) pageSize = nodes . Length ; // bah
2018-08-01 15:40:54 +10:00
var pr = new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( nodes . Length , pageNumber , pageSize )
2018-06-29 19:52:40 +02:00
{
2020-06-12 15:58:53 +02:00
Items = nodes . Select ( _umbracoMapper . Map < IMedia , ContentItemBasic < ContentPropertyBasic > > )
2018-06-29 19:52:40 +02:00
} ;
return pr ;
}
// else proceed as usual
long totalChildren ;
2018-10-31 23:11:37 +11:00
List < IMedia > children ;
2018-06-29 19:52:40 +02:00
if ( pageNumber > 0 & & pageSize > 0 )
{
IQuery < IMedia > queryFilter = null ;
if ( filter . IsNullOrWhiteSpace ( ) = = false )
{
//add the default text filter
2020-06-12 15:58:53 +02:00
queryFilter = _sqlContext . Query < IMedia > ( )
2018-06-29 19:52:40 +02:00
. Where ( x = > x . Name . Contains ( filter ) ) ;
}
2020-06-12 15:58:53 +02:00
children = _mediaService
2018-06-29 19:52:40 +02:00
. GetPagedChildren (
id , ( pageNumber - 1 ) , pageSize ,
out totalChildren ,
2018-11-01 00:21:52 +11:00
queryFilter ,
Ordering . By ( orderBy , orderDirection , isCustomField : ! orderBySystemField ) ) . ToList ( ) ;
2018-06-29 19:52:40 +02:00
}
else
{
2018-10-31 23:11:37 +11:00
//better to not use this without paging where possible, currently only the sort dialog does
2020-06-12 15:58:53 +02:00
children = _mediaService . GetPagedChildren ( id , 0 , int . MaxValue , out var total ) . ToList ( ) ;
2018-10-31 23:11:37 +11:00
totalChildren = children . Count ;
2018-06-29 19:52:40 +02:00
}
if ( totalChildren = = 0 )
{
2018-08-01 15:40:54 +10:00
return new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( 0 , 0 , 0 ) ;
2018-06-29 19:52:40 +02:00
}
2018-08-01 15:40:54 +10:00
var pagedResult = new PagedResult < ContentItemBasic < ContentPropertyBasic > > ( totalChildren , pageNumber , pageSize ) ;
2018-06-29 19:52:40 +02:00
pagedResult . Items = children
2020-06-12 15:58:53 +02:00
. Select ( _umbracoMapper . Map < IMedia , ContentItemBasic < ContentPropertyBasic > > ) ;
2018-06-29 19:52:40 +02:00
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>
2020-06-12 15:58:53 +02:00
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")]
[DetermineAmbiguousActionByPassingParameters]
2018-08-01 15:40:54 +10:00
public PagedResult < ContentItemBasic < ContentPropertyBasic > > GetChildren ( Guid id ,
2018-06-29 19:52:40 +02:00
int pageNumber = 0 ,
int pageSize = 0 ,
string orderBy = "SortOrder" ,
Direction orderDirection = Direction . Ascending ,
bool orderBySystemField = true ,
string filter = "" )
{
2020-06-12 15:58:53 +02:00
var entity = _entityService . Get ( id ) ;
2018-06-29 19:52:40 +02:00
if ( entity ! = null )
{
2019-06-18 19:18:48 +02:00
return GetChildren ( entity . Id , pageNumber , pageSize , orderBy , orderDirection , orderBySystemField , filter ) ;
2018-06-29 19:52:40 +02:00
}
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
/// <summary>
/// Returns the child media objects - using the entity UDI 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>
2020-06-12 15:58:53 +02:00
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")]
[DetermineAmbiguousActionByPassingParameters]
2018-08-01 15:40:54 +10:00
public PagedResult < ContentItemBasic < ContentPropertyBasic > > GetChildren ( Udi id ,
2018-06-29 19:52:40 +02:00
int pageNumber = 0 ,
int pageSize = 0 ,
string orderBy = "SortOrder" ,
Direction orderDirection = Direction . Ascending ,
bool orderBySystemField = true ,
string filter = "" )
{
var guidUdi = id as GuidUdi ;
if ( guidUdi ! = null )
{
2020-06-12 15:58:53 +02:00
var entity = _entityService . Get ( guidUdi . Guid ) ;
2018-06-29 19:52:40 +02:00
if ( entity ! = null )
{
2019-06-18 19:18:48 +02:00
return GetChildren ( entity . Id , pageNumber , pageSize , orderBy , orderDirection , orderBySystemField , filter ) ;
2018-06-29 19:52:40 +02:00
}
}
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
#endregion
/// <summary>
/// Moves an item to the recycle bin, if it is already there then it will permanently delete it
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[EnsureUserPermissionForMedia("id")]
[HttpPost]
public HttpResponseMessage DeleteById ( int id )
{
2020-06-12 15:58:53 +02:00
var foundMedia = GetObjectFromRequest ( ( ) = > _mediaService . GetById ( id ) ) ;
2018-06-29 19:52:40 +02:00
if ( foundMedia = = null )
{
return HandleContentNotFound ( id , false ) ;
}
//if the current item is in the recycle bin
if ( foundMedia . Trashed = = false )
{
2020-06-12 15:58:53 +02:00
var moveResult = _mediaService . MoveToRecycleBin ( foundMedia , _webSecurity . GetUserId ( ) . ResultOr ( Constants . Security . SuperUserId ) ) ;
2018-06-29 19:52:40 +02:00
if ( moveResult = = false )
{
//returning an object of INotificationModel will ensure that any pending
// notification messages are added to the response.
return Request . CreateValidationErrorResponse ( new SimpleNotificationModel ( ) ) ;
}
}
else
{
2020-06-12 15:58:53 +02:00
var deleteResult = _mediaService . Delete ( foundMedia , _webSecurity . GetUserId ( ) . ResultOr ( Constants . Security . SuperUserId ) ) ;
2018-06-29 19:52:40 +02:00
if ( deleteResult = = false )
{
//returning an object of INotificationModel will ensure that any pending
// notification messages are added to the response.
return Request . CreateValidationErrorResponse ( new SimpleNotificationModel ( ) ) ;
}
}
return Request . CreateResponse ( HttpStatusCode . OK ) ;
}
/// <summary>
/// Change the sort order for media
/// </summary>
/// <param name="move"></param>
/// <returns></returns>
[EnsureUserPermissionForMedia("move.Id")]
public HttpResponseMessage PostMove ( MoveOrCopy move )
{
var toMove = ValidateMoveOrCopy ( move ) ;
2018-11-19 15:32:26 +11:00
var destinationParentID = move . ParentId ;
var sourceParentID = toMove . ParentId ;
2018-12-12 17:49:24 +01:00
2020-06-12 15:58:53 +02:00
var moveResult = _mediaService . Move ( toMove , move . ParentId , _webSecurity . GetUserId ( ) . ResultOr ( Constants . Security . SuperUserId ) ) ;
2018-06-29 19:52:40 +02:00
2018-11-19 15:32:26 +11:00
if ( sourceParentID = = destinationParentID )
{
2020-06-12 15:58:53 +02:00
return Request . CreateValidationErrorResponse ( new SimpleNotificationModel ( new BackOfficeNotification ( "" , _localizedTextService . Localize ( "media/moveToSameFolderFailed" ) , NotificationStyle . Error ) ) ) ;
2018-11-19 15:32:26 +11:00
}
if ( moveResult = = false )
{
return Request . CreateValidationErrorResponse ( new SimpleNotificationModel ( ) ) ;
}
else
{
var response = Request . CreateResponse ( HttpStatusCode . OK ) ;
response . Content = new StringContent ( toMove . Path , Encoding . UTF8 , "text/plain" ) ;
return response ;
}
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Saves content
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
2018-07-19 19:32:07 +10:00
[MediaItemSaveValidation]
2020-05-20 08:39:27 +02:00
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
2018-06-29 19:52:40 +02:00
public MediaItemDisplay PostSave (
[ModelBinder(typeof(MediaItemBinder))]
MediaItemSave contentItem )
{
2019-01-26 10:52:19 -05:00
//Recent versions of IE/Edge may send in the full client side file path instead of just the file name.
2018-10-01 14:32:46 +02:00
//To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all
//uploaded files to being *only* the actual file name (as it should be).
if ( contentItem . UploadedFiles ! = null & & contentItem . UploadedFiles . Any ( ) )
{
foreach ( var file in contentItem . UploadedFiles )
{
file . FileName = Path . GetFileName ( file . FileName ) ;
}
}
2018-06-29 19:52:40 +02:00
//If we've reached here it means:
// * Our model has been bound
// * and validated
// * any file attachments have been saved to their temporary location for us to use
// * we have a reference to the DTO object and the persisted object
// * Permissions are valid
//Don't update the name if it is empty
if ( contentItem . Name . IsNullOrWhiteSpace ( ) = = false )
{
contentItem . PersistedContent . Name = contentItem . Name ;
}
2018-08-02 15:12:26 +10:00
MapPropertyValuesForPersistence < IMedia , MediaItemSave > (
2018-04-04 01:59:51 +10:00
contentItem ,
2018-08-01 16:46:13 +10:00
contentItem . PropertyCollectionDto ,
2018-11-20 13:24:06 +01:00
( save , property ) = > property . GetValue ( ) , //get prop val
( save , property , v ) = > property . SetValue ( v ) , //set prop val
null ) ; // media are all invariant
2018-06-29 19:52:40 +02:00
2019-03-13 18:12:48 +11:00
//we will continue to save if model state is invalid, however we cannot save if critical data is missing.
//TODO: Allowing media to be saved when it is invalid is odd - media doesn't have a publish phase so suddenly invalid data is allowed to be 'live'
if ( ! ModelState . IsValid )
2018-06-29 19:52:40 +02:00
{
2019-03-13 18:12:48 +11:00
//check for critical data validation issues, we can't continue saving if this data is invalid
if ( ! RequiredForPersistenceAttribute . HasRequiredValuesForPersistence ( contentItem ) )
2018-06-29 19:52:40 +02:00
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
2019-01-26 10:52:19 -05:00
// add the model state to the outgoing object and throw validation response
2020-06-12 15:58:53 +02:00
var forDisplay = _umbracoMapper . Map < MediaItemDisplay > ( contentItem . PersistedContent ) ;
2018-06-29 19:52:40 +02:00
forDisplay . Errors = ModelState . ToErrorDictionary ( ) ;
throw new HttpResponseException ( Request . CreateValidationErrorResponse ( forDisplay ) ) ;
}
}
//save the item
2020-06-12 15:58:53 +02:00
var saveStatus = _mediaService . Save ( contentItem . PersistedContent , _webSecurity . GetUserId ( ) . ResultOr ( Constants . Security . SuperUserId ) ) ;
2018-06-29 19:52:40 +02:00
//return the updated model
2020-06-12 15:58:53 +02:00
var display = _umbracoMapper . Map < MediaItemDisplay > ( contentItem . PersistedContent ) ;
2018-06-29 19:52:40 +02:00
2019-01-26 10:52:19 -05:00
//lastly, if it is not valid, add the model state to the outgoing object and throw a 403
2018-06-29 19:52:40 +02:00
HandleInvalidModelState ( display ) ;
//put the correct msgs in
switch ( contentItem . Action )
{
case ContentSaveAction . Save :
case ContentSaveAction . SaveNew :
if ( saveStatus . Success )
{
display . AddSuccessNotification (
2020-06-12 15:58:53 +02:00
_localizedTextService . Localize ( "speechBubbles/editMediaSaved" ) ,
_localizedTextService . Localize ( "speechBubbles/editMediaSavedText" ) ) ;
2018-06-29 19:52:40 +02:00
}
else
{
AddCancelMessage ( display ) ;
//If the item is new and the operation was cancelled, we need to return a different
// status code so the UI can handle it since it won't be able to redirect since there
// is no Id to redirect to!
if ( saveStatus . Result . Result = = OperationResultType . FailedCancelledByEvent & & IsCreatingAction ( contentItem . Action ) )
{
throw new HttpResponseException ( Request . CreateValidationErrorResponse ( display ) ) ;
}
}
break ;
}
return display ;
}
2018-12-12 17:49:24 +01:00
2018-06-29 19:52:40 +02:00
/// <summary>
/// Empties the recycle bin
/// </summary>
/// <returns></returns>
[HttpDelete]
[HttpPost]
public HttpResponseMessage EmptyRecycleBin ( )
{
2020-06-12 15:58:53 +02:00
_mediaService . EmptyRecycleBin ( _webSecurity . GetUserId ( ) . ResultOr ( Constants . Security . SuperUserId ) ) ;
2018-06-29 19:52:40 +02:00
2020-06-12 15:58:53 +02:00
return Request . CreateNotificationSuccessResponse ( _localizedTextService . Localize ( "defaultdialogs/recycleBinIsEmpty" ) ) ;
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Change the sort order for media
/// </summary>
/// <param name="sorted"></param>
/// <returns></returns>
[EnsureUserPermissionForMedia("sorted.ParentId")]
public HttpResponseMessage PostSort ( ContentSortOrder sorted )
{
if ( sorted = = null )
{
return Request . CreateResponse ( HttpStatusCode . NotFound ) ;
}
//if there's nothing to sort just return ok
if ( sorted . IdSortOrder . Length = = 0 )
{
return Request . CreateResponse ( HttpStatusCode . OK ) ;
}
2020-06-12 15:58:53 +02:00
var mediaService = _mediaService ;
2018-06-29 19:52:40 +02:00
var sortedMedia = new List < IMedia > ( ) ;
try
{
sortedMedia . AddRange ( sorted . IdSortOrder . Select ( mediaService . GetById ) ) ;
// Save Media with new sort order and update content xml in db accordingly
if ( mediaService . Sort ( sortedMedia ) = = false )
{
Logger . Warn < MediaController > ( "Media sorting failed, this was probably caused by an event being cancelled" ) ;
return Request . CreateValidationErrorResponse ( "Media sorting failed, this was probably caused by an event being cancelled" ) ;
}
return Request . CreateResponse ( HttpStatusCode . OK ) ;
}
catch ( Exception ex )
{
2018-08-17 15:41:58 +01:00
Logger . Error < MediaController > ( ex , "Could not update media sort order" ) ;
2018-06-29 19:52:40 +02:00
throw ;
}
}
2018-12-12 17:49:24 +01:00
2018-06-29 19:52:40 +02:00
public MediaItemDisplay PostAddFolder ( PostedFolder folder )
{
var intParentId = GetParentIdAsInt ( folder . ParentId , validatePermissions : true ) ;
2018-12-12 17:49:24 +01:00
2020-06-12 15:58:53 +02:00
var mediaService = _mediaService ;
2018-06-29 19:52:40 +02:00
var f = mediaService . CreateMedia ( folder . Name , intParentId , Constants . Conventions . MediaTypes . Folder ) ;
2020-06-12 15:58:53 +02:00
mediaService . Save ( f , _webSecurity . CurrentUser . Id ) ;
2018-06-29 19:52:40 +02:00
2020-06-12 15:58:53 +02:00
return _umbracoMapper . Map < MediaItemDisplay > ( f ) ;
2018-06-29 19:52:40 +02:00
}
/// <summary>
/// Used to submit a media file
/// </summary>
/// <returns></returns>
/// <remarks>
/// We cannot validate this request with attributes (nicely) due to the nature of the multi-part for data.
/// </remarks>
[FileUploadCleanupFilter(false)]
public async Task < HttpResponseMessage > PostAddFile ( )
{
if ( Request . Content . IsMimeMultipartContent ( ) = = false )
{
throw new HttpResponseException ( HttpStatusCode . UnsupportedMediaType ) ;
}
2020-02-10 11:23:23 +01:00
var root = _ioHelper . MapPath ( Constants . SystemDirectories . TempFileUploads ) ;
2018-06-29 19:52:40 +02:00
//ensure it exists
Directory . CreateDirectory ( root ) ;
var provider = new MultipartFormDataStreamProvider ( root ) ;
var result = await Request . Content . ReadAsMultipartAsync ( provider ) ;
//must have a file
if ( result . FileData . Count = = 0 )
{
return Request . CreateResponse ( HttpStatusCode . NotFound ) ;
}
//get the string json from the request
string currentFolderId = result . FormData [ "currentFolder" ] ;
int parentId = GetParentIdAsInt ( currentFolderId , validatePermissions : true ) ;
2018-12-12 17:49:24 +01:00
2018-06-29 19:52:40 +02:00
var tempFiles = new PostedFiles ( ) ;
2020-06-12 15:58:53 +02:00
var mediaService = _mediaService ;
2018-12-12 17:49:24 +01:00
2018-06-29 19:52:40 +02:00
//in case we pass a path with a folder in it, we will create it and upload media to it.
if ( result . FormData . ContainsKey ( "path" ) )
{
var folders = result . FormData [ "path" ] . Split ( '/' ) ;
for ( int i = 0 ; i < folders . Length - 1 ; i + + )
{
var folderName = folders [ i ] ;
IMedia folderMediaItem ;
//if uploading directly to media root and not a subfolder
if ( parentId = = - 1 )
{
//look for matching folder
folderMediaItem =
mediaService . GetRootMedia ( ) . FirstOrDefault ( x = > x . Name = = folderName & & x . ContentType . Alias = = Constants . Conventions . MediaTypes . Folder ) ;
if ( folderMediaItem = = null )
{
//if null, create a folder
folderMediaItem = mediaService . CreateMedia ( folderName , - 1 , Constants . Conventions . MediaTypes . Folder ) ;
mediaService . Save ( folderMediaItem ) ;
}
}
else
{
//get current parent
var mediaRoot = mediaService . GetById ( parentId ) ;
//if the media root is null, something went wrong, we'll abort
if ( mediaRoot = = null )
return Request . CreateErrorResponse ( HttpStatusCode . InternalServerError ,
"The folder: " + folderName + " could not be used for storing images, its ID: " + parentId +
" returned null" ) ;
//look for matching folder
2018-10-31 23:11:37 +11:00
folderMediaItem = FindInChildren ( mediaRoot . Id , folderName , Constants . Conventions . MediaTypes . Folder ) ;
2018-06-29 19:52:40 +02:00
if ( folderMediaItem = = null )
{
//if null, create a folder
folderMediaItem = mediaService . CreateMedia ( folderName , mediaRoot , Constants . Conventions . MediaTypes . Folder ) ;
mediaService . Save ( folderMediaItem ) ;
}
}
//set the media root to the folder id so uploaded files will end there.
parentId = folderMediaItem . Id ;
}
}
//get the files
foreach ( var file in result . FileData )
{
var fileName = file . Headers . ContentDisposition . FileName . Trim ( new [ ] { '\"' } ) . TrimEnd ( ) ;
2019-12-18 18:55:00 +01:00
var safeFileName = fileName . ToSafeFileName ( ShortStringHelper ) ;
2018-06-29 19:52:40 +02:00
var ext = safeFileName . Substring ( safeFileName . LastIndexOf ( '.' ) + 1 ) . ToLower ( ) ;
2020-03-12 15:30:22 +01:00
if ( _contentSettings . IsFileAllowedForUpload ( ext ) )
2018-06-29 19:52:40 +02:00
{
var mediaType = Constants . Conventions . MediaTypes . File ;
if ( result . FormData [ "contentTypeAlias" ] = = Constants . Conventions . MediaTypes . AutoSelect )
{
2020-03-12 15:30:22 +01:00
if ( _contentSettings . ImageFileTypes . Contains ( ext ) )
2018-06-29 19:52:40 +02:00
{
mediaType = Constants . Conventions . MediaTypes . Image ;
}
}
else
{
mediaType = result . FormData [ "contentTypeAlias" ] ;
}
2018-10-01 14:32:46 +02:00
var mediaItemName = fileName . ToFriendlyName ( ) ;
2018-06-29 19:52:40 +02:00
2020-06-12 15:58:53 +02:00
var f = mediaService . CreateMedia ( mediaItemName , parentId , mediaType , _webSecurity . CurrentUser . Id ) ;
2018-06-29 19:52:40 +02:00
var fileInfo = new FileInfo ( file . LocalFileName ) ;
var fs = fileInfo . OpenReadWithRetry ( ) ;
if ( fs = = null ) throw new InvalidOperationException ( "Could not acquire file stream" ) ;
using ( fs )
{
2020-06-12 15:58:53 +02:00
f . SetValue ( _mediaFileSystem , ShortStringHelper , _contentTypeBaseServiceProvider , Constants . Conventions . Media . File , fileName , fs ) ;
2018-06-29 19:52:40 +02:00
}
2020-06-12 15:58:53 +02:00
var saveResult = mediaService . Save ( f , _webSecurity . CurrentUser . Id ) ;
2018-06-29 19:52:40 +02:00
if ( saveResult = = false )
{
AddCancelMessage ( tempFiles ,
2020-06-12 15:58:53 +02:00
message : _localizedTextService . Localize ( "speechBubbles/operationCancelledText" ) + " -- " + mediaItemName ) ;
2018-06-29 19:52:40 +02:00
}
else
{
tempFiles . UploadedFiles . Add ( new ContentPropertyFile
{
FileName = fileName ,
PropertyAlias = Constants . Conventions . Media . File ,
TempFilePath = file . LocalFileName
} ) ;
}
}
else
{
2020-01-20 11:37:19 +01:00
tempFiles . Notifications . Add ( new BackOfficeNotification (
2020-06-12 15:58:53 +02:00
_localizedTextService . Localize ( "speechBubbles/operationFailedHeader" ) ,
_localizedTextService . Localize ( "media/disallowedFileType" ) ,
2019-01-29 23:05:59 +11:00
NotificationStyle . Warning ) ) ;
2018-06-29 19:52:40 +02:00
}
}
//Different response if this is a 'blueimp' request
if ( Request . GetQueryNameValuePairs ( ) . Any ( x = > x . Key = = "origin" ) )
{
var origin = Request . GetQueryNameValuePairs ( ) . First ( x = > x . Key = = "origin" ) ;
if ( origin . Value = = "blueimp" )
{
return Request . CreateResponse ( HttpStatusCode . OK ,
tempFiles ,
//Don't output the angular xsrf stuff, blue imp doesn't like that
new JsonMediaTypeFormatter ( ) ) ;
}
}
return Request . CreateResponse ( HttpStatusCode . OK , tempFiles ) ;
}
2018-10-31 23:11:37 +11:00
private IMedia FindInChildren ( int mediaId , string nameToFind , string contentTypeAlias )
{
const int pageSize = 500 ;
var page = 0 ;
var total = long . MaxValue ;
while ( page * pageSize < total )
{
2020-06-12 15:58:53 +02:00
var children = _mediaService . GetPagedChildren ( mediaId , page , pageSize , out total ,
_sqlContext . Query < IMedia > ( ) . Where ( x = > x . Name = = nameToFind ) ) ;
2018-10-31 23:11:37 +11:00
foreach ( var c in children )
2018-11-01 00:21:52 +11:00
return c ; //return first one if any are found
2018-10-31 23:11:37 +11:00
}
return null ;
}
2018-06-29 19:52:40 +02:00
/// <summary>
/// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT
/// </summary>
/// <param name="parentId"></param>
/// <param name="validatePermissions">
/// If true, this will check if the current user has access to the resolved integer parent id
/// and if that check fails an unauthorized exception will occur
/// </param>
/// <returns></returns>
2020-06-12 15:58:53 +02:00
private ActionResult < int > GetParentIdAsInt ( string parentId , bool validatePermissions )
2018-06-29 19:52:40 +02:00
{
int intParentId ;
// test for udi
2019-11-13 16:33:40 +11:00
if ( UdiParser . TryParse ( parentId , out GuidUdi parentUdi ) )
2018-06-29 19:52:40 +02:00
{
parentId = parentUdi . Guid . ToString ( ) ;
}
//if it's not an INT then we'll check for GUID
if ( int . TryParse ( parentId , out intParentId ) = = false )
{
// if a guid then try to look up the entity
Guid idGuid ;
if ( Guid . TryParse ( parentId , out idGuid ) )
{
2020-06-12 15:58:53 +02:00
var entity = _entityService . Get ( idGuid ) ;
2018-06-29 19:52:40 +02:00
if ( entity ! = null )
{
intParentId = entity . Id ;
}
else
{
2020-06-12 15:58:53 +02:00
return NotFound ( "The passed id doesn't exist" ) ;
2018-06-29 19:52:40 +02:00
}
}
else
{
2020-06-12 15:58:53 +02:00
throw HttpResponseException . CreateValidationErrorResponse ( "The request was not formatted correctly, the parentId is not an integer, Guid or UDI" ) ;
2018-06-29 19:52:40 +02:00
}
}
//ensure the user has access to this folder by parent id!
if ( validatePermissions & & CheckPermissions (
2020-06-12 15:58:53 +02:00
new Dictionary < object , object > ( ) ,
_webSecurity . CurrentUser ,
_mediaService ,
_entityService ,
2018-06-29 19:52:40 +02:00
intParentId ) = = false )
{
2020-06-12 15:58:53 +02:00
throw new HttpResponseException (
2018-06-29 19:52:40 +02:00
HttpStatusCode . Forbidden ,
2020-01-20 11:37:19 +01:00
new SimpleNotificationModel ( new BackOfficeNotification (
2020-06-12 15:58:53 +02:00
_localizedTextService . Localize ( "speechBubbles/operationFailedHeader" ) ,
_localizedTextService . Localize ( "speechBubbles/invalidUserPermissionsText" ) ,
NotificationStyle . Warning ) ) ) ;
2018-06-29 19:52:40 +02:00
}
return intParentId ;
}
/// <summary>
/// Ensures the item can be moved/copied to the new location
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
private IMedia ValidateMoveOrCopy ( MoveOrCopy model )
{
if ( model = = null )
{
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
2020-06-12 15:58:53 +02:00
var mediaService = _mediaService ;
2018-06-29 19:52:40 +02:00
var toMove = mediaService . GetById ( model . Id ) ;
if ( toMove = = null )
{
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
if ( model . ParentId < 0 )
{
2019-02-05 07:54:59 +01:00
//cannot move if the content item is not allowed at the root unless there are
//none allowed at root (in which case all should be allowed at root)
2020-06-12 15:58:53 +02:00
var mediaTypeService = _mediaTypeService ;
2019-02-05 07:54:59 +01:00
if ( toMove . ContentType . AllowedAsRoot = = false & & mediaTypeService . GetAll ( ) . Any ( ct = > ct . AllowedAsRoot ) )
2018-06-29 19:52:40 +02:00
{
var notificationModel = new SimpleNotificationModel ( ) ;
2020-06-12 15:58:53 +02:00
notificationModel . AddErrorNotification ( _localizedTextService . Localize ( "moveOrCopy/notAllowedAtRoot" ) , "" ) ;
throw HttpResponseException . CreateValidationErrorResponse ( notificationModel ) ;
2018-06-29 19:52:40 +02:00
}
}
else
{
var parent = mediaService . GetById ( model . ParentId ) ;
if ( parent = = null )
{
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
//check if the item is allowed under this one
2020-06-12 15:58:53 +02:00
var parentContentType = _mediaTypeService . Get ( parent . ContentTypeId ) ;
2019-02-05 14:06:48 +01:00
if ( parentContentType . AllowedContentTypes . Select ( x = > x . Id ) . ToArray ( )
2018-06-29 19:52:40 +02:00
. Any ( x = > x . Value = = toMove . ContentType . Id ) = = false )
{
var notificationModel = new SimpleNotificationModel ( ) ;
2020-06-12 15:58:53 +02:00
notificationModel . AddErrorNotification ( _localizedTextService . Localize ( "moveOrCopy/notAllowedByContentType" ) , "" ) ;
throw HttpResponseException . CreateValidationErrorResponse ( notificationModel ) ;
2018-06-29 19:52:40 +02:00
}
// Check on paths
if ( ( string . Format ( ",{0}," , parent . Path ) ) . IndexOf ( string . Format ( ",{0}," , toMove . Id ) , StringComparison . Ordinal ) > - 1 )
{
var notificationModel = new SimpleNotificationModel ( ) ;
2020-06-12 15:58:53 +02:00
notificationModel . AddErrorNotification ( _localizedTextService . Localize ( "moveOrCopy/notAllowedByPath" ) , "" ) ;
throw HttpResponseException . CreateValidationErrorResponse ( notificationModel ) ;
2018-06-29 19:52:40 +02:00
}
}
return toMove ;
}
/// <summary>
/// Performs a permissions check for the user to check if it has access to the node based on
/// start node and/or permissions for the node
/// </summary>
/// <param name="storage">The storage to add the content item to so it can be reused</param>
/// <param name="user"></param>
/// <param name="mediaService"></param>
/// <param name="entityService"></param>
/// <param name="nodeId">The content to lookup, if the contentItem is not specified</param>
/// <param name="media">Specifies the already resolved content item to check against, setting this ignores the nodeId</param>
/// <returns></returns>
2020-06-12 15:58:53 +02:00
internal static bool CheckPermissions ( IDictionary < object , object > storage , IUser user , IMediaService mediaService , IEntityService entityService , int nodeId , IMedia media = null )
2018-06-29 19:52:40 +02:00
{
if ( storage = = null ) throw new ArgumentNullException ( "storage" ) ;
if ( user = = null ) throw new ArgumentNullException ( "user" ) ;
if ( mediaService = = null ) throw new ArgumentNullException ( "mediaService" ) ;
if ( entityService = = null ) throw new ArgumentNullException ( "entityService" ) ;
2019-11-05 13:45:42 +01:00
if ( media = = null & & nodeId ! = Constants . System . Root & & nodeId ! = Constants . System . RecycleBinMedia )
2018-06-29 19:52:40 +02:00
{
media = mediaService . GetById ( nodeId ) ;
2019-01-26 10:52:19 -05:00
//put the content item into storage so it can be retrieved
2018-06-29 19:52:40 +02:00
// in the controller (saves a lookup)
storage [ typeof ( IMedia ) . ToString ( ) ] = media ;
}
2019-11-05 13:45:42 +01:00
if ( media = = null & & nodeId ! = Constants . System . Root & & nodeId ! = Constants . System . RecycleBinMedia )
2018-06-29 19:52:40 +02:00
{
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
}
2019-11-05 13:45:42 +01:00
var hasPathAccess = ( nodeId = = Constants . System . Root )
2018-06-29 19:52:40 +02:00
? user . HasMediaRootAccess ( entityService )
2019-11-05 13:45:42 +01:00
: ( nodeId = = Constants . System . RecycleBinMedia )
2018-06-29 19:52:40 +02:00
? user . HasMediaBinAccess ( entityService )
: user . HasPathAccess ( media , entityService ) ;
return hasPathAccess ;
}
2019-11-06 13:41:21 +00:00
2019-11-18 11:43:31 +00:00
public PagedResult < EntityBasic > GetPagedReferences ( int id , string entityType , int pageNumber = 1 , int pageSize = 100 )
2019-11-06 13:41:21 +00:00
{
2019-11-15 12:50:44 +00:00
if ( pageNumber < = 0 | | pageSize < = 0 )
{
throw new NotSupportedException ( "Both pageNumber and pageSize must be greater than zero" ) ;
}
2019-11-06 13:41:21 +00:00
2019-11-20 12:15:27 +11:00
var objectType = ObjectTypes . GetUmbracoObjectType ( entityType ) ;
var udiType = ObjectTypes . GetUdiType ( objectType ) ;
2019-11-18 11:43:31 +00:00
2020-06-12 15:58:53 +02:00
var relations = _relationService . GetPagedParentEntitiesByChildId ( id , pageNumber - 1 , pageSize , out var totalRecords , objectType ) ;
2019-11-15 12:50:44 +00:00
2019-11-18 11:43:31 +00:00
return new PagedResult < EntityBasic > ( totalRecords , pageNumber , pageSize )
2019-11-15 12:50:44 +00:00
{
2019-11-18 12:18:50 +00:00
Items = relations . Cast < ContentEntitySlim > ( ) . Select ( rel = > new EntityBasic
2019-11-15 12:50:44 +00:00
{
2019-11-18 11:43:31 +00:00
Id = rel . Id ,
Key = rel . Key ,
2019-11-20 12:15:27 +11:00
Udi = Udi . Create ( udiType , rel . Key ) ,
2019-11-18 11:43:31 +00:00
Icon = rel . ContentTypeIcon ,
Name = rel . Name ,
Alias = rel . ContentTypeAlias
2019-11-15 12:50:44 +00:00
} )
} ;
2019-11-06 13:41:21 +00:00
}
2018-06-29 19:52:40 +02:00
}
2018-10-08 11:23:12 +02:00
}