Ejemplo n.º 1
0
        public HttpResponseMessage GetMembersExport(FormDataCollection queryStrings)
        {
            // Base Query data
            string    memberType     = queryStrings.HasKey("memberType") ? queryStrings.GetValue <string>("memberType") : "";
            string    orderBy        = queryStrings.HasKey("orderBy") ? queryStrings.GetValue <string>("orderBy") : "email";
            Direction orderDirection = queryStrings.HasKey("orderDirection") ? queryStrings.GetValue <Direction>("orderDirection") : Direction.Ascending;

            string filter = queryStrings.HasKey("filter") ? queryStrings.GetValue <string>("filter") : "";

            int totalMembers = 0;

            var members = Mapper.Map <IEnumerable <MemberExportModel> >(MemberSearch.PerformMemberSearch(filter, queryStrings, out totalMembers,
                                                                                                         memberType,
                                                                                                         orderBy: orderBy,
                                                                                                         orderDirection: orderDirection));

            var content = members.CreateCSV();

            // see http://stackoverflow.com/questions/9541351/returning-binary-file-from-controller-in-asp-net-web-api
            // & http://stackoverflow.com/questions/12975886/how-to-download-a-file-using-web-api-in-asp-net-mvc-4-and-jquery
            // We really should use an async version - the above reference includes an example.
            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);

            result.Content = new StringContent(content);
            result.Content.Headers.ContentType                 = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition          = new ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = string.Format("Members_{0:yyyyMMdd}.csv", DateTime.Now);

            return(result);
        }
        public HttpResponseMessage GetMembersExport(FormDataCollection queryStrings)
        {
            // Base Query data
            string memberType = queryStrings.HasKey("memberType") ? queryStrings.GetValue<string>("memberType") : "";
            string orderBy = queryStrings.HasKey("orderBy") ? queryStrings.GetValue<string>("orderBy") : "email";
            Direction orderDirection = queryStrings.HasKey("orderDirection") ? queryStrings.GetValue<Direction>("orderDirection") : Direction.Ascending;

            string filter = queryStrings.HasKey("filter") ? queryStrings.GetValue<string>("filter") : "";

            int totalMembers = 0;

            var members = Mapper.Map<IEnumerable<MemberExportModel>>(MemberSearch.PerformMemberSearch(filter, queryStrings, out totalMembers,
                                                                                                        memberType,
                                                                                                        orderBy: orderBy, 
                                                                                                        orderDirection: orderDirection));

            var content = members.CreateCSV();

            // see http://stackoverflow.com/questions/9541351/returning-binary-file-from-controller-in-asp-net-web-api
            // & http://stackoverflow.com/questions/12975886/how-to-download-a-file-using-web-api-in-asp-net-mvc-4-and-jquery
            // We really should use an async version - the above reference includes an example.
            HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
            result.Content = new StringContent(content);
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = string.Format("Members_{0:yyyyMMdd}.csv", DateTime.Now);

            return result;
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Returns the value of a mandatory item in the FormCollection
 /// </summary>
 /// <param name="items"></param>
 /// <param name="key"></param>
 /// <returns></returns>
 public static string GetRequiredString(this FormDataCollection items, string key)
 {
     if (items.HasKey(key) == false)
     {
         throw new ArgumentNullException("The " + key + " query string parameter was not found but is required");
     }
     return(items.Single(x => x.Key.InvariantEquals(key)).Value);
 }
        protected virtual TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
        {
            var nodes = new TreeNodeCollection();

            var rootIdString    = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
            var hasAccessToRoot = UserStartNodes.Contains(Constants.System.Root);

            var startNodeId = queryStrings.HasKey(TreeQueryStringParameters.StartNodeId)
                ? queryStrings.GetValue <string>(TreeQueryStringParameters.StartNodeId)
                : string.Empty;

            if (string.IsNullOrEmpty(startNodeId) == false && startNodeId != "undefined" && startNodeId != rootIdString)
            {
                // request has been made to render from a specific, non-root, start node
                id = startNodeId;

                // ensure that the user has access to that node, otherwise return the empty tree nodes collection
                // 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
                if (HasPathAccess(id, queryStrings) == false)
                {
                    Logger.Warn <ContentTreeControllerBase>("User {Username} does not have access to node with id {Id}", Security.CurrentUser.Username, id);
                    return(nodes);
                }

                // 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;
                }
            }

            // get child entities - if id is root, but user's start nodes do not contain the
            // root node, this returns the start nodes instead of root's children
            var entities = GetChildEntities(id, queryStrings).ToList();

            nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings)).Where(x => x != null));

            // 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)
            {
                var topNodeIds = entities.Where(x => x.Level > 1).Select(GetTopNodeId).Where(x => x != 0).Distinct().ToArray();
                if (topNodeIds.Length > 0)
                {
                    var topNodes = Services.EntityService.GetAll(UmbracoObjectType, topNodeIds.ToArray());
                    nodes.AddRange(topNodes.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings)).Where(x => x != null));
                }
            }

            return(nodes);
        }
        public PagedResult<MemberListItem> GetMembers(FormDataCollection queryStrings)
        {
            // Base Query data
            int pageNumber = queryStrings.HasKey("pageNumber") ? queryStrings.GetValue<int>("pageNumber") : 1;
            int pageSize = queryStrings.HasKey("pageSize") ? queryStrings.GetValue<int>("pageSize") : 10;
            string orderBy = queryStrings.HasKey("orderBy") ? queryStrings.GetValue<string>("orderBy") : "email";
            Direction orderDirection = queryStrings.HasKey("orderDirection") ? queryStrings.GetValue<Direction>("orderDirection") : Direction.Ascending;
            string memberType = queryStrings.HasKey("memberType") ? queryStrings.GetValue<string>("memberType") : "";

            string filter = queryStrings.HasKey("filter") ? queryStrings.GetValue<string>("filter") : "";

            int totalMembers = 0;
            var members = Mapper.Map<IEnumerable<MemberListItem>>(MemberSearch.PerformMemberSearch(filter, queryStrings, out totalMembers,
                                                                                                    memberType, pageNumber, pageSize,
                                                                                                    orderBy, orderDirection));
            if (totalMembers == 0)
                return new PagedResult<MemberListItem>(0, 0, 0);

            var pagedResult = new PagedResult<MemberListItem>(
               totalMembers,
               pageNumber,
               pageSize);

            pagedResult.Items = members;

            return pagedResult;
        }
