Skip to content

Commit

Permalink
Merge pull request #2042 from umbraco/temp-fsTreeController
Browse files Browse the repository at this point in the history
filesystem controller compatibility
  • Loading branch information
clausjensen committed Jul 12, 2017
2 parents 3de0b85 + ab3469d commit f7f3dcc
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 93 deletions.
127 changes: 44 additions & 83 deletions src/Umbraco.Web/Trees/FileSystemTreeController.cs
@@ -1,21 +1,14 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http.Formatting;
using umbraco.BusinessLogic.Actions;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Web.Models.Trees;
using System.Web;

namespace Umbraco.Web.Trees
{
public abstract class FileSystemTreeController : TreeController
{
protected abstract IFileSystem2 FileSystem { get; }
protected abstract string[] Extensions { get; }
protected abstract string FileIcon { get; }
protected abstract string FilePath { get; }
protected abstract string FileSearchPattern { get; }

/// <summary>
/// Inheritors can override this method to modify the file node that is created.
Expand All @@ -29,100 +22,68 @@ public abstract class FileSystemTreeController : TreeController
/// <param name="treeNode"></param>
protected virtual void OnRenderFolderNode(ref TreeNode treeNode) { }

protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
protected override TreeNodeCollection GetTreeNodes(string id, System.Net.Http.Formatting.FormDataCollection queryStrings)
{
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
? HttpUtility.UrlDecode(id).TrimStart("/")
: "";

var directories = FileSystem.GetDirectories(path);

var nodes = new TreeNodeCollection();
foreach (var directory in directories)
var orgPath = "";
string path;
if (string.IsNullOrEmpty(id) == false && id != "-1")
{
var hasChildren = FileSystem.GetFiles(directory).Any() || FileSystem.GetDirectories(directory).Any();

var name = Path.GetFileName(directory);
var node = CreateTreeNode(HttpUtility.UrlEncode(directory), path, queryStrings, name, "icon-folder", hasChildren);
OnRenderFolderNode(ref node);
if(node != null)
nodes.Add(node);
orgPath = id;
path = IOHelper.MapPath(FilePath + "/" + orgPath);
orgPath += "/";
}

//this is a hack to enable file system tree to support multiple file extension look-up
//so the pattern both support *.* *.xml and xml,js,vb for lookups
var files = FileSystem.GetFiles(path).Where(x =>
else
{
var extension = Path.GetExtension(x);
return extension != null && Extensions.Contains(extension.Trim('.'), StringComparer.InvariantCultureIgnoreCase);
});
path = IOHelper.MapPath(FilePath);
}

var dirInfo = new DirectoryInfo(path);
var dirInfos = dirInfo.GetDirectories();

foreach (var file in files)
{
var withoutExt = Path.GetFileNameWithoutExtension(file);
if (withoutExt.IsNullOrWhiteSpace() == false)
var nodes = new TreeNodeCollection();
foreach (var dir in dirInfos)
{
if ((dir.Attributes & FileAttributes.Hidden) == 0)
{
var name = Path.GetFileName(file);
var node = CreateTreeNode(HttpUtility.UrlEncode(file), path, queryStrings, name, FileIcon, false);
OnRenderFileNode(ref node);
var hasChildren = dir.GetFiles().Length > 0 || dir.GetDirectories().Length > 0;
var node = CreateTreeNode(orgPath + dir.Name, orgPath, queryStrings, dir.Name, "icon-folder", hasChildren);

OnRenderFolderNode(ref node);
if (node != null)
nodes.Add(node);
}
}

return nodes;
}

protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
{
var menu = new MenuItemCollection();
//this is a hack to enable file system tree to support multiple file extension look-up
//so the pattern both support *.* *.xml and xml,js,vb for lookups
var allowedExtensions = new string[0];
var filterByMultipleExtensions = FileSearchPattern.Contains(",");
FileInfo[] fileInfo;

//if root node no need to visit the filesystem so lets just create the menu and return it
if (id == Constants.System.Root.ToInvariantString())
if (filterByMultipleExtensions)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
//create action
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);

return menu;
fileInfo = dirInfo.GetFiles();
allowedExtensions = FileSearchPattern.ToLower().Split(',');
}
else
fileInfo = dirInfo.GetFiles(FileSearchPattern);

var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
? System.Web.HttpUtility.UrlDecode(id).TrimStart("/")
: "";

var isFile = FileSystem.FileExists(path);
var isDirectory = FileSystem.DirectoryExists(path);

if (isDirectory)
foreach (var file in fileInfo)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
//create action
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
if ((file.Attributes & FileAttributes.Hidden) == 0)
{
if (filterByMultipleExtensions && Array.IndexOf(allowedExtensions, file.Extension.ToLower().Trim('.')) < 0)
continue;

var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any();
var node = CreateTreeNode(orgPath + file.Name, orgPath, queryStrings, file.Name, "icon-file", false);

//We can only delete folders if it doesn't have any children (folders or files)
if (hasChildren == false)
{
//delete action
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
}
OnRenderFileNode(ref node);

//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
}
else if (isFile)
{
//if it's not a directory then we only allow to delete the item
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
if (node != null)
nodes.Add(node);
}
}

