11using System . Net ;
2+ using Microsoft . AspNetCore . Hosting ;
23using Microsoft . AspNetCore . Http ;
34using Microsoft . AspNetCore . Mvc ;
5+ using Microsoft . Extensions . DependencyInjection ;
6+ using Microsoft . Extensions . FileProviders ;
47using Umbraco . Cms . Core ;
8+ using Umbraco . Cms . Core . DependencyInjection ;
59using Umbraco . Cms . Core . Events ;
610using Umbraco . Cms . Core . IO ;
711using Umbraco . Cms . Core . Services ;
@@ -17,68 +21,152 @@ public class StaticFilesTreeController : TreeController
1721 private const string Webroot = "wwwroot" ;
1822 private readonly IFileSystem _fileSystem ;
1923 private readonly IMenuItemCollectionFactory _menuItemCollectionFactory ;
24+ private readonly IWebHostEnvironment _webHostEnvironment ;
2025
26+ [ ActivatorUtilitiesConstructor ]
2127 public StaticFilesTreeController (
2228 ILocalizedTextService localizedTextService ,
2329 UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection ,
2430 IEventAggregator eventAggregator ,
2531 IPhysicalFileSystem fileSystem ,
26- IMenuItemCollectionFactory menuItemCollectionFactory )
32+ IMenuItemCollectionFactory menuItemCollectionFactory ,
33+ IWebHostEnvironment webHostEnvironment )
2734 : base ( localizedTextService , umbracoApiControllerTypeCollection , eventAggregator )
2835 {
2936 _fileSystem = fileSystem ;
3037 _menuItemCollectionFactory = menuItemCollectionFactory ;
38+ _webHostEnvironment = webHostEnvironment ;
39+ }
40+
41+ [ Obsolete ( "Obsolete, use ctor that takes an IWebHostEnvironment, will be removed in future versions." ) ]
42+ public StaticFilesTreeController (
43+ ILocalizedTextService localizedTextService ,
44+ UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection ,
45+ IEventAggregator eventAggregator ,
46+ IPhysicalFileSystem fileSystem ,
47+ IMenuItemCollectionFactory menuItemCollectionFactory )
48+ : this ( localizedTextService , umbracoApiControllerTypeCollection , eventAggregator , fileSystem , menuItemCollectionFactory , StaticServiceProvider . Instance . GetRequiredService < IWebHostEnvironment > ( ) )
49+ {
3150 }
3251
3352 protected override ActionResult < TreeNodeCollection > GetTreeNodes ( string id , FormCollection queryStrings )
3453 {
3554 var path = string . IsNullOrEmpty ( id ) == false && id != Constants . System . RootString
3655 ? WebUtility . UrlDecode ( id ) . TrimStart ( "/" )
37- : "" ;
56+ : string . Empty ;
3857
3958 var nodes = new TreeNodeCollection ( ) ;
40- IEnumerable < string > directories = _fileSystem . GetDirectories ( path ) ;
4159
42- foreach ( var directory in directories )
60+ // Add App_Plugins && wwwroot folder if path is empty, as we are only returning root folders.
61+ if ( path == string . Empty )
4362 {
44- // We don't want any other directories under the root node other than the ones serving static files - App_Plugins and wwwroot
45- if ( id == Constants . System . RootString && directory != AppPlugins && directory != Webroot )
63+ AddRootFolder ( AppPlugins , queryStrings , nodes ) ;
64+ AddRootFolder ( Webroot , queryStrings , nodes ) ;
65+ }
66+ else
67+ {
68+ if ( path . StartsWith ( Webroot , StringComparison . OrdinalIgnoreCase ) )
69+ {
70+ AddWebRootFiles ( path , queryStrings , nodes ) ;
71+ }
72+ else if ( path . StartsWith ( AppPlugins , StringComparison . OrdinalIgnoreCase ) )
4673 {
47- continue ;
74+ AddPhysicalFiles ( path , queryStrings , nodes ) ;
4875 }
76+ }
4977
50- var hasChildren = _fileSystem . GetFiles ( directory ) . Any ( ) || _fileSystem . GetDirectories ( directory ) . Any ( ) ;
78+ return nodes ;
79+ }
5180
52- var name = Path . GetFileName ( directory ) ;
53- TreeNode ? node = CreateTreeNode ( WebUtility . UrlEncode ( directory ) , path , queryStrings , name ,
54- Constants . Icons . Folder , hasChildren ) ;
81+ // We don't have any menu item options (such as create/delete/reload) & only use the root node to load a custom UI
82+ protected override ActionResult < MenuItemCollection > GetMenuForNode ( string id , FormCollection queryStrings ) =>
83+ _menuItemCollectionFactory . Create ( ) ;
5584
56- if ( node != null )
57- {
58- nodes . Add ( node ) ;
59- }
85+ private void AddRootFolder ( string directory , FormCollection queryStrings , TreeNodeCollection nodes )
86+ {
87+ if ( _fileSystem . DirectoryExists ( directory ) is false )
88+ {
89+ return ;
6090 }
6191
62- // Only get the files inside App_Plugins and wwwroot
92+ var hasChildren = _fileSystem . GetFiles ( directory ) . Any ( ) || _fileSystem . GetDirectories ( directory ) . Any ( ) ;
93+
94+ var name = Path . GetFileName ( directory ) ;
95+ TreeNode node = CreateTreeNode ( WebUtility . UrlEncode ( directory ) , "" , queryStrings , name , Constants . Icons . Folder , hasChildren ) ;
96+ nodes . Add ( node ) ;
97+ }
98+
99+ private void AddPhysicalFiles ( string path , FormCollection queryStrings , TreeNodeCollection nodes )
100+ {
63101 IEnumerable < string > files = _fileSystem . GetFiles ( path )
64102 . Where ( x => x . StartsWith ( AppPlugins ) || x . StartsWith ( Webroot ) ) ;
65103
66104 foreach ( var file in files )
67105 {
68106 var name = Path . GetFileName ( file ) ;
69- TreeNode ? node = CreateTreeNode ( WebUtility . UrlEncode ( file ) , path , queryStrings , name ,
70- Constants . Icons . DefaultIcon , false ) ;
107+ TreeNode node = CreateTreeNode ( WebUtility . UrlEncode ( file ) , path , queryStrings , name , Constants . Icons . DefaultIcon , false ) ;
108+ nodes . Add ( node ) ;
109+ }
110+
111+ IEnumerable < string > directories = _fileSystem . GetDirectories ( path ) ;
71112
72- if ( node != null )
113+ foreach ( var directory in directories )
114+ {
115+ var hasChildren = _fileSystem . GetFiles ( directory ) . Any ( ) || _fileSystem . GetDirectories ( directory ) . Any ( ) ;
116+ var name = Path . GetFileName ( directory ) ;
117+ TreeNode node = CreateTreeNode ( WebUtility . UrlEncode ( directory ) , path , queryStrings , name , Constants . Icons . Folder , hasChildren ) ;
118+ nodes . Add ( node ) ;
119+ }
120+ }
121+
122+ private void AddWebRootFiles ( string path , FormCollection queryStrings , TreeNodeCollection nodes )
123+ {
124+ var calculatedPath = path . TrimStart ( Webroot ) ;
125+ IDirectoryContents files = _webHostEnvironment . WebRootFileProvider . GetDirectoryContents ( calculatedPath ) ;
126+ foreach ( IFileInfo file in files . OrderByDescending ( x => x . IsDirectory ) )
127+ {
128+ // This logic looks a little wierd, but because the WebrootFileProvider can actually detect
129+ // our files from App_Plugins, we have to manually exclude them, luckily they are always physical files
130+ // so we can just check if the files are in there, and then exclude them.
131+ bool isPhysicalFile = file . PhysicalPath is not null ;
132+ if ( isPhysicalFile )
73133 {
74- nodes . Add ( node ) ;
134+ if ( file . PhysicalPath ! . StartsWith ( _webHostEnvironment . ContentRootPath + $ "\\ { AppPlugins } ", StringComparison . OrdinalIgnoreCase ) )
135+ {
136+ continue ;
137+ }
75138 }
76- }
77139
78- return nodes ;
79- }
140+ TreeNode ? node ;
141+ if ( file . IsDirectory )
142+ {
143+ // We don't want to include the umbraco folder, so exclude it.
144+ if ( calculatedPath == string . Empty && "umbraco" . InvariantEquals ( file . Name ) )
145+ {
146+ continue ;
147+ }
80148
81- // We don't have any menu item options (such as create/delete/reload) & only use the root node to load a custom UI
82- protected override ActionResult < MenuItemCollection > GetMenuForNode ( string id , FormCollection queryStrings ) =>
83- _menuItemCollectionFactory . Create ( ) ;
149+ bool hasChildren ;
150+
151+ if ( isPhysicalFile )
152+ {
153+ var calculatedFilePaths = _webHostEnvironment . WebRootPath + calculatedPath ;
154+ hasChildren = _fileSystem . GetFiles ( calculatedFilePaths ) . Any ( ) || _fileSystem . GetDirectories ( calculatedFilePaths ) . Any ( ) ;
155+ }
156+ else
157+ {
158+ IDirectoryContents childFiles = _webHostEnvironment . WebRootFileProvider . GetDirectoryContents ( calculatedPath + $ "/{ file . Name } ") ;
159+ hasChildren = childFiles . Any ( ) ;
160+ }
161+
162+ node = CreateTreeNode ( WebUtility . UrlEncode ( string . Join ( "/" , path , file . Name ) ) , path , queryStrings , file . Name , Constants . Icons . Folder , hasChildren ) ;
163+ }
164+ else
165+ {
166+ node = CreateTreeNode ( WebUtility . UrlEncode ( string . Join ( "/" , path , file . Name ) ) , path , queryStrings , file . Name , Constants . Icons . DefaultIcon , false ) ;
167+ }
168+
169+ nodes . Add ( node ) ;
170+ }
171+ }
84172}
0 commit comments