Ejemplo n.º 6
0
        public PagedResult <MemberListItem> GetMembers(FormDataCollection queryStrings)
        {
            // Base Query data
            int       pageNumber     = queryStrings.HasKey("pageNumber") ? queryStrings.GetValue <int>("pageNumber") : 1;
            int       pageSize       = queryStrings.HasKey("pageSize") ? queryStrings.GetValue <int>("pageSize") : 10;
            string    orderBy        = queryStrings.HasKey("orderBy") ? queryStrings.GetValue <string>("orderBy") : "email";
            Direction orderDirection = queryStrings.HasKey("orderDirection") ? queryStrings.GetValue <Direction>("orderDirection") : Direction.Ascending;
            string    memberType     = queryStrings.HasKey("memberType") ? queryStrings.GetValue <string>("memberType") : "";

            string filter = queryStrings.HasKey("filter") ? queryStrings.GetValue <string>("filter") : "";

            int totalMembers = 0;
            var members      = Mapper.Map <IEnumerable <MemberListItem> >(MemberSearch.PerformMemberSearch(filter, queryStrings, out totalMembers,
                                                                                                           memberType, pageNumber, pageSize,
                                                                                                           orderBy, orderDirection));

            if (totalMembers == 0)
            {
                return(new PagedResult <MemberListItem>(0, 0, 0));
            }

            var pagedResult = new PagedResult <MemberListItem>(
                totalMembers,
                pageNumber,
                pageSize);

            pagedResult.Items = members;

            return(pagedResult);
        }