return menu;
return nodes;
}
}
}
128 changes: 128 additions & 0 deletions src/Umbraco.Web/Trees/FileSystemTreeController2.cs
@@ -0,0 +1,128 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http.Formatting;
using umbraco.BusinessLogic.Actions;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Web.Models.Trees;
using System.Web;

namespace Umbraco.Web.Trees
{
public abstract class FileSystemTreeController2 : TreeController
{
protected abstract IFileSystem2 FileSystem { get; }
protected abstract string[] Extensions { get; }
protected abstract string FileIcon { get; }

/// <summary>
/// Inheritors can override this method to modify the file node that is created.
/// </summary>
/// <param name="treeNode"></param>
protected virtual void OnRenderFileNode(ref TreeNode treeNode) { }

/// <summary>
/// Inheritors can override this method to modify the folder node that is created.
/// </summary>
/// <param name="treeNode"></param>
protected virtual void OnRenderFolderNode(ref TreeNode treeNode) { }

protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
? HttpUtility.UrlDecode(id).TrimStart("/")
: "";

var directories = FileSystem.GetDirectories(path);

var nodes = new TreeNodeCollection();
foreach (var directory in directories)
{
var hasChildren = FileSystem.GetFiles(directory).Any() || FileSystem.GetDirectories(directory).Any();

var name = Path.GetFileName(directory);
var node = CreateTreeNode(HttpUtility.UrlEncode(directory), path, queryStrings, name, "icon-folder", hasChildren);
OnRenderFolderNode(ref node);
if(node != null)
nodes.Add(node);
}

//this is a hack to enable file system tree to support multiple file extension look-up
//so the pattern both support *.* *.xml and xml,js,vb for lookups
var files = FileSystem.GetFiles(path).Where(x =>
{
var extension = Path.GetExtension(x);
return extension != null && Extensions.Contains(extension.Trim('.'), StringComparer.InvariantCultureIgnoreCase);
});

foreach (var file in files)
{
var withoutExt = Path.GetFileNameWithoutExtension(file);
if (withoutExt.IsNullOrWhiteSpace() == false)
{
var name = Path.GetFileName(file);
var node = CreateTreeNode(HttpUtility.UrlEncode(file), path, queryStrings, name, FileIcon, false);
OnRenderFileNode(ref node);
if (node != null)
nodes.Add(node);
}
}

return nodes;
}

protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
{
var menu = new MenuItemCollection();

//if root node no need to visit the filesystem so lets just create the menu and return it
if (id == Constants.System.Root.ToInvariantString())
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
//create action
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);

return menu;
}

var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
? HttpUtility.UrlDecode(id).TrimStart("/")
: "";

