Welcome to TechNet Blogs Sign in | Join | Help

Automatically cleanup placeholder content after resource gallery items have been deleted

A problem I have been confronted serveral times is that authors have problems to save pages because the content of the page is refering to a resource gallery item that has been deleted in the past.

Usually deleting such resource gallery items should not happen as this means that the site contains broken images or invalid attachment links.

But on huge systems with many authors and different department this can happen quite often.

The best solution would be to deny the deletion of a resource gallery item if it is still in use. Unfortunatelly MCMS does not provide such a feature.

Whenever an author tries to update a posting that contains a reference to a deleted resource gallery item he will see the following error message:

Save Placeholder Failed
-----------------------------------------------------------
Error Details:
The current user does not have rights to edit the requested item. If you are seeing this exception when a MCMS template is executing, it means that you have removed the CmsAuthorizationModule from the HttpModules section of your web.config. You can only remove this module if: 1. All requests for every MCMS template in the web application will only be accessed by anonymous users 2. Guest access is enabled in MCMS (via the SCA) 3. The MCMS guest user has access to all postings based on templates in the web application If any of these requirements are not met, you MUST register the CmsAuthorizationModule in your web.config.
-----------------------------------------------------------

This error message is missleading and also does not give the author a hint about which item is causing the problem.

To bypass this problem cleanup code can be inserted in the MCMS workflow to remove all references to resource gallery items which no longer exist in the MCMS repository.

Here is sample code that can be added to the global.asax.cs to achieve this:

private bool DeletedResource(string link)
{
   
// Extract Resource GUID from URL
   
string[] splt = link.Split('/');
   
string GUID = splt[3];

   
// create new context with admin rights to be able to see deleted items
   
CmsApplicationContext appContext = new CmsApplicationContext();
   
appContext.AuthenticateAsUser("WinNT://servername/cmsAdmin", "cmsAdminPassword", PublishingMode.Unpublished);

   
object o = appContext.Searches.GetByGuid("{"+GUID+"}");

   
// Test item for being deleted
    bool isDeleted= false;
   
if (o != null)
   
{
       
isDeleted = ((o
is Resource) & (((Resource)o).Path.StartsWith("/Archive Folder")));
   
}

   
// dispose admin context 
   
appContext.Dispose();
   
appContext =
null;

   
// return result
   
return isDeleted;
}

private static int FindTag(string text, string tag, int start, string recursecompare)
{
   
int pos = text.ToLower().IndexOf(tag.ToLower(),start);
   
int check = text.ToLower().IndexOf(recursecompare.ToLower(),start+1);
   
if ((check >= 0) & (check < pos))
   
{
       
check = FindTag(text,tag,check,recursecompare);
       
pos = text.ToLower().IndexOf(tag.ToLower(), check+1);
   
}
   
return pos;
}

private static string RemoveTagPair(string text, string tag, string endtag, string recursecompare)
{
   
int start = text.ToLower().IndexOf(tag.ToLower());
   
int end = -1;
   
while (start >= 0)
   
{
       
end = FindTag(text,endtag,start,recursecompare);
       
if (end > start)
           
text = text.Remove(end,endtag.Length);
       
text = text.Remove(start,tag.Length);
       
start = text.ToLower().IndexOf(tag.ToLower());
   
}
   
return text;
}

private string HandleImgAndAttPlaceholderTypes(string propValue)
{
   
if (propValue.ToLower().StartsWith("/nr/rdonlyres"))
   
{
       
if (DeletedResource(propValue))
       
{
           
propValue = "";
       
}
   
}
   
return propValue;
}

private string HandleImageTags(string propValue)
{
   
int start=propValue.ToLower().IndexOf("<img ");
   
while (start >= 0)
   
{
       
int end = propValue.IndexOf(">",start);
       
if (end > start)
       
{
           
string tag = propValue.Substring(start,end-start+1);
           
int linkStart = tag.ToLower().IndexOf("\"/nr/rdonlyres");
           
if (linkStart >= 0)
            
{
               
int linkEnd = tag.IndexOf("\"",linkStart+1);
               
if (linkEnd > linkStart)
               
{
                   
string linkStr = tag.Substring(linkStart,linkEnd-linkStart+1);
                   
if (DeletedResource(linkStr))
                   
{
                       
propValue = propValue.Replace(tag,"");
                       
tag = "";
                   
}
               
}
           
}
            
start = propValue.ToLower().IndexOf("<img ",start+tag.Length);
       
}
    
}
   
return propValue;
}

