Thursday, October 9, 2008

Customizing Search results

Scenario:
You want to customize the search results page.

Solution:
Apply a new XSLT the 'Search Core Results' webpart, to make it simpler you can look at the result XML using the below XSLT.

Code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xmp><xsl:copy-of select="*"/></xmp>
</xsl:template>
</xsl:stylesheet>
Article:
http://www.codeplex.com/sctxsl/Release/ProjectReleases.aspx?ReleaseId=12070 ( XSL Samples )
http://msdn.microsoft.com/en-us/library/ms550732.aspx
http://blogs.catapultsystems.com/matthew/archive/2008/08/28/create-a-xml-test-page-for-search-results.aspx

Wednesday, October 8, 2008

Testing code in sharepoint context

Scenario:
You want to test the webpart code in sharepoint context
Solution:
You can use the Visual Studio Test classes. Code sample shows both using Context and without context.

Code(Without Context):

public static string GetSiteTitle(string url) { 
SPSite site = new SPSite(url);
string title = site.RootWeb.Title;
site.RootWeb.Dispose();
site.Dispose();
return title;
}

[TestMethod()]
public void GetSiteTitleTest() {
string url = http://localhost;
string expected = "Home";
string actual = MyClass.GetSiteTitle(url);
Assert.AreEqual(expected, actual);
}
Code(With Context):
public static string GetSiteTitle() { 
SPSite site = SPContext.Current.Site;
string title = site.RootWeb.Title;
return title;
}

[TestMethod()]
[HostType("ASP.Net")]
[UrlToTest("http://localhost/default.aspx")]
public void GetSiteTitleTest() {
string expected = "Home";
string actual = MyClassName.GetSiteTitle();
Assert.AreEqual(expected, actual);
}
Article:
http://blogs.msdn.com/mcsnoiwb/archive/2008/10/08/unit-testing-sharepoint-code.aspx

Sunday, October 5, 2008

Checking user permission for lists

Scenario:
You want to check user permission on all the lists
Solution:
You can develop a webpart and using object model you can check that.

Code:

StringBuilder sb = new StringBuilder();
sb.Append("<UL>");

SPSite sitecol = SPContext.Current.Site;
SPWeb site = SPContext.Current.Web;
SPUser user = SPContext.Current.Web.CurrentUser;

SPSecurity.RunWithElevatedPrivileges( delegate() {
using (SPSite elevatedSiteCol = new SPSite(sitecol.ID)) {
using (SPWeb elevatedSite = elevatedSiteCol.OpenWeb(site.ID)) {
foreach (SPList list in elevatedSite.Lists) {
if (list.DoesUserHavePermissions(user,SPBasePermissions.ViewListItems))
{
sb.Append("<LI><a href='" + list.RootFolder.Url + "'>" + list.Title + "</a></LI>");
}
else
{
sb.Append("<LI style='color:red'>" + list.Title + "</LI>");
}
}
}
}
}
);

sb.Append("</UL>");
Note:
http://daniellarson.spaces.live.com/blog/cns!D3543C5837291E93!2005.entry?wa=wsignin1.0&sa=201418415

Saturday, October 4, 2008

SharePoint Element.xml examples

Element.xml:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

<Field ID="NewGUID(with Braces)" Type="Text" DisplayName="NewColumnName" Name="NewColumnName" Description="This is new column" Group="SharePoint Training" Indexed="TRUE" Required="TRUE" Sealed="TRUE"></Field>

<ContentType ID="0x01NewGuidwithBracesAnd(-)"
Name="New Content Type"
Description="This is a new content type" Group="SharePoint Training" >
<FieldRefs>
<FieldRef ID="GUIDForTheFieldCreatedAbove(with Braces)" Name="NewColumnName" />
<RemoveFieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title"/>
</FieldRefs>
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
<spe:Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
<spe:Receiver>
<spe:Name>NewContentTypeDeleteHandler</spe:Name>
<spe:Type>ItemDeleting</spe:Type>
<spe:Assembly>AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5</spe:Assembly>
<spe:Class>NameSpace.NewContentTypeEventHandler</spe:Class>
</spe:Receiver>
</spe:Receivers>
</XmlDocument>

