KB's

Users who are not administrators cannot drop controls on layout elements

Problem:

When using Sitefinity 4.1 SP2 or lower versions users who are set to be  editors (who are allowed to edit pages) or designers (who are allowed to access templates and edit them) cannot drop controls on layout elements (they are allowed, however, drop controls between the layout elements).

The problem is comes from the fact that layout permissions are not supported in previous releases which leaves the administrator with no options to set proper permissions for the user roles.

Solution:

The issue can be solved either by upgrading the website project or executing the code provided below.
For those who have earlier version than 4.1 SP3, a 2-step upgrade should be performed:

Sitefinity
version -> 4.1 SP3 -> 4.2.

If the upgrade procedure is not an option or the problem was not resolved, the following script can be run on a relevant page or module.

This code should reset the existing permissions on all layout elements, allowing all backend users to drop controls on all layout elements:

private void ResetPermissionsForLayoutElements()
{
    foreach (DataProviderSettings providerSettings in Config.Get<PagesConfig>().Providers)
    {
        PageManager mgr = PageManager.GetManager(providerSettings.Name);
        mgr.Provider.SuppressSecurityChecks = true;
 
        var config = Config.Get<Telerik.Sitefinity.Security.Configuration.SecurityConfig>();
        var setName = SecurityConstants.Sets.LayoutElement.SetName;
        var actionsMask = config.Permissions[setName].Actions[SecurityConstants.Sets.LayoutElement.DropOn].Value;
        var principals = new Guid[] { config.ApplicationRoles[SecurityManager.BackendUsersRoleName].Id };
 
        List<ObjectData> controlsToUpdate = new List<ObjectData>();
 
        var templatesToUpdate = mgr.GetControls<Telerik.Sitefinity.Pages.Model.TemplateControl>()
            .Where(c => c.IsLayoutControl)
            .ToArray()
            .Where(c => !c.IsGranted(setName, principals, actionsMask))
            .ToArray();
        controlsToUpdate.AddRange(templatesToUpdate);
 
        var templateDraftsToUpdate = mgr.GetControls<Telerik.Sitefinity.Pages.Model.TemplateDraftControl>()
            .Where(c => c.IsLayoutControl)
            .ToArray()
            .Where(c => !c.IsGranted(setName, principals, actionsMask))
            .ToArray();
        controlsToUpdate.AddRange(templateDraftsToUpdate);
 
        var pagesToUpdate = mgr.GetControls<PageControl>()
            .Where(c => c.IsLayoutControl)
            .ToArray()
            .Where(c => !c.IsGranted(setName, principals, actionsMask))
            .ToArray();
        controlsToUpdate.AddRange(pagesToUpdate);
 
        var pageDraftsToUpdate = mgr.GetControls<PageDraftControl>()
            .Where(c => c.IsLayoutControl)
            .ToArray()
            .Where(c => !c.IsGranted(setName, principals, actionsMask))
            .ToArray();
        controlsToUpdate.AddRange(pageDraftsToUpdate);
 
        foreach (var item in controlsToUpdate)
        {
            var secItem = (ISecuredObject)item;
            var perm = secItem.Permissions
                .Where(p => p.SetName == setName && p.PrincipalId == principals[0] && p.ObjectId == item.Id)
                .SingleOrDefault();
            if (perm == null)
            {
                perm = mgr.GetPermission(setName, item.Id, principals[0]);
                if (perm == null)
                {
                    perm = mgr.CreatePermission(setName, item.Id, principals[0]);
                }
            }
            perm.GrantActions(true, SecurityConstants.Sets.LayoutElement.DropOn);
            perm.UndenyActions(SecurityConstants.Sets.LayoutElement.DropOn);
 
            if (!secItem.Permissions.Contains(perm))
                secItem.Permissions.Add(perm);
        }
        mgr.SaveChanges();
    }
}