Sitefinity File Manager Part 2: Permissions

After reading part 1 of this SiteFinity File Manager series, you should now have the file manager in Sitefinity’s RadEditor dialog set to load in a default folder. The only thing left is to restrict access to other folders. Additionally, we need to set the default upload folder for incoming files.

FileManager Permissions

By default, the RadEditor provides full access to the entire file system for your website. This means that users can navigate outside of their folder and wreak havoc on your site. So although we have already set the editor to open in their folder by default, we have to make sure that they aren’t allowed to leave it. Fortunately, the fix is very simple.

The file you need to edit is located here:
/Sitefinity/Admin/ControlTemplates/Generic_Content/EditorTemplate.ascx. Once again, we need to replace this file with a full UserControl, that includes code-behind. This is done by copying the code from the file, deleteing it, creating a new UserControl (be sure to use the exact same file name!) then pasting the code into the new file.

Permissions for the Editor are saved as a group of three string arrays that hold the list of folders that are accessible. One array is for View permissions, the second for Upload permissions, and the last one is for Delete permissions. Using this you can grant read-only access to the full site (or for example, a separate global images folder) while giving the user write and delete permissions only to their own folder. You can even disable delete permissions to ensure that while users can upload files, they can’t mistakenly erase something.

So all we need to do is open up the codebehind file (EditorTemplate.ascx.cs) and add the following code (modified, of course, to fit the roles and file structure of your own website) to the Page_Load method:

string[] paths = new string[] { };

if (Page.User.IsInRole("departmentA"))
    paths = new string[] { "~/images/departmentA" };

else if (Page.User.IsInRole("departmentA"))
    paths = new string[] { "~/images/departmentB" };

else if (Page.User.IsInRole("manager"))
    paths = new string[] { "~/images/deparmentA", "~/images/departmentB", "~/images/manager" };

In my case, all users should have full access to their own department folders, so I set the permissions to be the same across the board.

RadEditor1.ImageManager.ViewPaths = paths;
RadEditor1.ImageManager.DeletePaths = paths;
RadEditor1.ImageManager.UploadPaths = paths;

However, user images should be uploaded and stored to an images subfolder, while files (such as PDF documents) should be saved instead to a subfolder in the docs folder. For me the fix was simple:

for (int i = 0; i < paths.Length; i++)
    paths[i] = paths[i].Replace("/images/", "/docs/");

RadEditor1.DocumentManager.ViewPaths = paths;
RadEditor1.DocumentManager.DeletePaths = paths;
RadEditor1.DocumentManager.UploadPaths = paths;

However if your strucure is different you may need to create an additional set of arrays based on the permissions you need set.

And that’s all there is to securing your File Manager! Now, all we need to do is set the default upload folder for incoming files. This too, is very simple.

Default Upload Folder – *EditorDialog

When you first open the image/document selector button in rad editor, the first option you’re given is the ability to upload a new file from your computer. By default this goes into the root of the site, which isn’t helpful at all. What’s more is that there is no option to change it in the editor! Fortunately, we only need to modify two files:

/Sitefinity/UserControls/Dialogs/ImageEditorDialog.aspx
/Sitefinity/UserControls/Dialogs/DocumentEditorDialog.aspx

First, open both files and locate the ImageEditorDialog user control and give them an ID so we can access it from codebehind:

<lib:ImageEditorDialog ID="imgpicker" runat="server" DisplayMode="Images" />

Now all you have to do is go into the codebehind for each page and set the DefaultUploadFolder property of the control that was just identified.

protected void Page_Load(object sender, EventArgs e)
{
    if (User.IsInRole("departmentA"))
        imgpicker.DefaultUploadFolder = "~/images/departmentA";
    else if (User.IsInRole("departmentB"))
        imgpicker.DefaultUploadFolder = "~/images/departmentB";
}

And once again, that’s all there is to it. Since the editors are separated (documents and images) you can set a different folder for each based on whether the user is uploading images or documents. This is going to save me a TON of work and significantly ease the amount of training I need to do. I hope you find it helpful as well. As always, your comments are welcome and appreciated!

Sitefinity: File Manager Default Folder

