using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using umbraco;
using umbraco.BusinessLogic.Actions;
using System.Globalization;
namespace Umbraco.Web.Trees
{
public abstract class ContentTreeControllerBase : TreeController
{
#region Actions
///
/// Gets an individual tree node
///
///
///
///
[HttpQueryStringFilter("queryStrings")]
public TreeNode GetTreeNode(string id, FormDataCollection queryStrings)
{
int asInt;
if (int.TryParse(id, out asInt) == false)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
var entity = Services.EntityService.Get(asInt, UmbracoObjectType);
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
protected abstract TreeNode GetSingleTreeNode(IUmbracoEntity e, string parentId, FormDataCollection queryStrings);
///
/// Returns the
///
protected abstract int RecycleBinId { get; }
///
/// Returns true if the recycle bin has items in it
///
protected abstract bool RecycleBinSmells { get; }
///
/// Returns the user's start node for this tree
///
protected abstract int UserStartNode { get; }
protected abstract TreeNodeCollection PerformGetTreeNodes(string id, FormDataCollection queryStrings);
protected abstract MenuItemCollection PerformGetMenuForNode(string id, FormDataCollection queryStrings);
protected abstract UmbracoObjectTypes UmbracoObjectType { get; }
protected IEnumerable GetChildEntities(string id)
{
int iid;
if (int.TryParse(id, out iid) == false)
{
throw new InvalidCastException("The id for the media tree must be an integer");
}
//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 node data
if (iid == Constants.System.Root && UserStartNode != Constants.System.Root)
{
//just return their single start node, it will show up under the 'Content' label
var startNode = Services.EntityService.Get(UserStartNode, UmbracoObjectType);
return new[] { startNode };
}
return Services.EntityService.GetChildren(iid, UmbracoObjectType).ToArray();
}
///
/// Returns true or false if the current user has access to the node based on the user's allowed start node (path) access
///
///
///
///
protected abstract bool HasPathAccess(string id, FormDataCollection queryStrings);
///
/// 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.
///
///
///
///
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(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(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("application") + TreeAlias.EnsureStartsWith('/') + "/recyclebin"));
queryStrings.GetValue("application")));
}
return nodes;
}
return GetTreeNodesInternal(id, queryStrings);
}
///
/// Before we make a call to get the tree nodes we have to check if they can actually be rendered
///
///
///
///
///
/// 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.
///
private TreeNodeCollection GetTreeNodesInternal(string id, FormDataCollection queryStrings)
{
//before we get the children we need to see if this is a container node
var current = Services.EntityService.Get(int.Parse(id), UmbracoObjectType);
if (queryStrings.Get("isDialog") != "true" && current != null && current.IsContainer())
{
//no children!
return new TreeNodeCollection();
}
return PerformGetTreeNodes(id, queryStrings);
}
///
/// Checks if the menu requested is for the recycle bin and renders that, otherwise renders the result of PerformGetMenuForNode
///
///
///
///
protected sealed override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
{
if (RecycleBinId.ToInvariantString() == id)
{
var menu = new MenuItemCollection();
menu.Items.Add(ui.Text("actions", "emptyTrashcan"));
menu.Items.Add(ui.Text("actions", ActionRefresh.Instance.Alias), true);
return menu;
}
return PerformGetMenuForNode(id, queryStrings);
}
///
/// Based on the allowed actions, this will filter the ones that the current user is allowed
///
///
///
///
protected void FilterUserAllowedMenuItems(MenuItemCollection menuWithAllItems, IEnumerable