Ejemplo n.º 7
0
        public PagedResult <MappedSearchResult> GetSearchResults(FormDataCollection queryStrings)
        {
            int pageNumber = queryStrings.HasKey("pageNumber") ? queryStrings.GetValue <int>("pageNumber") : 1;
            int pageSize   = queryStrings.HasKey("pageSize") ? queryStrings.GetValue <int>("pageSize") : 0;

            string filter = queryStrings.HasKey("filter") ? queryStrings.GetValue <string>("filter") : string.Empty;

            if (string.IsNullOrEmpty(filter))
            {
                return(new PagedResult <MappedSearchResult>(0, pageNumber, pageSize));
            }

            // todo: consider caching search results in session for paging optimisation.
            var results     = Umbraco.PerformContentSearch(filter);
            var count       = results.Count();
            var pagedResult = new PagedResult <MappedSearchResult>(
                count,
                pageNumber,
                pageSize);

            if (count > 0)
            {
                if (pageSize > 0)
                {
                    int skipCount = (pageNumber > 0 && pageSize > 0) ? Convert.ToInt32((pageNumber - 1) * pageSize) : 0;
                    if (count < skipCount)
                    {
                        skipCount = count / pageSize;
                    }

                    pagedResult.Items = results.Skip(skipCount).Take(pageSize);
                }
                else
                {
                    pagedResult.Items = results;
                }
            }
            return(pagedResult);
        }
        /// <summary>
        /// Gets the tree nodes for the given id
        /// </summary>
        /// <param name="id"></param>
        /// <param name="queryStrings"></param>
        /// <returns></returns>
        protected virtual TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
        {
            var nodes = new TreeNodeCollection();

            var altStartId = string.Empty;

            if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
            {
                altStartId = queryStrings.GetValue <string>(TreeQueryStringParameters.StartNodeId);
            }

            //check if a request has been made to render from a specific start node
            if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
            {
                id = altStartId;

                //we need to verify that the user has access to view this node, otherwise we'll render an empty tree collection
                // 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
                if (HasPathAccess(id, queryStrings) == false)
                {
                    LogHelper.Warn <ContentTreeControllerBase>("The user " + Security.CurrentUser.Username + " does not have access to the tree node " + id);
                    return(new TreeNodeCollection());
                }

                // So there's an alt id specified, it's not the root node and the user has access to it, great! But there's one thing we
                // need to consider:
                // If the tree is being rendered in a dialog view we want to render only the children of the specified id, but
                // when the tree is being rendered normally in a section and the current user's start node is not -1, then
                // we want to include their start node in the tree as well.
                // Therefore, in the latter case, we want to change the id to -1 since we want to render the current user's root node
                // and the GetChildEntities method will take care of rendering the correct root node.
                // If it is in dialog mode, then we don't need to change anything and the children will just render as per normal.
                if (IsDialog(queryStrings) == false && UserStartNode != Constants.System.Root)
                {
                    id = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
                }
            }

            var entities = GetChildEntities(id);

            nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null));
            return(nodes);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Ensures the recycle bin is appended when required (i.e. user has access to the root and it's not in dialog mode)
        /// </summary>
        /// <param name="id"></param>
        /// <param name="queryStrings"></param>
        /// <returns></returns>
        /// <remarks>
        /// This method is overwritten strictly to render the recycle bin, it should serve no other purpose
        /// </remarks>
        protected sealed override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
        {
            //check if we're rendering the root
            if (id == Constants.System.RootString && UserStartNodes.Contains(Constants.System.Root))
            {
                var altStartId = string.Empty;

                if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
                {
                    altStartId = queryStrings.GetValue <string>(TreeQueryStringParameters.StartNodeId);
                }

                //check if a request has been made to render from a specific start node
                if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.RootString)
                {
                    id = altStartId;
                }

                var nodes = GetTreeNodesInternal(id, queryStrings);

                //only render the recycle bin if we are not in dialog and the start id is still the root
                //we need to check for the "application" key in the queryString because its value is required here,
                //and for some reason when there are no dashboards, this parameter is missing
                if (IsDialog(queryStrings) == false && id == Constants.System.RootString && queryStrings.HasKey("application"))
                {
                    nodes.Add(CreateTreeNode(
                                  RecycleBinId.ToInvariantString(),
                                  id,
                                  queryStrings,
                                  Services.TextService.Localize("general", "recycleBin"),
                                  "icon-trash",
                                  RecycleBinSmells,
                                  queryStrings.GetRequiredValue <string>("application") + TreeAlias.EnsureStartsWith('/') + "/recyclebin"));
                }

                return(nodes);
            }

            return(GetTreeNodesInternal(id, queryStrings));
        }
        /// <summary>
        /// Ensures the recycle bin is appended when required (i.e. user has access to the root and it's not in dialog mode)
        /// </summary>
        /// <param name="id"></param>
        /// <param name="queryStrings"></param>
        /// <returns></returns>
        /// <remarks>
        /// This method is overwritten strictly to render the recycle bin, it should serve no other purpose
        /// </remarks>
        protected sealed override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
        {
            //check if we're rendering the root
            if (id == Constants.System.Root.ToInvariantString() && UserStartNode == Constants.System.Root)
            {
                var altStartId = string.Empty;

                if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
                {
                    altStartId = queryStrings.GetValue <string>(TreeQueryStringParameters.StartNodeId);
                }

                //check if a request has been made to render from a specific start node
                if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
                {
                    id = altStartId;
                }

                var nodes = GetTreeNodesInternal(id, queryStrings);

                //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())
                {
                    nodes.Add(CreateTreeNode(
                                  RecycleBinId.ToInvariantString(),
                                  id,
                                  queryStrings,
                                  ui.GetText("general", "recycleBin"),
                                  "icon-trash",
                                  RecycleBinSmells,
                                  queryStrings.GetValue <string>("application") + TreeAlias.EnsureStartsWith('/') + "/recyclebin"));
                }

                return(nodes);
            }

            return(GetTreeNodesInternal(id, queryStrings));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Helper method to create a root model for a tree
        /// </summary>
        /// <returns></returns>
        protected virtual TreeNode CreateRootNode(FormDataCollection queryStrings)
        {
            var getChildNodesUrl = Url.GetTreeUrl(GetType(), RootNodeId, queryStrings);
            var isDialog         = queryStrings.GetValue <bool>(TreeQueryStringParameters.DialogMode);
            //var node = new TreeNode(RootNodeId, BackOfficeRequestContext.RegisteredComponents.MenuItems, jsonUrl)
            var node = new TreeNode(RootNodeId, getChildNodesUrl)
            {
                HasChildren = true,

                //THIS IS TEMPORARY UNTIL WE FIGURE OUT HOW WE ARE LOADING STUFF (I.E. VIEW NAMES, ACTION NAMES, DUNNO)
                EditorUrl = queryStrings.HasKey(TreeQueryStringParameters.OnNodeClick)        //has a node click handler?
                                    ? queryStrings.Get(TreeQueryStringParameters.OnNodeClick) //return node click handler
                                    : isDialog                                                //is in dialog mode without a click handler ?
                                          ? "#"                                               //return empty string, otherwise, return an editor URL:
                                          : "mydashboard",
                Title = RootNodeDisplayName
            };

            //add the tree type to the root
            node.AdditionalData.Add("treeType", GetType().FullName);

            ////add the tree-root css class
            //node.Style.AddCustom("tree-root");

            //node.AdditionalData.Add("id", node.HiveId.ToString());
            //node.AdditionalData.Add("title", node.Title);

            AddQueryStringsToAdditionalData(node, queryStrings);

            //check if the tree is searchable and add that to the meta data as well
            if (this is ISearchableTree)
            {
                node.AdditionalData.Add("searchable", "true");
            }

            return(node);
        }
        /// <summary>
        /// This will automatically check if the recycle bin needs to be rendered (i.e. its the first level)
        /// and will automatically append it to the result of GetChildNodes.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="queryStrings"></param>
        /// <returns></returns>
        protected sealed override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
        {
            //check if we're rendering the root
            if (id == Constants.System.Root.ToInvariantString() && UserStartNode == Constants.System.Root)
            {
                var nodes = new TreeNodeCollection();
                var altStartId = string.Empty;
                
                if(queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
                    altStartId = queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId);


                //check if a request has been made to render from a specific start node
                //TODO: This 'undefined' check should not be required whatseover - this parameter should not be sent up ever it if is null from the front-end.
                if (!string.IsNullOrEmpty(altStartId) && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
                {
                    id = queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId);

                    //we need to verify that the user has access to view this node, otherwise we'll render an empty tree collection
                    // 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                
                    if (HasPathAccess(id, queryStrings))
                    {
                        nodes = GetTreeNodesInternal(id, queryStrings);
                    }
                }
                else
                {
                    //load normally
                    nodes = GetTreeNodesInternal(id, queryStrings);
                }

                //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())
                {
                    nodes.Add(CreateTreeNode(
                        RecycleBinId.ToInvariantString(),
                        id,
                        queryStrings,
                        ui.GetText("general", "recycleBin"),
                        "icon-trash",
                        RecycleBinSmells,
                        //TODO: This would be nice to enable so we can have a nice recyclebin view, see the NOTE: in the routes.js angular file
                        // for the time being we'll just load the dashboard of the section.
                        //queryStrings.GetValue<string>("application") + TreeAlias.EnsureStartsWith('/') + "/recyclebin"));    
                        queryStrings.GetValue<string>("application")));
                        
                }

                return nodes;
            }

            return GetTreeNodesInternal(id, queryStrings);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Helper method to create a root model for a tree
        /// </summary>
        /// <returns></returns>
        protected virtual TreeNode CreateRootNode(FormDataCollection queryStrings)
        {
            var getChildNodesUrl = Url.GetTreeUrl(GetType(), RootNodeId, queryStrings);
            var isDialog = queryStrings.GetValue<bool>(TreeQueryStringParameters.DialogMode);
            //var node = new TreeNode(RootNodeId, BackOfficeRequestContext.RegisteredComponents.MenuItems, jsonUrl)
            var node = new TreeNode(RootNodeId, getChildNodesUrl)
                {
                    HasChildren = true,

                    //THIS IS TEMPORARY UNTIL WE FIGURE OUT HOW WE ARE LOADING STUFF (I.E. VIEW NAMES, ACTION NAMES, DUNNO)
                    EditorUrl = queryStrings.HasKey(TreeQueryStringParameters.OnNodeClick) //has a node click handler?
                                    ? queryStrings.Get(TreeQueryStringParameters.OnNodeClick) //return node click handler
                                    : isDialog //is in dialog mode without a click handler ?
                                          ? "#" //return empty string, otherwise, return an editor URL:
                                          : "mydashboard",
                    Title = RootNodeDisplayName
                };

            //add the tree type to the root
            node.AdditionalData.Add("treeType", GetType().FullName);

            ////add the tree-root css class
            //node.Style.AddCustom("tree-root");

            //node.AdditionalData.Add("id", node.HiveId.ToString());
            //node.AdditionalData.Add("title", node.Title);

            AddQueryStringsToAdditionalData(node, queryStrings);

            //check if the tree is searchable and add that to the meta data as well
            if (this is ISearchableTree)
            {
                node.AdditionalData.Add("searchable", "true");
            }

            return node;
        }
        protected virtual TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings)
        {
            var nodes = new TreeNodeCollection();

            var altStartId = string.Empty;

            if (queryStrings.HasKey(TreeQueryStringParameters.StartNodeId))
            {
                altStartId = queryStrings.GetValue <string>(TreeQueryStringParameters.StartNodeId);
            }
            var rootIdString = Constants.System.Root.ToString(CultureInfo.InvariantCulture);

            //check if a request has been made to render from a specific start node
            if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != rootIdString)
            {
                id = altStartId;

                //we need to verify that the user has access to view this node, otherwise we'll render an empty tree collection
                // 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
                if (HasPathAccess(id, queryStrings) == false)
                {
                    LogHelper.Warn <ContentTreeControllerBase>("The user " + Security.CurrentUser.Username + " does not have access to the tree node " + id);
                    return(new TreeNodeCollection());
                }

                // So there's an alt id specified, it's not the root node and the user has access to it, great! But there's one thing we
                // need to consider:
                // If the tree is being rendered in a dialog view we want to render only the children of the specified id, but
                // when the tree is being rendered normally in a section and the current user's start node is not -1, then
                // we want to include their start node in the tree as well.
                // Therefore, in the latter case, we want to change the id to -1 since we want to render the current user's root node
                // and the GetChildEntities method will take care of rendering the correct root node.
                // If it is in dialog mode, then we don't need to change anything and the children will just render as per normal.
                if (IsDialog(queryStrings) == false && UserStartNodes.Contains(Constants.System.Root) == false)
                {
                    id = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
                }
            }

            var entities = GetChildEntities(id).ToList();

            //If we are looking up the root and there is more than one node ...
            //then we want to lookup those nodes' 'site' nodes and render those so that the
            //user has some context of where they are in the tree, this is generally for pickers in a dialog.
            //for any node they don't have access too, we need to add some metadata
            if (id == rootIdString && entities.Count > 1)
            {
                var siteNodeIds = new List <int>();
                //put into array since we might modify the list
                foreach (var e in entities.ToArray())
                {
                    var pathParts = e.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (pathParts.Length < 2)
                    {
                        continue; // this should never happen but better to check
                    }
                    int siteNodeId;
                    if (int.TryParse(pathParts[1], out siteNodeId) == false)
                    {
                        continue;
                    }

                    //we'll look up this
                    siteNodeIds.Add(siteNodeId);
                }
                var siteNodes = Services.EntityService.GetAll(UmbracoObjectType, siteNodeIds.ToArray())
                                .DistinctBy(e => e.Id)
                                .ToArray();

                //add site nodes
                nodes.AddRange(siteNodes.Select(e => GetSingleTreeNodeWithAccessCheck(e, id, queryStrings)).Where(node => node != null));

                return(nodes);
            }

            nodes.AddRange(entities.Select(e => GetSingleTreeNodeWithAccessCheck(e, id, queryStrings)).Where(node => node != null));
            return(nodes);
        }