private string HandleAnchorTags(string propValue)
{
   
int start=propValue.ToLower().IndexOf("<a ");
   
while (start >= 0)
   
{
       
int end = propValue.IndexOf(">",start);
       
if (end > start)
       
{
           
string tag = propValue.Substring(start,end-start+1);
           
int linkStart = tag.ToLower().IndexOf("\"/nr/rdonlyres");
           
if (linkStart >= 0)
           
{
               
int linkEnd = tag.IndexOf("\"",linkStart+1);
               
if (linkEnd > linkStart)
               
{
                   
string linkStr = tag.Substring(linkStart,linkEnd-linkStart+1);
                   
if (DeletedResource(linkStr))
                   
{
                       
propValue = RemoveTagPair(propValue,tag,"</a>","<a");
                       
tag = "";
                   
}
               
}
           
}
           
start = propValue.ToLower().IndexOf("<a ",start+tag.Length);
       
}
   
}
   
return propValue;
}

public void CmsPosting_PlaceholderPropertyChanging( Object sender, PropertyChangingEventArgs e )
{
   
string propName = e.PropertyName;
   
string propValue = e.PropertyValue as string;
   
switch (propName) 
   
{
       
case "Html" : // handle HtmlPlaceholder
        {
            propValue = HandleImageTags(propValue);
            propValue = HandleAnchorTags(propValue);
            break;
        
}
        
case "Src" : // handle ImagePlaceholder
        case "Url" : // handle AttachmentPlaceholder
        
{
            
propValue = HandleImgAndAttPlaceholderTypes(propValue);
            
break;
        
}
    
}
    
e.PropertyValue = propValue;
}

 

Published Wednesday, July 07, 2004 4:25 PM by Stefan_Gossner
Filed under: ,

Comments

Tuesday, July 20, 2004 11:49 AM by Frank Joppe

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Hi Stefan,

I have this problem while adding a posting. The page has an attachment, this attachment is browsed for - a local resource. When saving the page, we get the same error.

Do you have any ideas?
Tuesday, July 20, 2004 11:51 AM by Stefan

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

This cannot be the same problem.
Does the page save if this attachment is not added?
Tuesday, July 20, 2004 12:20 PM by Frank Joppe

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Thank you for your quick answer. We have checked, it seems that the user did not have rights on certain templates. An unexpected situation, because last week she had no problems at all and we are the only ones touching the site manager. Regranting rights solved our problem, now everything works fine again.
Tuesday, July 20, 2004 1:50 PM by Tobias

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

We have expirienced a similar problem:

If a uses an image from the resource gallery, and the image is deleted from the resource gallery, it is moved to an archived folder outside the normal channel/resource tree.
Thus only administrators have access rights - the posting (or rather, the image) can not even be viewed by anyone else, because they can not be subscribers.
Tuesday, July 20, 2004 1:55 PM by Stefan

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Exactly this is covered with the code above.
Wednesday, July 21, 2004 4:20 AM by RickG

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Hi Stefan,

When I try to use this code in my global.asax I get errors on the last portion of the code beginning with case "Src" (Invalid expression 'case'). Trying to correct it but I'm having difficulty getting around the errors.

Also noticed one typo in 'case "Html"' where 'ropValue' might need to be 'propValue'.

Thanks!

RickG
Wednesday, July 21, 2004 11:05 AM by Stefan

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Hi Rick,

you are right, there have been two typos: a brace "{" was missing and ropValue needed to be propValue.

The code above is now correct.

Cheers,
Stefan
Thursday, July 22, 2004 1:04 AM by Rick G

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Thanks Stefan!
Thursday, July 22, 2004 1:34 AM by RickG

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

Hi Stefan,

I have been testing this on my Test Server and have run into an error during a page Save while in Edit mode:

***Save Placeholder Failed***
Exception has been thrown by the target of an invocation.

I commented out your code and the Save works. I'll let you know if I find the cause. I do have other custom events in my app so it may be a conflict of some sort.
Thursday, July 29, 2004 6:01 PM by George Leithead

# re: Automatically cleanup placeholder content after resource gallery items have been deleted

I too get the same problem as RickG, in that I get the "Exception has been thrown by the target of an invocation".

Anyone found out why this is yet, and a solution?
Wednesday, February 23, 2005 4:36 AM by Stefan Go

# Dealing with links to deleted resources

Wednesday, March 02, 2005 9:17 AM by Stefan Go

# re: Dealing with links to deleted resources

New Comments to this post are disabled
 
Page view tracker