Category Archives: Sharepoint 2007

Requirements for SharePoint Groups when sending emails to them

I had a SharePoint designer workflow that send an email to a SharePoint group. In the History Log of the workflow, the follow message was logged:

The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly.

The outgoing email settings however were configure correctly (alerts and emails from other workflows were being send out).
There were actually two reasons why the emails weren’t being sent:
The settings ‘Who can view the membership of the group?’ on the group was configured as ‘Group Members’
The workflow is executed in the context of the current user. If the user has no access to view group membership, the workflow won’t be able to expand the group.
You should configure this settings as ‘Everyone’
image
The group had no permissions
The group should have at least ‘Read’ permission to the site. If the group has no permissions configured, you will receive the error as described above.
image

Content By Query WebPart outputs incorrect url when there is no root sitecollection

If you have a webapplication with no sitecollection at the root url (e.g. all site collection are located under http:///sites/…) and you use the CBQWP to query for list items (events / tasks./ … anything but documents), you will receive a ‘404 page not found’ when clicking the link.

The CBQWP uses the CopyUtil.aspx page to redirect you to the item in question (see http://weblogs.asp.net/jan/archive/2008/02/26/copyutil-aspx-a-little-sharepoint-gem.aspx). If there is no sitecollection at the root url, the site collection url will be missing from the url that is generated.

To solve this issue, edit the ‘ContentQueryMain.xslt’ file and change

<xsl:if test=”$UseCopyUtil = ‘True'”>
<xsl:value-of select=”concat(‘/_layouts/CopyUtil.aspx?Use=id&Action=dispform&ItemId=’,@ID,’&ListId=’,@ListId,’&WebId=’,@WebId,’&SiteId=’,$SiteId)”/>
</xsl:if>

into

<xsl:if test=”$UseCopyUtil = ‘True'”>
<xsl:value-of select=”concat($SiteUrl,’/_layouts/CopyUtil.aspx?Use=id&Action=dispform&ItemId=’,@ID,’&ListId=’,@ListId,’&WebId=’,@WebId,’&SiteId=’,$SiteId)”/>
</xsl:if>

Using javascript in the NavigateUrlFormat property of the SPMenuField

When you use an SPMenuField in an SPGridView, you can use the NavigateUrlFormat property to specify an url to navigate to when the users clicks the cell. Using the TokenNameAndValueFields and the NavigateUrlFields properties you can specified tokens in the Url that should be replaced with the underlying values from the datasource for each row in the grid. This all works fine, but when you try to use a javascript function in the NavigateUrlFormat property, the javascript function is never rendered.

SPMenuField colMenu = new SPMenuField();

colMenu.HeaderText = "Company";
colMenu.TextFields = "Company";

colMenu.MenuTemplateId = "mnuCompany";
colMenu.TokenNameAndValueFields = "COMPANYID=CompanyId";
colMenu.NavigateUrlFields = "CompanyId";
colMenu.NavigateUrlFormat = "javascript:alert('you have clicked company with id {0}');";
colMenu.SortExpression = "Company";

When you start digging around in the SharePoint libraries using reflector, you’ll see that reason for this is that the code that renders the menu (Microsoft.SharePoint.WebControls.Menu.Render(HtmlTextWriter)) makes a call to ‘SPHttpUtility.HtmlUrlAttributeEncode(string url)’ passing the value of the NavigateUrlFormat (in the SPMenuField class, the value of NavigateUrlFormat is passed to the NavigateUrl property of an internally create Microsoft.SharePoint.WebControls.Menucontrol).

The method SPHttpUtitlity.HtmlUrlAttributeEncode makes a call to SPUrlUtility.IsProtocolAllowedto verify is the requested protocol (javascript: in our case) is allowed. Since the ‘javascript’ protocal is not in the list, the link will simply not be rendered.

The list of allowed protocols is an hardcoded string array that is initialized in the constructor of SPUrlUtility.

 

static SPUrlUtility()
{
    m_rgstrAllowedProtocols = new string[] { "http://", "https://", "file://", @"file:\\", "ftp://", 
		"mailto:", "msn:", "news:", "nntp:", "pnm://", "mms://", "outlook:" };
}

 

The list of allowed protocols is available through the public AllowedProtocolsproperty, but it is read-only and since it’s an array, it’s not possible to add additional items to it.

As a workaround, I decided to replace one of the values in the AllowedProtocols array before I render my control in the Render event and set the initial value back when the rendering is done.

The downside of this approach is that any links using the protocol that you replace in the array will not be rendered (as it is no longer an allowed protocol). Therefore I chose to ‘replace’ one of the lesser used protocols: ‘pnm://’

As you can imagine, this is not best practice and even not recommended. Although the AllowedProtocols property is public and therefore should always be available (then again, who will stop MS from changing the public interfaces of their classes if they really want to?).

protected override void Render
{
	SPUrlUtility.AllowedProtocols[9] = "javascript:";
	try
	{

		base.Render(writer);
	}
	Finally
	{
    	SPUrlUtility.AllowedProtocols[9] = "pnm://";
	}
}

protected override void CreateChildControls()
{

	SPGridView grid = new SPGridView();

	SPMenuField colMenu = new SPMenuField();

	colMenu.HeaderText = "Company";
	colMenu.TextFields = "Company";

	colMenu.MenuTemplateId = "mnuCompany";
	colMenu.TokenNameAndValueFields = "COMPANYID=CompanyId";
	colMenu.NavigateUrlFields = "CompanyId";
	colMenu.NavigateUrlFormat = "javascript:alert('you have clicked company with id {0}');";
	colMenu.SortExpression = "Company";

	grid.Columns.Add(colMenu);

	this.Controls.Add(grid);

	... (rest of code ommitted)

}