RESOLUTION
To resolve this issue, use the following code example to create a form that uses the URL of a specific posting to iterate all the resources and postings that require resource gallery user rights.
Note To quickly discover the resources that are used in a specific posting, you can write code to do the following:
- Open the posting.
- Enumerate the placeholders.
- Search with a regular expression to find resources and postings that are referenced.
- Produce an exact list of resources that the administrator can use to verify or set rights on in Site Manager.
Note The following code example uses the MCMS Woodgrove sample site as an example. Use this code example as an example of how you can modify your Web site to resolve this issue.
For additional information about the Woodgrove site, visit the following Microsoft Web site:
The following three files can be added to a Microsoft Visual Studio development system project to be used against the Woodgrove sample site:
- SavePlaceholder.aspx.cs
- SavePlaceholder.aspx.resx
- SavePlaceholder.aspx
Microsoft provides programming examples for illustration only, without warranty either expressed or implied. This includes, but is not limited to, the implied warranties of merchantability or fitness for a particular purpose. This article assumes that you are familiar with the programming language that is being demonstrated and with the tools that are used to create and to debug procedures. Microsoft support engineers can help explain the functionality of a particular procedure, but they will not modify these examples to provide added functionality or construct procedures to meet your specific requirements.
SavePlaceholder.aspx.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using Microsoft.ContentManagement.WebControls;
using Microsoft.ContentManagement.Publishing;
using Microsoft.ContentManagement.Publishing.Extensions.Placeholders;
using System.Text.RegularExpressions;
using System.Text;
namespace WoodgroveNet
{
/// <summary>
/// Summary description for SavePlaceholder.
/// </summary>
public class SavePlaceholder : System.Web.UI.Page
{
protected System.Web.UI.WebControls.TextBox txtGuid;
protected System.Web.UI.WebControls.Button btnSubmitGuid;
protected System.Web.UI.WebControls.TextBox txtPath;
protected System.Web.UI.WebControls.Label lblReport;
protected System.Web.UI.WebControls.Button btnSubmitPath;
private void Page_Load( object sender, System.EventArgs e )
{
lblReport.Text = "";
}
void GetObjectPaths( IEnumerable ieList )
{
if( ieList == null )
return;
System.Collections.IEnumerator
iEnumerator = ieList.GetEnumerator();
while ( iEnumerator.MoveNext() )
{
// Because we are passing in a list of the
// GUID, we get the object and output the path.
WriteInfo(
CmsHttpContext.Current.Searches.GetByGuid(
"{" + iEnumerator.Current+ "}" ).Path,
false );
}
}
// This code is to parse the attachment and image
// placeholders because they are not fully qualified
// HTML but just a string that represents the path
// the resource.
ArrayList DumpHrefs( String inputString, bool bHTML )
{
Regex r;
Match m;
if( inputString == null )
return null;
ArrayList alURL = new ArrayList();
// This constant will be the first part in the event
// that we are parsing HTML placeholders. If this is
// the case, we will extend the search to parse
// out only items that start with an href.
const string strHTML = "(href|src)\\s*=\\s*\"";
// Because Image and Attachment placeholders only have
// the path and no real HTML, we just have to extract
// the GUID. This will also be appended to the
// strHTML later to extract just the GUID.
//
// By putting <1> in the expression, we can make sure
// that the GUID will be in slot 1 for the match.
const string strCMSObject = "(/NR/RDONLYRES/|/NR/EXERES/)" +
"(?<1>[a-f,0-9]{8}-[a-f,0-9]{4}" +
"-[a-f,0-9]{4}-[a-f,0-9]{4}" +
"-[a-f,0-9]{12})";
string strRegex = "";
if(bHTML)
{
strRegex = strHTML + strCMSObject;
}
else
{
strRegex = strCMSObject;
}
r = new Regex( strRegex,
RegexOptions.IgnoreCase | RegexOptions.Compiled );
for( m = r.Match( inputString ); m.Success; m = m.NextMatch() )
{
// We get the first index because we specified <1>
// in the earlier expression.
if( !alURL.Contains( m.Groups[1].Value ) )
alURL.Add( m.Groups[1].Value );
}
return alURL;
}
void EnumPlaceholders(Posting pPosting)
{
if(pPosting == null)
return;
// Because we have a posting, we will then loop through
// each of the placeholders and then pass their appropriate
// content based on their type.
foreach(
Microsoft.ContentManagement.Publishing.Placeholder ph
in pPosting.Placeholders )
{
ArrayList alURL;
WriteInfo(
string.Format( "PlaceholderName : {0}",ph.Name ),
true);
switch(ph.GetType().ToString())
{
case "Microsoft.ContentManagement.Publishing." +
"Extensions.Placeholders.HtmlPlaceholder" :
{
alURL = DumpHrefs(((HtmlPlaceholder)ph).Html, true );
GetObjectPaths(alURL);
break;
}
case "Microsoft.ContentManagement.Publishing." +
"Extensions.Placeholders.AttachmentPlaceholder" :
{
alURL = DumpHrefs(
( ( AttachmentPlaceholder ) ph ).Url,
false);
GetObjectPaths( alURL );
alURL = DumpHrefs(
( ( AttachmentPlaceholder ) ph ).IconUrl,
False );
GetObjectPaths( alURL );
break;
}
case "Microsoft.ContentManagement.Publishing." +
"Extensions.Placeholders.ImagePlaceholder" :
{
alURL = DumpHrefs( ( ( ImagePlaceholder ) ph ).Href, false );
GetObjectPaths( alURL );
alURL = DumpHrefs( ( ( ImagePlaceholder) ph ).Src, false );
GetObjectPaths( alURL );
break;
}
default:
{
WriteInfo("Parse information is not available for " +
"this placeholder", false);
break;
}
}
WriteInfo("", false);
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit( e );
}
private void InitializeComponent()
{
this.btnSubmitPath.Click +=
new System.EventHandler( this.btnSubmitPath_Click );
this.btnSubmitGuid.Click +=
new System.EventHandler( this.btnSubmitGuid_Click );
this.Load += new System.EventHandler( this.Page_Load );
}
#endregion
private void btnSubmitGuid_Click(object sender, System.EventArgs e)
{
try
{
Posting pPosting =
( Posting ) CmsHttpContext.Current.Searches.GetByGuid(
"{" + txtGuid.Text + "}" );
EnumPlaceholders( pPosting );
}
catch(Exception ex)
{
string strMessage =
string.Format(
"There was an error retrieving the Posting for {0}",
txtGuid.Text);
WriteInfo(strMessage, true);
strMessage = string.Format("Exception: {0}", ex.Message);
WriteInfo(strMessage, true);
}
}
private void btnSubmitPath_Click(object sender, System.EventArgs e)
{
try
{
Posting pPosting =
( Posting ) CmsHttpContext.Current.Searches.GetByUrl(
txtPath.Text );
EnumPlaceholders(pPosting);
}
catch(Exception ex)
{
string strMessage = string.Format(
"There was an error retrieving the Posting for {0}",
txtPath.Text );
WriteInfo( strMessage, true );
strMessage = string.Format( "Exception: {0}", ex.Message );
WriteInfo( strMessage, true );
}
}
void WriteInfo(string strMessage, bool isBold)
{
Label label = new Label();
label.Text = strMessage + "<BR>";
if(isBold)
label.Font.Bold = true;
lblReport.Controls.Add( label );
}
}
}
SavePlaceholder.aspx.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="$this.TrayAutoArrange" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</data>
<data name="$this.DefaultModifiers" type="System.CodeDom.MemberAttributes, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Private</value>
</data>
<data name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</data>
</root>
SavePlaceholder.aspx
<%@ Register TagPrefix="uc1" TagName="DefaultConsole" Src="Console/DefaultConsole.ascx" %>
<%@ Page language="c#" Codebehind="SavePlaceholder.aspx.cs" AutoEventWireup="false" Inherits="WoodgroveNet.SavePlaceholder" %>
<%@ Register TagPrefix="cms" Namespace="Microsoft.ContentManagement.WebControls" Assembly="Microsoft.ContentManagement.WebControls, Version=5.0.1200.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>SavePlaceholder</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:textbox id="txtGuid" style="Z-INDEX: 101; LEFT: 200px; POSITION: absolute; TOP: 56px" runat="server"
Width="296px"></asp:textbox><asp:button id="btnSubmitPath" style="Z-INDEX: 106; LEFT: 504px; POSITION: absolute; TOP: 128px"
runat="server" Text="Submit"></asp:button><asp:label id="Label2" style="Z-INDEX: 105; LEFT: 16px; POSITION: absolute; TOP: 128px" runat="server">Enter Path of Posting</asp:label>
<asp:TextBox id="txtPath" style="Z-INDEX: 104; LEFT: 200px; POSITION: absolute; TOP: 128px" runat="server"
Width="296px"></asp:TextBox>
<asp:Label id="Label1" style="Z-INDEX: 103; LEFT: 16px; POSITION: absolute; TOP: 56px" runat="server">Enter GUID of Posting</asp:Label>
<asp:Button id="btnSubmitGuid" style="Z-INDEX: 102; LEFT: 504px; POSITION: absolute; TOP: 56px"
runat="server" Text="Submit"></asp:Button>
<asp:Label id="lblReport" runat="server" style="Z-INDEX: 107; LEFT: 24px; POSITION: absolute; TOP: 176px"
Height="16px">Label</asp:Label></form>
</body>
</HTML>
Note If appropriate, an administrator can then use Site Manager to grant rights on the appropriate resource containers for Author 2. The result that you want is to have Author 1 and Author 2 share the same rights on all referenced resource gallery containers.