<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Display>NewContentTypeListForm</Display>
</FormTemplates>
</XmlDocument>
</XmlDocuments>
</ContentType>

<ListInstance FeatureId="GUIDofTheFeatureHavingListTemplateDefinition(withoutBraces)"
Title="New List Display Name" Url="Lists/NewListName">
</ListInstance>

<ContentTypeBinding ContentTypeId="0x01NewGuidwithOutBracesAnd(-)SameAsUsedAbove" ListUrl="Lists/NewListName" />

</Elements>
Article:

Programatically adding nodes to Top Navigation Control

Scenario:
You want to programatically add node to Top Navigation Control

Solution:
You can add child nodes to Site Collection's TopNavigationBar

Code:

using (SPWeb site = new SPSite("http://localhost")) {

SPNavigationNodeCollection topNav = site.Navigation.TopNavigationBar;

// create top navigation tab & add to top nav bar
SPNavigationNode topNavMenuItem = new SPNavigationNode("Site Collection Galleries", string.Empty, false);
topNav[0].Children.AddAsLast(topNavMenuItem);

// create first drop down pointing to Master Page Gallery
SPNavigationNode mpg = new SPNavigationNode("Master Page Gallery", string.Format("{0}/_catalogs/masterpage", site.Url), true);
topNavMenuItem.Children.AddAsFirst(mpg);

// create first drop down pointing to Web Part Gallery
SPNavigationNode wpg = new SPNavigationNode("Web Part Gallery", string.Format("{0}/_catalogs/wp", site.Url), true);
topNavMenuItem.Children.AddAsLast(wpg);

// create first drop down pointing to List Template Gallery
SPNavigationNode ltg = new SPNavigationNode("List Template Gallery", string.Format("{0}/_catalogs/lt", site.Url), true);
topNavMenuItem.Children.AddAsLast(ltg);

// create first drop down pointing to Site Template Gallery
SPNavigationNode stg = new SPNavigationNode("Site Template Gallery", string.Format("{0}/_catalogs/wt", site.Url), true);
topNavMenuItem.Children.AddAsLast(stg);

// commit the changes
site.Update();
}
Article:

Friday, October 3, 2008

Adding Title(with menu) field for Document Library

Scenario:
Out-of-box SharePoint allow to have context menu for 'Name' column only. Now you want to have similar Context Menu for 'Title' field also.

Solution:
Add a new field of type 'Title(with menu)' using Object Model.

Code:

using Microsoft.SharePoint; 

