Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • David Armitage 504 posts 2072 karma points
    Nov 25, 2016 @ 16:02
    David Armitage
    0

    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

  • Marcio Goularte 374 posts 1346 karma points
    Nov 25, 2016 @ 19:45
    Marcio Goularte
    0

    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:

     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

  • David Armitage 504 posts 2072 karma points
    Nov 26, 2016 @ 04:52
    David Armitage
    0

    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

  • David Armitage 504 posts 2072 karma points
    Nov 26, 2016 @ 08:46
    David Armitage
    0

    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.

    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.

  • Marcio Goularte 374 posts 1346 karma points
    Nov 26, 2016 @ 19:33
    Marcio Goularte
    100

    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.

  • David Armitage 504 posts 2072 karma points
    Nov 27, 2016 @ 10:16
    David Armitage
    0

    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

  • David Armitage 504 posts 2072 karma points
    Nov 27, 2016 @ 10:49
    David Armitage
    1

    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.

    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());
    
        }
    }
    
  • Marcio Goularte 374 posts 1346 karma points
    Nov 27, 2016 @ 22:44
    Marcio Goularte
    1

    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:

    UmbracoContext.Current.Security.CurrentUser
    
  • Piotr Bach 15 posts 129 karma points c-trib
    Nov 11, 2021 @ 09:32
    Piotr Bach
    1

    Hi, Dedicated Media Folder + Protect Used Media packages will do the job here. Best Piotr

Please Sign in or register to post replies

Write your reply to:

Draft