var isFile = FileSystem.FileExists(path);
var isDirectory = FileSystem.DirectoryExists(path);

if (isDirectory)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
//create action
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));

var hasChildren = FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any();

//We can only delete folders if it doesn't have any children (folders or files)
if (hasChildren == false)
{
//delete action
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true);
}

//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
}
else if (isFile)
{
//if it's not a directory then we only allow to delete the item
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
}

return menu;
}
}
}
4 changes: 2 additions & 2 deletions src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs
Expand Up @@ -8,14 +8,14 @@ namespace Umbraco.Web.Trees
/// Tree for displaying partial view macros in the developer app
/// </summary>
[Tree(Constants.Applications.Developer, "partialViewMacros", null, sortOrder: 6)]
public class PartialViewMacrosTreeController : FileSystemTreeController
public class PartialViewMacrosTreeController : FileSystemTreeController2
{
protected override IFileSystem2 FileSystem
{
get { return FileSystemProviderManager.Current.MacroPartialsFileSystem; }
}

private static readonly string[] ExtensionsStatic = { "cshtml" };
private static readonly string[] ExtensionsStatic = {"cshtml"};

protected override string[] Extensions
{
Expand Down
12 changes: 6 additions & 6 deletions src/Umbraco.Web/Trees/PartialViewsTreeController.cs
Expand Up @@ -8,14 +8,14 @@ namespace Umbraco.Web.Trees
/// Tree for displaying partial views in the settings app
/// </summary>
[Tree(Constants.Applications.Settings, "partialViews", null, sortOrder: 2)]
public class PartialViewsTreeController : FileSystemTreeController
public class PartialViewsTreeController : FileSystemTreeController2
{
protected override IFileSystem2 FileSystem
{
get { return FileSystemProviderManager.Current.PartialViewsFileSystem; }
}
protected override IFileSystem2 FileSystem
{
get { return FileSystemProviderManager.Current.PartialViewsFileSystem; }
}

private static readonly string[] ExtensionsStatic = { "cshtml" };
private static readonly string[] ExtensionsStatic = {"cshtml"};

protected override string[] Extensions
{
Expand Down
2 changes: 1 addition & 1 deletion src/Umbraco.Web/Trees/ScriptTreeController.cs
Expand Up @@ -5,7 +5,7 @@
namespace Umbraco.Web.Trees
{
[Tree(Constants.Applications.Settings, "scripts", null, sortOrder: 4)]
public class ScriptTreeController : FileSystemTreeController
public class ScriptTreeController : FileSystemTreeController2
{
protected override IFileSystem2 FileSystem
{
Expand Down
3 changes: 2 additions & 1 deletion src/Umbraco.Web/Umbraco.Web.csproj
Expand Up @@ -435,6 +435,7 @@
<Compile Include="Security\Identity\PreviewAuthenticationMiddleware.cs" />
<Compile Include="SingletonHttpContextAccessor.cs" />
<Compile Include="Trees\ContentTypeTreeController.cs" />
<Compile Include="Trees\FileSystemTreeController.cs" />
<Compile Include="Trees\PackagesTreeController.cs" />
<Compile Include="Trees\MediaTypeTreeController.cs" />
<Compile Include="Trees\MemberTypeTreeController.cs" />
Expand Down Expand Up @@ -712,7 +713,7 @@
<Compile Include="TagQuery.cs" />
<Compile Include="Trees\CoreTreeAttribute.cs" />
<Compile Include="Trees\DataTypeTreeController.cs" />
<Compile Include="Trees\FileSystemTreeController.cs" />
<Compile Include="Trees\FileSystemTreeController2.cs" />
<Compile Include="Trees\LanguageTreeController.cs" />
<Compile Include="Trees\LegacyBaseTreeAttribute.cs" />
<Compile Include="Trees\MemberTreeController.cs" />
Expand Down

0 comments on commit f7f3dcc

Please sign in to comment.