public void AddNewTitleFieldWithMenu()
{
string fieldTitle = "Title";
Guid fieldId = Guid.NewGuid();

using (SPSite site = new SPSite("http://localhost")) {
using (SPWeb web = site.OpenWeb()) {

SPList list = web.Lists["Shared Documents"];

string fieldDef = @"<Field ID='" + (fieldId.ToString()) + @"' SourceID='http://schemas.microsoft.com/sharepoint/v3'
Name='" + fieldTitle + @"'
StaticName='" + fieldTitle + @"'
Group='Custom Fields'
ReadOnly='TRUE'
Type='Computed'
DisplayName='" + fieldTitle + @"'
DisplayNameSrcField='FileLeafRef'
Filterable='FALSE'
ClassInfo='Menu'
AuthoringInfo='(with menu v1)'><!-- _locID@DisplayName='camlionet75' _locComment=' ' --><!-- _locID@AuthoringInfo='115' _locComment=' ' -->
<FieldRefs>
<FieldRef ID='{fa564e0f-0c70-4ab9-b863-0177e6ddd247}' Name='Title'/>
<FieldRef ID='{687c7f94-686a-42d3-9b67-2782eac4b4f8}' Name='FileLeafRef'/>
<FieldRef ID='{3c6303be-e21f-4366-80d7-d6d0a3b22c7a}' Name='_EditMenuTableStart'/>
<FieldRef ID='{2ea78cef-1bf9-4019-960a-02c41636cb47}' Name='_EditMenuTableEnd'/>
<FieldRef ID='{9d30f126-ba48-446b-b8f9-83745f322ebe}' Name='LinkFilenameNoMenu'/>
<FieldRef ID='{687c7f94-686a-42d3-9b67-2782eac4b4f8}' Name='FileLeafRef'/>
<FieldRef ID='{30bb605f-5bae-48fe-b4e3-1f81d9772af9}' Name='FSObjType'/>
<FieldRef ID='{998b5cff-4a35-47a7-92f3-3914aa6aa4a2}' Name='Created_x0020_Date'/>
<FieldRef ID='{94f89715-e097-4e8b-ba79-ea02aa8b7adb}' Name='FileRef'/>
<FieldRef ID='{39360f11-34cf-4356-9945-25c44e68dade}' Name='File_x0020_Type'/>
<FieldRef ID='{03e45e84-1992-4d42-9116-26f756012634}' Name='ContentTypeId'/>
</FieldRefs>
<DisplayPattern>
<FieldSwitch>
<Expr><GetVar Name='FreeForm'/></Expr>
<Case Value='TRUE'><Field Name='LinkFilenameNoMenu'/></Case>
<Default>
<Field Name='_EditMenuTableStart'/>

<IfEqual>
<Expr1><LookupColumn Name='FSObjType'/></Expr1>
<Expr2>1</Expr2>
<Then>
<FieldSwitch><Expr><GetVar Name='RecursiveView'/></Expr>
<Case Value='1'>
<LookupColumn Name='FileLeafRef' HTMLEncode='TRUE'/>
</Case>
<Default>
<SetVar Name='UnencodedFilterLink'>
<SetVar Name='RootFolder'><HTML>/</HTML><LookupColumn Name='FileRef'/></SetVar>
<SetVar Name='FolderCTID'>
<FieldSwitch><Expr><ListProperty Select='EnableContentTypes'/></Expr>
<Case Value='1'><Column Name='ContentTypeId'/></Case>
</FieldSwitch>
</SetVar>
<FilterLink Default='' Paged='FALSE'/>
</SetVar>
<HTML><![CDATA[<A onfocus='OnLink(this)' HREF=']]></HTML>
<GetVar Name='UnencodedFilterLink' HTMLEncode='TRUE'/>
<HTML><![CDATA[' onclick='javascript:EnterFolder(']]></HTML>
<ScriptQuote NotAddingQuote='TRUE'><GetVar Name='UnencodedFilterLink'/></ScriptQuote>
<HTML><![CDATA[');javascript:return false;'>]]></HTML>
<LookupColumn Name='FileLeafRef' HTMLEncode='TRUE'/>
<HTML><![CDATA[</A>]]></HTML>
</Default>
</FieldSwitch>
</Then>
<Else>
<HTML><![CDATA[<A onfocus='OnLink(this)' HREF=']]></HTML>
<Field Name='EncodedAbsUrl'/>
<HTML><![CDATA[' onclick='DispDocItemEx(this,']]></HTML>
<ServerProperty Select='HtmlTransform'/>
<HTML><![CDATA[',']]></HTML>
<ServerProperty Select='HtmlTrAcceptType'><Column Name='File_x0020_Type'/></ServerProperty>
<HTML><![CDATA[',']]></HTML>
<ServerProperty Select='HtmlTrHandleUrl'><Column Name='File_x0020_Type'/></ServerProperty>
<HTML><![CDATA[',']]></HTML>
<ServerProperty Select='HtmlTrProgId'><Column Name='File_x0020_Type'/></ServerProperty>
<HTML><![CDATA[')'>]]></HTML>
<UrlBaseName HTMLEncode='TRUE'><LookupColumn Name='Title'/></UrlBaseName>
<HTML><![CDATA[</A>]]></HTML>
<IfNew Name='Created_x0020_Date'>
<HTML><![CDATA[<IMG SRC='/_layouts/1033/images/new.gif' alt=']]></HTML>
<HTML>$Resources:core,new_gif_alttext</HTML><HTML><![CDATA['>]]></HTML>
</IfNew>
</Else>
</IfEqual>
<Field Name='_EditMenuTableEnd'/>
</Default>
</FieldSwitch>
</DisplayPattern>
</Field>";

list.Fields.AddFieldAsXml(fieldDef, true, SPAddFieldOptions.AddToAllContentTypes);
}
}
}

Wednesday, October 1, 2008

Sending email to user few days before document expires

Scenario:
Out-of-Box Expiration policy simply delete the document without sending any confirmation few days before Expiration Date is reached

Solution:
You can write a console application and schedule it to Run every night. This application will basically check if any document is expiring in next 30 days and will send an email to the Last Modified User

Code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Mail;
using System.Configuration;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace ExpiringDocumentsEmail
{
class Program
{
static void Main(string[] args)
{
try
{
string sSiteUrl = ConfigurationManager.AppSettings["Site"];
string[] sLists = COnfigurationManager.AppSettings["Lists"]).Split(',');
string sDateColumnName = ConfigurationManager.AppSettings["DateColumnName"];
string sEmailToColumnName = ConfigurationManager.AppSettings["EmailToColumnName"];
string sMailSubject = ConfigurationManager.AppSettings["Subject"];
string sGapInDays = ConfigurationManager.AppSettings["GapInDays"];
string sViewName = ConfigurationManager.AppSettings["ViewName"];

using (SPSite oSPSite = new SPSite(sSiteUrl))
{
using (SPWeb oSPWeb = oSPSite.OpenWeb())
{
foreach (string listName in sLists)
{
SPList oSPList = oSPWeb.Lists[listName];

foreach (SPListItem oSPListItem in oSPList.Items)
{
System.TimeSpan dateDiff = new System.TimeSpan(((DateTime)oSPListItem[sDateColumnName]).Ticks - DateTime.Now.Ticks);

// Console.WriteLine(((long)dateDiff.Days).ToString());

if ((long)dateDiff.Days == int.Parse(sGapInDays))
{
SPUser user = oSPWeb.SiteUsers.GetByID(Convert.ToInt32(oSPListItem[sEmailToColumnName].ToString().Split(';')[0]));
if (user.Email.ToString().Length > 0)
{
SendEmail(user.Email.ToString(), sMailSubject, oSPSite.Url + oSPList.Views[sViewName].ServerRelativeUrl);
}
}
}
}
}
}

// Console.Read();
}
catch ( Exception ex )
{
// Console.WriteLine(ex.ToString());
// Console.Read();
}
}

public static void SendEmail(string toAddress, string subject, string ListUrl)
{

string smtpServer = System.Configuration.ConfigurationManager.AppSettings["SmtpServer"];
string fromUser = System.Configuration.ConfigurationManager.AppSettings["EmailFrom"];

MailMessage message = new MailMessage(fromUser, toAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = "You can navigate to the expiring document by click " + "<a href=\"" + ListUrl + "\">here</a>. This is an auto generated email. Please do not reply.";

try
{
SmtpClient client = new SmtpClient(smtpServer);
//client.Send(message);
client.SendAsync(message,"mail sent.");
}
catch { }
}
}
}
Application Configuration (App.Config):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Site" value="http://localhost/"/>
<add key="Lists" value="Shared Documents,Client Documents"/>
<add key="ViewName" value="Expiring"/>
<add key="GapInDays" value="30"/>
<add key="DateColumnName" value="Expiring Date"/>
<add key="EmailToColumnName" value="Modified By"/>
<add key="Subject" value="Document expires in 30 days"/>
<add key="SmtpServer" value="mailhost.training.com"/>
<add key="EmailFrom" value="admin@training.com"/>
</appSettings>
</configuration>