One of the toughest roadblocks I’ve had to deal with while training and supporting users of sitefinity is the issue of uploading files and images through the editor. The default behavior is to start the user in the root of the site, allowing them access to all files and folders, possibly even granting them the ability to delete the whole site! Having trustworthy users is certainly a plausible workaround, but unfortunately not a guaranteed one. And besides that, having to navigate into images -> department -> subfolder1 -> subsubfolder2 -> newimages gets old quickly, especially if you have more than one image that needs to be added.

Fortunately, after a few weeks of code-rummaging through the sitefinity backend, I’ve found a way to improve the situation. It’s not perfect, but it’s another step closer, and isn’t that what it’s all about? No? Well it was still fun to do… so here goes!

Note that these changes are for the FileManager located INSIDE OF RADEDITOR and NOT the default CMS File Manager accessible from the tabstrip. I’m sure that similiar functionality could be achieved following these examples, but I was not in need of this feature and therefore lazied out of it :P)

There are three areas that have to be updated, the ItemSelectorTemplate, which is where we set the default ‘startup’ folder for the File Manager; the Document and Image EditorDialog, which is where we set the default upload folder to receive files, and finally the EditorTemplate, which is where we set View/Upload/Delete permissions for the RadEditor itself. I’ve split this series into two parts; today we focus on the Default Start Folder.

The Default Start Folder – ItemSelectorTemplate

The related user control that we’ll need to modify is located in the folder /Sitefinity/Admin/ControlTemplates/Libraries/Dialogs/ItemSelectorTemplate.ascx. The first thing you need to do is replace this control with a standard UserControl (one that includes code-behind). As I outlined in this forum post about resizing gallery images (which will be posted here in my blog soon, I hope!), the best way is to copy everything in the control, delete the file, then add a new UserControl using the Visual Studio dialog, making sure to use the exact same filename as the original file. Then paste the content from the old control, and you’re good to go!

Item selection (such as images or documents) is handled by a single sitefinity control called urlWebEditor. Now, this was the tough part of all of this (well for me anyway), as I had to spend a few hours scouring through the Sitefinity core, trying to figure out just how the hell this Item Selector dialog worked and where it is configured…

Fortunately you don’t have to worry about all that! All you need to know is that it uses the Telerik.FileManager.ManageFiles class, which is a control added to the urlWebEditor control collection during load. All we have to do is locate this control in the urlWebEditor control collection, and change its properties based on the role of the user. Since this is the only control loaded into the collection, we can grab it by its index:

protected void Page_Load(object sender, EventArgs e)
{
    Telerik.FileManager.ManageFiles mgr = urlWebEditor.Controls[0] as Telerik.FileManager.ManageFiles;
}

First, we need a way to determine what Mode we are in, either Images or Documents. (NOTE: This is an optional step which you may or many not require based on how you organize your files. In my case, I have images stored in one location, and documents stored in another, with each location having matching subfolders to separate images from documents. If you have all both your files and images together in one location, you could easily modify this to bypass this step).

This is accomplished by noting that the urlWebEditor is contained within a ContainerTemplate, which is then located inside of the ItemSelector control itself. Since it’s the ItemSelector which determines the current mode, we have to reflect back up the chain to grab an instance of the parent’s parent, and cast it to the type we want to find the current mode. I’ve wrapped this functionality into a local property:

ItemSelector.ViewMode CurrentMode
{
    get {
        ItemSelector parent = this.Parent.Parent as ItemSelector;
        return parent.ShowMode;
    }
}

Now we can use the results of this property to set our file path.

protected void Page_Load(object sender, EventArgs e)
{
    Telerik.FileManager.ManageFiles mgr = urlWebEditor.Controls[0] as Telerik.FileManager.ManageFiles;
    string path = CurrentMode == ItemSelector.ViewMode.Images ? "~/images" : "~/docs";
    if (Page.Page.User.IsInRole("departmentA"))
        path += "/departmentA";
    else if (Page.User.IsInRole("deptartmentB"))
        path += "/deptB";
    
    mgr.SelectedFolder = new System.IO.DirectoryInfo(Server.MapPath(path));
}

Obviously, you should change the path based on the relationship between roles and your file system, the basic idea is pretty straightforward. As you can see, once you have the default path, it’s simply a matter of setting the SelectedFolder property of the urlWebEditor control.

And that’s it! The file manager will now start in the default folder you set, based on the user role! Tomorrow we’ll tackle part two, and set the default upload folder for incoming files. Stay tuned and thanks for reading!