2013-08-12 15:06:12 +02:00
using System ;
2017-09-19 15:51:47 +02:00
using System.Collections.Concurrent ;
2013-08-12 15:06:12 +02:00
using System.Collections.Generic ;
using System.Linq ;
2013-12-12 14:10:03 +11:00
using System.Net ;
using System.Net.Http ;
2013-08-12 15:06:12 +02:00
using System.Net.Http.Formatting ;
2013-12-12 14:10:03 +11:00
using System.Web.Http ;
2013-08-12 15:06:12 +02:00
using Umbraco.Core ;
2016-03-11 15:43:34 +01:00
using Umbraco.Core.Services ;
2014-09-23 16:50:05 +10:00
using Umbraco.Core.Logging ;
2013-08-12 15:06:12 +02:00
using Umbraco.Core.Models ;
2013-10-08 12:38:27 +11:00
using Umbraco.Web.Models.Trees ;
2013-12-12 14:10:03 +11:00
using Umbraco.Web.WebApi.Filters ;
2013-11-18 22:29:19 +01:00
using System.Globalization ;
2018-01-15 11:32:30 +01:00
using Umbraco.Core.Models.Entities ;
2018-04-19 23:41:35 +10:00
using Umbraco.Web._Legacy.Actions ;
2013-08-12 15:06:12 +02:00
namespace Umbraco.Web.Trees
{
2013-09-26 15:55:38 +10:00
public abstract class ContentTreeControllerBase : TreeController
2013-08-12 15:06:12 +02:00
{
2013-12-12 14:10:03 +11:00
#region Actions
/// <summary>
/// Gets an individual tree node
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
[HttpQueryStringFilter("queryStrings")]
public TreeNode GetTreeNode ( string id , FormDataCollection queryStrings )
{
int asInt ;
2018-03-27 10:04:07 +02:00
Guid asGuid = Guid . Empty ;
2013-12-12 14:10:03 +11:00
if ( int . TryParse ( id , out asInt ) = = false )
{
2018-03-27 10:04:07 +02:00
if ( Guid . TryParse ( id , out asGuid ) = = false )
{
throw new HttpResponseException ( Request . CreateResponse ( HttpStatusCode . NotFound ) ) ;
}
2013-12-12 14:10:03 +11:00
}
2018-03-27 10:04:07 +02:00
var entity = asGuid = = Guid . Empty
? Services . EntityService . Get ( asInt , UmbracoObjectType )
: Services . EntityService . Get ( asGuid , UmbracoObjectType ) ;
2013-12-12 14:10:03 +11:00
if ( entity = = null )
{
throw new HttpResponseException ( Request . CreateResponse ( HttpStatusCode . NotFound ) ) ;
}
var node = GetSingleTreeNode ( entity , entity . ParentId . ToInvariantString ( ) , queryStrings ) ;
//add the tree alias to the node since it is standalone (has no root for which this normally belongs)
node . AdditionalData [ "treeAlias" ] = TreeAlias ;
return node ;
}
#endregion
2017-09-19 15:51:47 +02:00
/// <summary>
/// Ensure the noAccess metadata is applied for the root node if in dialog mode and the user doesn't have path access to it
/// </summary>
/// <param name="queryStrings"></param>
/// <returns></returns>
protected override TreeNode CreateRootNode ( FormDataCollection queryStrings )
{
var node = base . CreateRootNode ( queryStrings ) ;
if ( IsDialog ( queryStrings ) & & UserStartNodes . Contains ( Constants . System . Root ) = = false )
{
node . AdditionalData [ "noAccess" ] = true ;
}
return node ;
}
2018-01-15 11:32:30 +01:00
protected abstract TreeNode GetSingleTreeNode ( IEntitySlim entity , string parentId , FormDataCollection queryStrings ) ;
2013-12-12 14:10:03 +11:00
2017-09-19 15:51:47 +02:00
/// <summary>
2017-09-23 10:08:18 +02:00
/// Returns a <see cref="TreeNode"/> for the <see cref="IUmbracoEntity"/> and
2017-09-19 15:51:47 +02:00
/// attaches some meta data to the node if the user doesn't have start node access to it when in dialog mode
/// </summary>
/// <param name="e"></param>
/// <param name="parentId"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
2018-01-15 11:32:30 +01:00
internal TreeNode GetSingleTreeNodeWithAccessCheck ( IEntitySlim e , string parentId , FormDataCollection queryStrings )
2017-09-19 15:51:47 +02:00
{
2018-01-15 11:32:30 +01:00
var entityIsAncestorOfStartNodes = Security . CurrentUser . IsInBranchOfStartNode ( e , Services . EntityService , RecycleBinId , out var hasPathAccess ) ;
2017-09-19 15:51:47 +02:00
if ( entityIsAncestorOfStartNodes = = false )
return null ;
2017-09-23 10:08:18 +02:00
var treeNode = GetSingleTreeNode ( e , parentId , queryStrings ) ;
2017-09-19 15:51:47 +02:00
if ( hasPathAccess = = false )
{
treeNode . AdditionalData [ "noAccess" ] = true ;
}
return treeNode ;
}
2013-08-12 15:06:12 +02:00
/// <summary>
2016-09-01 19:06:08 +02:00
/// Returns the
2013-08-12 15:06:12 +02:00
/// </summary>
protected abstract int RecycleBinId { get ; }
/// <summary>
/// Returns true if the recycle bin has items in it
/// </summary>
protected abstract bool RecycleBinSmells { get ; }
2013-10-01 16:38:10 +10:00
/// <summary>
/// Returns the user's start node for this tree
/// </summary>
2017-09-12 16:22:16 +02:00
protected abstract int [ ] UserStartNodes { get ; }
2017-09-23 10:08:18 +02:00
2014-09-23 16:50:05 +10:00
protected virtual TreeNodeCollection PerformGetTreeNodes ( string id , FormDataCollection queryStrings )
{
var nodes = new TreeNodeCollection ( ) ;
2017-09-19 15:51:47 +02:00
var rootIdString = Constants . System . Root . ToString ( CultureInfo . InvariantCulture ) ;
2018-03-27 10:04:07 +02:00
var hasAccessToRoot = UserStartNodes . Contains ( Constants . System . Root ) ;
var startNodeId = queryStrings . HasKey ( TreeQueryStringParameters . StartNodeId )
? queryStrings . GetValue < string > ( TreeQueryStringParameters . StartNodeId )
: string . Empty ;
2014-09-23 16:50:05 +10:00
2018-03-27 10:04:07 +02:00
if ( string . IsNullOrEmpty ( startNodeId ) = = false & & startNodeId ! = "undefined" & & startNodeId ! = rootIdString )
2014-09-23 16:50:05 +10:00
{
2018-03-27 10:04:07 +02:00
// request has been made to render from a specific, non-root, start node
id = startNodeId ;
2014-09-23 16:50:05 +10:00
2018-03-27 10:04:07 +02:00
// ensure that the user has access to that node, otherwise return the empty tree nodes collection
2016-09-01 19:06:08 +02:00
// TODO: in the future we could return a validation statement so we can have some UI to notify the user they don't have access
2014-09-23 16:50:05 +10:00
if ( HasPathAccess ( id , queryStrings ) = = false )
{
2018-03-27 10:04:07 +02:00
Logger . Warn < ContentTreeControllerBase > ( "User " + Security . CurrentUser . Username + " does not have access to node with id " + id ) ;
return nodes ;
2014-09-23 16:50:05 +10:00
}
2016-09-01 19:06:08 +02:00
2018-03-27 10:04:07 +02:00
// if the tree is rendered...
// - in a dialog: render only the children of the specific start node, nothing to do
// - in a section: if the current user's start nodes do not contain the root node, we need
// to include these start nodes in the tree too, to provide some context - i.e. change
// start node back to root node, and then GetChildEntities method will take care of the rest.
if ( IsDialog ( queryStrings ) = = false & & hasAccessToRoot = = false )
id = rootIdString ;
2014-09-23 16:50:05 +10:00
}
2016-09-01 19:06:08 +02:00
2018-03-27 10:04:07 +02:00
// get child entities - if id is root, but user's start nodes do not contain the
2018-01-17 10:47:35 +01:00
// root node, this returns the start nodes instead of root's children
2018-04-17 01:37:35 +10:00
var langId = queryStrings [ "languageId" ] . TryConvertTo < int? > ( ) ;
var entities = GetChildEntities ( id , langId . Success ? langId . Result : null ) . ToList ( ) ;
2018-03-27 10:04:07 +02:00
nodes . AddRange ( entities . Select ( x = > GetSingleTreeNodeWithAccessCheck ( x , id , queryStrings ) ) . Where ( x = > x ! = null ) ) ;
2017-09-19 15:51:47 +02:00
2018-03-27 10:04:07 +02:00
// if the user does not have access to the root node, what we have is the start nodes,
// but to provide some context we also need to add their topmost nodes when they are not
// topmost nodes themselves (level > 1).
if ( id = = rootIdString & & hasAccessToRoot = = false )
2017-09-19 15:51:47 +02:00
{
2018-03-27 10:04:07 +02:00
var topNodeIds = entities . Where ( x = > x . Level > 1 ) . Select ( GetTopNodeId ) . Where ( x = > x ! = 0 ) . Distinct ( ) . ToArray ( ) ;
if ( topNodeIds . Length > 0 )
2017-09-19 15:51:47 +02:00
{
2018-03-27 10:04:07 +02:00
var topNodes = Services . EntityService . GetAll ( UmbracoObjectType , topNodeIds . ToArray ( ) ) ;
nodes . AddRange ( topNodes . Select ( x = > GetSingleTreeNodeWithAccessCheck ( x , id , queryStrings ) ) . Where ( x = > x ! = null ) ) ;
2017-09-19 15:51:47 +02:00
}
}
2014-09-23 16:50:05 +10:00
return nodes ;
2017-09-23 10:08:18 +02:00
}
2014-01-17 13:00:11 +11:00
2018-03-27 10:04:07 +02:00
private static readonly char [ ] Comma = { ',' } ;
private int GetTopNodeId ( IUmbracoEntity entity )
{
int id ;
var parts = entity . Path . Split ( Comma , StringSplitOptions . RemoveEmptyEntries ) ;
return parts . Length > = 2 & & int . TryParse ( parts [ 1 ] , out id ) ? id : 0 ;
}
2013-08-12 15:06:12 +02:00
protected abstract MenuItemCollection PerformGetMenuForNode ( string id , FormDataCollection queryStrings ) ;
protected abstract UmbracoObjectTypes UmbracoObjectType { get ; }
2018-04-17 01:37:35 +10:00
protected IEnumerable < IEntitySlim > GetChildEntities ( string id , int? langId )
2013-08-12 15:06:12 +02:00
{
2018-03-27 10:04:07 +02:00
// try to parse id as an integer else use GetEntityFromId
// which will grok Guids, Udis, etc and let use obtain the id
if ( int . TryParse ( id , out var entityId ) = = false )
2013-08-12 15:06:12 +02:00
{
2018-03-27 10:04:07 +02:00
var entity = GetEntityFromId ( id ) ;
if ( entity = = null )
2017-05-12 14:49:44 +02:00
throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
2018-03-27 10:04:07 +02:00
entityId = entity . Id ;
2013-08-12 15:06:12 +02:00
}
2018-04-19 23:41:35 +10:00
IEntitySlim [ ] result ;
2013-08-12 15:06:12 +02:00
2017-09-12 16:22:16 +02:00
// if a request is made for the root node but user has no access to
// root node, return start nodes instead
2018-03-27 10:04:07 +02:00
if ( entityId = = Constants . System . Root & & UserStartNodes . Contains ( Constants . System . Root ) = = false )
2013-08-12 15:06:12 +02:00
{
2018-04-17 01:37:35 +10:00
result = UserStartNodes . Length > 0
? Services . EntityService . GetAll ( UmbracoObjectType , UserStartNodes ) . ToArray ( )
: Array . Empty < IEntitySlim > ( ) ;
2018-04-19 23:41:35 +10:00
}
else
{
result = Services . EntityService . GetChildren ( entityId , UmbracoObjectType ) . ToArray ( ) ;
}
2018-04-20 13:26:45 +10:00
//This should really never be null, but we'll error check anyways
int? currLangId = langId . HasValue ? langId . Value : Services . LocalizationService . GetDefaultVariantLanguage ( ) ? . Id ;
//Try to see if there is a variant name for the current language for the item and set the name accordingly.
//If any of this fails, the tree node name will remain the default invariant culture name.
//fixme - what if there is no name found at all ? This could occur if the doc type is variant and the user fills in all language values, then creates a new lang, sets it as default and deletes all other pre-existing langs
if ( currLangId . HasValue )
2018-04-19 23:41:35 +10:00
{
2018-04-20 13:26:45 +10:00
foreach ( var e in result )
2018-04-19 23:41:35 +10:00
{
2018-04-20 13:26:45 +10:00
if ( e . AdditionalData . TryGetValue ( "CultureNames" , out var cultureNames )
& & cultureNames is IDictionary < int , string > cnd )
{
if ( cnd . TryGetValue ( currLangId . Value , out var name ) )
{
e . Name = name ;
}
2018-04-19 23:41:35 +10:00
}
}
}
2018-04-17 01:37:35 +10:00
return result ;
2013-08-12 15:06:12 +02:00
}
2013-11-19 12:28:50 +11:00
/// <summary>
/// Returns true or false if the current user has access to the node based on the user's allowed start node (path) access
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
2017-09-19 15:51:47 +02:00
//we should remove this in v8, it's now here for backwards compat only
2013-11-19 12:28:50 +11:00
protected abstract bool HasPathAccess ( string id , FormDataCollection queryStrings ) ;
2017-09-19 15:51:47 +02:00
/// <summary>
/// Returns true or false if the current user has access to the node based on the user's allowed start node (path) access
/// </summary>
/// <param name="entity"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
protected bool HasPathAccess ( IUmbracoEntity entity , FormDataCollection queryStrings )
{
if ( entity = = null ) return false ;
return Security . CurrentUser . HasPathAccess ( entity , Services . EntityService , RecycleBinId ) ;
}
2013-08-12 15:06:12 +02:00
/// <summary>
2014-09-23 16:50:05 +10:00
/// Ensures the recycle bin is appended when required (i.e. user has access to the root and it's not in dialog mode)
2013-08-12 15:06:12 +02:00
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
2014-09-23 16:50:05 +10:00
/// <remarks>
/// This method is overwritten strictly to render the recycle bin, it should serve no other purpose
/// </remarks>
2013-08-12 15:06:12 +02:00
protected sealed override TreeNodeCollection GetTreeNodes ( string id , FormDataCollection queryStrings )
{
2013-11-19 12:28:50 +11:00
//check if we're rendering the root
2017-09-12 16:22:16 +02:00
if ( id = = Constants . System . Root . ToInvariantString ( ) & & UserStartNodes . Contains ( Constants . System . Root ) )
2013-08-12 15:06:12 +02:00
{
2014-09-23 16:50:05 +10:00
var altStartId = string . Empty ;
2014-08-08 10:54:05 +02:00
2014-09-23 16:50:05 +10:00
if ( queryStrings . HasKey ( TreeQueryStringParameters . StartNodeId ) )
altStartId = queryStrings . GetValue < string > ( TreeQueryStringParameters . StartNodeId ) ;
2014-01-17 13:00:11 +11:00
2016-09-01 19:06:08 +02:00
//check if a request has been made to render from a specific start node
2014-09-23 16:50:05 +10:00
if ( string . IsNullOrEmpty ( altStartId ) = = false & & altStartId ! = "undefined" & & altStartId ! = Constants . System . Root . ToString ( CultureInfo . InvariantCulture ) )
2013-11-19 12:28:50 +11:00
{
2014-09-23 16:50:05 +10:00
id = altStartId ;
2013-11-19 12:28:50 +11:00
}
2016-09-01 19:06:08 +02:00
2014-09-23 16:50:05 +10:00
var nodes = GetTreeNodesInternal ( id , queryStrings ) ;
2016-09-01 19:06:08 +02:00
2014-09-23 16:50:05 +10:00
//only render the recycle bin if we are not in dialog and the start id id still the root
if ( IsDialog ( queryStrings ) = = false & & id = = Constants . System . Root . ToInvariantString ( ) )
2013-09-04 17:36:05 +10:00
{
nodes . Add ( CreateTreeNode (
2013-10-24 16:54:17 +11:00
RecycleBinId . ToInvariantString ( ) ,
2014-09-23 16:50:05 +10:00
id ,
2013-09-04 17:36:05 +10:00
queryStrings ,
2016-03-11 15:56:00 +01:00
Services . TextService . Localize ( "general/recycleBin" ) ,
2013-09-04 17:36:05 +10:00
"icon-trash" ,
RecycleBinSmells ,
2014-06-08 16:15:28 +01:00
queryStrings . GetValue < string > ( "application" ) + TreeAlias . EnsureStartsWith ( '/' ) + "/recyclebin" ) ) ;
2014-09-23 16:50:05 +10:00
2013-09-04 17:36:05 +10:00
}
2013-08-12 15:06:12 +02:00
return nodes ;
}
2013-12-04 15:54:50 +11:00
return GetTreeNodesInternal ( id , queryStrings ) ;
}
/// <summary>
/// Before we make a call to get the tree nodes we have to check if they can actually be rendered
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
/// <remarks>
/// Currently this just checks if it is a container type, if it is we cannot render children. In the future this might check for other things.
/// </remarks>
private TreeNodeCollection GetTreeNodesInternal ( string id , FormDataCollection queryStrings )
{
2017-09-19 15:51:47 +02:00
var current = GetEntityFromId ( id ) ;
2017-05-12 14:49:44 +02:00
2017-07-20 11:21:28 +02:00
//before we get the children we need to see if this is a container node
2014-01-17 13:00:11 +11:00
2014-01-28 15:49:04 +01:00
//test if the parent is a listview / container
2018-01-15 11:32:30 +01:00
if ( current ! = null & & current . IsContainer )
2013-11-15 16:19:46 +11:00
{
//no children!
return new TreeNodeCollection ( ) ;
}
2014-01-27 22:03:52 +01:00
2013-08-12 15:06:12 +02:00
return PerformGetTreeNodes ( id , queryStrings ) ;
}
/// <summary>
/// Checks if the menu requested is for the recycle bin and renders that, otherwise renders the result of PerformGetMenuForNode
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
protected sealed override MenuItemCollection GetMenuForNode ( string id , FormDataCollection queryStrings )
{
if ( RecycleBinId . ToInvariantString ( ) = = id )
{
var menu = new MenuItemCollection ( ) ;
2016-03-11 15:43:34 +01:00
menu . Items . Add < ActionEmptyTranscan > ( Services . TextService . Localize ( "actions/emptyTrashcan" ) ) ;
2016-03-15 16:58:13 +01:00
menu . Items . Add < ActionRefresh > ( Services . TextService . Localize ( "actions" , ActionRefresh . Instance . Alias ) , true ) ;
2013-08-12 15:06:12 +02:00
return menu ;
}
2017-09-19 15:51:47 +02:00
2013-08-12 15:06:12 +02:00
return PerformGetMenuForNode ( id , queryStrings ) ;
}
/// <summary>
/// Based on the allowed actions, this will filter the ones that the current user is allowed
/// </summary>
2013-09-26 15:55:38 +10:00
/// <param name="menuWithAllItems"></param>
2013-08-12 15:06:12 +02:00
/// <param name="userAllowedMenuItems"></param>
/// <returns></returns>
2013-09-26 15:55:38 +10:00
protected void FilterUserAllowedMenuItems ( MenuItemCollection menuWithAllItems , IEnumerable < MenuItem > userAllowedMenuItems )
2013-08-12 15:06:12 +02:00
{
var userAllowedActions = userAllowedMenuItems . Where ( x = > x . Action ! = null ) . Select ( x = > x . Action ) . ToArray ( ) ;
2013-09-26 15:55:38 +10:00
2013-10-03 15:05:48 +10:00
var notAllowed = menuWithAllItems . Items . Where (
2013-09-26 15:55:38 +10:00
a = > ( a . Action ! = null
& & a . Action . CanBePermissionAssigned
& & ( a . Action . CanBePermissionAssigned = = false | | userAllowedActions . Contains ( a . Action ) = = false ) ) )
. ToArray ( ) ;
//remove the ones that aren't allowed.
foreach ( var m in notAllowed )
{
2013-10-03 15:05:48 +10:00
menuWithAllItems . Items . Remove ( m ) ;
2013-09-26 15:55:38 +10:00
}
2013-08-12 15:06:12 +02:00
}
2013-09-26 15:55:38 +10:00
internal IEnumerable < MenuItem > GetAllowedUserMenuItemsForNode ( IUmbracoEntity dd )
2013-08-12 15:06:12 +02:00
{
2016-03-16 17:52:08 +01:00
var permission = Services . UserService . GetPermissions ( Security . CurrentUser , dd . Path ) ;
2017-09-19 15:51:47 +02:00
var actions = global :: Umbraco . Web . _Legacy . Actions . Action . FromEntityPermission ( permission )
. ToList ( ) ;
2017-09-23 10:08:18 +02:00
2013-08-12 15:06:12 +02:00
// A user is allowed to delete their own stuff
2018-03-02 15:48:21 +01:00
var tryGetCurrentUserId = Security . GetUserId ( ) ;
if ( tryGetCurrentUserId & & dd . CreatorId = = tryGetCurrentUserId . Result & & actions . Contains ( ActionDelete . Instance ) = = false )
2013-08-12 15:06:12 +02:00
actions . Add ( ActionDelete . Instance ) ;
2013-09-26 15:55:38 +10:00
return actions . Select ( x = > new MenuItem ( x ) ) ;
2013-08-12 15:06:12 +02:00
}
/// <summary>
/// Determins if the user has access to view the node/document
/// </summary>
/// <param name="doc">The Document to check permissions against</param>
/// <param name="allowedUserOptions">A list of MenuItems that the user has permissions to execute on the current document</param>
/// <remarks>By default the user must have Browse permissions to see the node in the Content tree</remarks>
2016-09-01 19:06:08 +02:00
/// <returns></returns>
2018-04-17 01:37:35 +10:00
internal bool CanUserAccessNode ( IUmbracoEntity doc , IEnumerable < MenuItem > allowedUserOptions , int? langId )
2013-08-12 15:06:12 +02:00
{
2018-04-17 01:37:35 +10:00
//TODO: At some stage when we implement permissions on languages we'll need to take care of langId
2013-08-12 15:06:12 +02:00
return allowedUserOptions . Select ( x = > x . Action ) . OfType < ActionBrowse > ( ) . Any ( ) ;
}
2017-05-12 14:49:44 +02:00
/// <summary>
2017-09-19 15:51:47 +02:00
/// this will parse the string into either a GUID or INT
2017-05-12 14:49:44 +02:00
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
2017-09-19 15:51:47 +02:00
internal Tuple < Guid ? , int? > GetIdentifierFromString ( string id )
2017-05-12 14:49:44 +02:00
{
2017-09-19 15:51:47 +02:00
Guid idGuid ;
int idInt ;
Udi idUdi ;
2017-05-12 14:49:44 +02:00
2017-09-19 15:51:47 +02:00
if ( Guid . TryParse ( id , out idGuid ) )
2017-05-12 14:49:44 +02:00
{
2017-09-19 15:51:47 +02:00
return new Tuple < Guid ? , int? > ( idGuid , null ) ;
2017-05-12 14:49:44 +02:00
}
2017-09-19 15:51:47 +02:00
if ( int . TryParse ( id , out idInt ) )
2017-05-12 14:49:44 +02:00
{
2017-09-19 15:51:47 +02:00
return new Tuple < Guid ? , int? > ( null , idInt ) ;
2017-05-12 14:49:44 +02:00
}
2017-09-19 15:51:47 +02:00
if ( Udi . TryParse ( id , out idUdi ) )
2017-05-12 14:49:44 +02:00
{
var guidUdi = idUdi as GuidUdi ;
2017-09-19 15:51:47 +02:00
if ( guidUdi ! = null )
2017-09-23 10:08:18 +02:00
return new Tuple < Guid ? , int? > ( guidUdi . Guid , null ) ;
2017-05-12 14:49:44 +02:00
}
2017-09-19 15:51:47 +02:00
return null ;
}
/// <summary>
/// Get an entity via an id that can be either an integer, Guid or UDI
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <remarks>
/// This object has it's own contextual cache for these lookups
/// </remarks>
2018-01-15 11:32:30 +01:00
internal IEntitySlim GetEntityFromId ( string id )
2017-09-19 15:51:47 +02:00
{
return _entityCache . GetOrAdd ( id , s = >
2017-05-12 14:49:44 +02:00
{
2018-01-15 11:32:30 +01:00
IEntitySlim entity ;
2017-05-12 14:49:44 +02:00
2018-01-15 11:32:30 +01:00
if ( Guid . TryParse ( s , out var idGuid ) )
2017-09-19 15:51:47 +02:00
{
2018-01-15 11:32:30 +01:00
entity = Services . EntityService . Get ( idGuid , UmbracoObjectType ) ;
2017-09-19 15:51:47 +02:00
}
2018-01-15 11:32:30 +01:00
else if ( int . TryParse ( s , out var idInt ) )
2017-09-19 15:51:47 +02:00
{
entity = Services . EntityService . Get ( idInt , UmbracoObjectType ) ;
}
2018-01-15 11:32:30 +01:00
else if ( Udi . TryParse ( s , out var idUdi ) )
2017-09-19 15:51:47 +02:00
{
var guidUdi = idUdi as GuidUdi ;
2018-01-15 11:32:30 +01:00
entity = guidUdi ! = null ? Services . EntityService . Get ( guidUdi . Guid , UmbracoObjectType ) : null ;
2017-09-19 15:51:47 +02:00
}
else
{
2018-01-15 11:32:30 +01:00
entity = null ;
2017-09-19 15:51:47 +02:00
}
return entity ;
} ) ;
2017-05-12 14:49:44 +02:00
}
2017-09-19 15:51:47 +02:00
2018-01-15 11:32:30 +01:00
private readonly ConcurrentDictionary < string , IEntitySlim > _entityCache = new ConcurrentDictionary < string , IEntitySlim > ( ) ;
2013-08-12 15:06:12 +02:00
}
2017-07-20 11:21:28 +02:00
}