Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filesystem controller compatibility #2042

Merged
merged 4 commits into from Jul 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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