So I need to prevent users from deleting Media Folders. I have a number of websites in one umbraco instance and its great that you can send the website and media start directories.
I have having is I create a number of media folders which will be static and shouldn't be deleted.
E.g
/Username
/Username /Images
/Username/Documents
The Problem is that users can delete these folders and there is no way I can see to set permissions.
The worst part of the issue is that if the user deletes the root media folder which there user account is attached to then we start to see issues. In this scenario after the root has been deleted when the user accesses the media section Umbraco forces the user out of the system and they have to login again.
It would be awesome if I could somehow prevent either the user from deleting certain media folders I choose (possibly related to the ID), or prevent the user from deleting any media folders, or finally just prevent them from deleting their root media folder to prevent this umbraco force logging out issue.
I was thinking that I might be able to capture a delete event on a media folder in the Umbraco events and basically skip over the delete.
If anyone has achieved this It would be much appreciated if you could tell me how?
Another way is by developing this. Preventing the user from deleting specific folders is possible through MediaService and implementing event handler, like this:
public class MediaEventHandler : ApplicationEventHandler
{
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
MediaService.Deleting += MediaService_Deleting;
}
private void MediaService_Deleting(IMediaService sender, Umbraco.Core.Events.DeleteEventArgs<Umbraco.Core.Models.IMedia> e)
{
foreach (var media in e.DeletedEntities)
{
if (media.ContentType.Alias.Equals("Folder"))
{
//Here you make logic that will not allow you to delete the folder by accessing the database, reading a file, checking permissions umbraco etc.
}
}
}
}
But I believe your need is more complex. You would also have to evaluate if you want to block access to the file (you would have to implement an HTTPHandler). If it is just not allowed to delete a folder, this path is the fastest
Yeah i was thinking something exactly like that. One question though in the deleting event once i have located the folder i dont want to delete how do i tell the event to ignore that specific delete request.
Or do i need to set the node back as un-deleted or something similar?
Also strange but the deleting event doesn't seem to fire. I tried both the content deleting and the media deleting and these just don't fire.
I have called alot of events in the past which fire as expected. I am not sure why this are not.
ContentService.Published += Published;
ContentService.Deleting += Deleting;
MediaService.Deleting += MediaDeleting;
private void Deleting(IContentService sender, DeleteEventArgs<IContent> e)
{
var test = "test";
foreach (var media in e.DeletedEntities)
{
if (media.ContentType.Alias.Equals("Folder"))
{
//Here you make logic that will not allow you to delete the folder by accessing the database, reading a file, checking permissions umbraco etc.
}
}
}
private void MediaDeleting(IMediaService sender, DeleteEventArgs<IMedia> e)
{
var test = "test";
foreach (var media in e.DeletedEntities)
{
if (media.ContentType.Alias.Equals("Folder"))
{
//Here you make logic that will not allow you to delete the folder by accessing the database, reading a file, checking permissions umbraco etc.
}
}
}
The publish is firing fine but the two new events just don't do anything.
it is true. I tested and did not fire. I thought it was strange, because I've done it before and it worked. But it's been a long time. So I was thinking of an alternative and the only one I found is using DelegatingHandler:
public class MediaApiHandler : System.Net.Http.DelegatingHandler
{
private const string ErrorMessage = "Can not delete this folder";
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
switch (request.RequestUri.AbsolutePath.ToLower())
{
case "/umbraco/backoffice/umbracoapi/media/deletebyid":
try
{
//Get ID Querystring
var mediaId = request.RequestUri.Query.Split('&').FirstOrDefault().Replace("?id=", String.Empty);
var media = ApplicationContext.Current.Services.MediaService.GetById(Convert.ToInt32(mediaId));
if (media.ContentType.Alias.Equals("Folder"))
{
var mediadisplay = Mapper.Map<IMedia, MediaItemDisplay>(media);
mediadisplay.AddErrorNotification("Error", ErrorMessage);
return base.SendAsync(request, new CancellationToken(true));
}
}
catch (Exception ex)
{
LogHelper.Error<MediaApiHandler>("Can not delete this folder", ex);
}
return base.SendAsync(request, cancellationToken);
default:
return base.SendAsync(request, cancellationToken);
}
}
}
public class MediaEventHandler : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
//Add a web api handler. Here we can change the values from each web api call.
GlobalConfiguration.Configuration.MessageHandlers.Add(new MediaApiHandler());
}
}
Unfortunately you can not show the notification message. But this code did not delete the folder.
That did the trick perfectly. I don't care too much about a notification so this code is suitable.
It would be nice to know when the deleting events no longer fire. It seems strange since they are still in the Umbraco 7 documentation. Do you have any idea? Possibly a bug introduced into the new versions or possible some obsolete code that hasn't been updated in to documentation yet?
Here is my complete code if anyone is interested...
The only problem with my code (which I gave up on finding a solution) is the way I got the user.
"'User' is obsolete: User 'UserService' instead
If anyone knows the new way how to get a user in the scenario please let me know.
using AutoMapper;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using umbraco.BusinessLogic;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
public class UmbracoMediaApiHandler : System.Net.Http.DelegatingHandler
{
private const string ErrorMessage = "Can not delete this folder";
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
switch (request.RequestUri.AbsolutePath.ToLower())
{
case "/umbraco/backoffice/umbracoapi/media/deletebyid":
try
{
//Get ID Querystring
var mediaId = request.RequestUri.Query.Split('&').FirstOrDefault().Replace("?id=", String.Empty);
var media = ApplicationContext.Current.Services.MediaService.GetById(Convert.ToInt32(mediaId));
if (media.ContentType.Alias.Equals("Folder"))
{
//get the current user type
User currentUser = User.GetCurrent();
if (currentUser == null || currentUser.UserType.Alias != "admin")
{
var loginName = currentUser.LoginName;
if(media.Level == 1)
{
if ((media.Name.ToLower() == loginName.ToLower()) && media.Level == 1)
{
//cancel the delete request
var mediadisplay = Mapper.Map<IMedia, MediaItemDisplay>(media);
mediadisplay.AddErrorNotification("Error", ErrorMessage);
return base.SendAsync(request, new CancellationToken(true));
}
}
else if(media.Level == 2)
{
if(media.Name.ToLower() == "resumes" || media.Name.ToLower() == "documents" || media.Name.ToLower() == "images")
{
//cancel the delete request
var mediadisplay = Mapper.Map<IMedia, MediaItemDisplay>(media);
mediadisplay.AddErrorNotification("Error", ErrorMessage);
return base.SendAsync(request, new CancellationToken(true));
}
}
}
}
}
catch (Exception ex)
{
LogHelper.Error<UmbracoMediaApiHandler>("Can not delete this folder", ex);
}
return base.SendAsync(request, cancellationToken);
default:
return base.SendAsync(request, cancellationToken);
}
}
}
public class MediaEventHandler : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
//Add a web api handler. Here we can change the values from each web api call.
GlobalConfiguration.Configuration.MessageHandlers.Add(new UmbracoMediaApiHandler());
}
}
Glad it worked for you. I do not know why it does not work anymore. I did a long time ago in v6 for folders and it worked but should have removed in those latest versions. Alternative is doing the delegateHandler. The notification would have to test more to make it work.
One tip would be to try removing the Delete action from the menu for folders, doing the validation if admin, etc. But it will need customization.
Prevent Users from Deleting Media Folders
Hi,
So I need to prevent users from deleting Media Folders. I have a number of websites in one umbraco instance and its great that you can send the website and media start directories.
I have having is I create a number of media folders which will be static and shouldn't be deleted.
E.g
/Username /Username /Images /Username/Documents
The Problem is that users can delete these folders and there is no way I can see to set permissions.
The worst part of the issue is that if the user deletes the root media folder which there user account is attached to then we start to see issues. In this scenario after the root has been deleted when the user accesses the media section Umbraco forces the user out of the system and they have to login again.
It would be awesome if I could somehow prevent either the user from deleting certain media folders I choose (possibly related to the ID), or prevent the user from deleting any media folders, or finally just prevent them from deleting their root media folder to prevent this umbraco force logging out issue.
I was thinking that I might be able to capture a delete event on a media folder in the Umbraco events and basically skip over the delete.
If anyone has achieved this It would be much appreciated if you could tell me how?
Kind Regards
David
Hi David,
You seen the package media protect.
https://our.umbraco.org/projects/website-utilities/media-protect/
He is licensed.
Another way is by developing this. Preventing the user from deleting specific folders is possible through MediaService and implementing event handler, like this:
But I believe your need is more complex. You would also have to evaluate if you want to block access to the file (you would have to implement an HTTPHandler). If it is just not allowed to delete a folder, this path is the fastest
Hi Marcio,
Yeah i was thinking something exactly like that. One question though in the deleting event once i have located the folder i dont want to delete how do i tell the event to ignore that specific delete request.
Or do i need to set the node back as un-deleted or something similar?
Kind Regards
David
Hi,
Also strange but the deleting event doesn't seem to fire. I tried both the content deleting and the media deleting and these just don't fire.
I have called alot of events in the past which fire as expected. I am not sure why this are not.
The publish is firing fine but the two new events just don't do anything.
it is true. I tested and did not fire. I thought it was strange, because I've done it before and it worked. But it's been a long time. So I was thinking of an alternative and the only one I found is using DelegatingHandler:
Unfortunately you can not show the notification message. But this code did not delete the folder.
Hi Marcio,
That did the trick perfectly. I don't care too much about a notification so this code is suitable.
It would be nice to know when the deleting events no longer fire. It seems strange since they are still in the Umbraco 7 documentation. Do you have any idea? Possibly a bug introduced into the new versions or possible some obsolete code that hasn't been updated in to documentation yet?
Kind Regards
David
Hi Guys,
Here is my complete code if anyone is interested...
The only problem with my code (which I gave up on finding a solution) is the way I got the user.
"'User' is obsolete: User 'UserService' instead
If anyone knows the new way how to get a user in the scenario please let me know.
Hi David,
Glad it worked for you. I do not know why it does not work anymore. I did a long time ago in v6 for folders and it worked but should have removed in those latest versions. Alternative is doing the delegateHandler. The notification would have to test more to make it work.
One tip would be to try removing the Delete action from the menu for folders, doing the validation if admin, etc. But it will need customization.
For the umbraco user, try this:
Hi, Dedicated Media Folder + Protect Used Media packages will do the job here. Best Piotr
is working on a reply...