Sunday February 05 , 2012

Posts Tagged ‘Sharepoint’

Sending Multiple Notifications in SharePoint

In Sharepoint there are many ways of notifying a user when an item gets updated on a list.

1. Setting up an alert.

2. Subscribing to an RSS Feed.

3. Using workflow via the List Settings, Sharepoint Designer or Visual Studio.

All these mechanisms have their pros and cons, but there is one thing that is not supported by any of them: Sending a notification to users when they are set up in a multi-choice person list within the SAME list. Additionally, 1 and 2 above require the user to set this up manually on their own, while 3  is much more complicated and has limitations. I chose to write my own Event Receiver in order to accomplish this task.

I won’t go into the details of creating an Event Receiver in Sharepoint and publishing it, since there is already a lot of documentation on this on the internet. In my example, the List Name is called “MyDocs” and the field that contains the users is called “Notifiers” (note: this field can contains a multiple users).

    public class MyDocsItemEventReceiver : SPItemEventReceiver
    {

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            base.ItemUpdated(properties);
            DisableEventFiring();

            try
            {
                SPListItem myDocsItem = properties.ListItem;
                var notifiers = myDocsItem["Notifiers"] as SPFieldUserValueCollection;
                SendEmailToNotifiers(notifiers);
            }
            finally
            {
                EnableEventFiring();
            }

        }
        private void SendEmailToNotifiers(SPFieldUserValueCollection _notifiers)
        {

            if (_notifiers != null)
            {
                List<string> _notifierList = new List<string>();

                foreach (SPFieldUserValue _notifier in _notifiers)
                {
                    if (!string.IsNullOrEmpty(_notifier.User.Email))
                        _notifierList.Add(_notifier.User.Email.Trim());
                }

                if (_notifierList.Count > 0)
                {
                    SmtpClient _smtpClient = new SmtpClient();
                    _smtpClient.Host = "email_server_name";
                    _smtpClient.Port = 25;
                    _smtpClient.EnableSsl = false;

                    MailMessage _mailMessage = new MailMessage();

                    foreach (string _reviewer in _notifierList)
                    {
                        _mailMessage.To.Add(new MailAddress(_reviewer));
                    }

                    _mailMessage.From = new MailAddress("fromaddress@company.com");
                    _mailMessage.Subject = "the subject line";
                    _mailMessage.Body = "the body of the email";

                    _smtpClient.Send(_mailMessage);
                }
            }

        }
}
You will need to import “System.Net.Mail” and get the mail server/port info, but it gives you the basis of accomplishing a very flexible solution for sending emails from an updated list. A possible use is to send notifications from Project Server 2007 when Issues/Risks are updated. The Event Receiver above will send emails to the users that are defined in the list item itself without having to create another list for lookup or managing a sharepoint group which usually required elevated privileges.
Enjoy!
 

Sharepoint (WSS/MOSS) Auditing VIEW On List Items

Recently I had a request from a client to log/audit when a user clicks on anything on a Sharepoint site. At first I thought, this will be easy, I will just turn on Auditing and select to log all VIEWs on all Items and then produce a report based on the Audit log. Well, things were not that simple.

It appears that Sharepoint logs VIEWs for Document Libraries very well, but fails miserably for logging VIEWs on every other type of Item, including Picture Libraries (this is true for WSS and MOSS). Basically, Sharepoint logs the List that the Item is contained in, but there is no logging as to the actual Item that was clicked on. So after Googling around bit I found that there was very little information on how to get around this and wanted to post a solution that works for most Items, but still fails for certain ones, e.g. Discussion Items for one. Maybe someone else here can enhance this solution to grab the missing ones.

My solution involves a custom HttpModule (not an HttpHandler), that inspects the IIS requests and if can load the Sharepoint context, Site, List and Item, then it manually adds the Audit Entry via the Sharepoint Object Model. This approach is only needed for non Document Libraries, since the regular Sharepoint Auditing does a better job at logging these types of Items.

The code for the HttpModule is below. You will need to do a bit of research on how to deploy an HttpModule, but there is plenty of information on this on the web. Essentially, you will need to compile this, strong name it, deploy it to the GAC and add an entry to the web.config of the Sharepoint site you wish to Audit.

Enjoy!

Imports System.Web
Imports Microsoft.SharePoint

Public Class AuditViewHttpModule
    Implements IHttpModule

    Public Sub Dispose() Implements System.Web.IHttpModule.Dispose

    End Sub

    Public Sub Init(ByVal context As System.Web.HttpApplication) _
    Implements System.Web.IHttpModule.Init

        AddHandler context.PreRequestHandlerExecute, _
        AddressOf Application_PreRequestHandlerExecute
    End Sub

    Private Sub Application_PreRequestHandlerExecute( _
        ByVal _source As Object, ByVal e As EventArgs)

        Dim _application As HttpApplication = Nothing
        Dim _context As HttpContext = Nothing

        Try

            _application = CType(_source, HttpApplication)
            _context = _application.Context

            Dim _site As SPSite = SPContext.Current.Site
            Dim _list As SPList = SPContext.Current.List
            Dim _item As SPListItem = SPContext.Current.ListItem

            If Not _site Is Nothing Then
                If Not _list Is Nothing Then
                    If Not _item Is Nothing Then
                        If _
                        _list.BaseTemplate <> _
                        SPListTemplateType.DocumentLibrary _
                        Then

                            _list.Audit.WriteAuditEvent( _
                            SPAuditEventType.View, "", "")
                        End If
                    End If
                End If
            End If

        Catch ex As Exception
            ' handle the error otherwise your
            ' sharepoint pages will crash!
        End Try
    End Sub

End Class
 

Sharepoint/WSS – Getting a list of files in a folder

Recently I had a request from a client to upload a random set of files on a user’s desktop folder into a SharePoint folder. This part of it was not tricky since you can use the System.Net.WebClient.UploadFile() method to accomplish the task. The problem I encountered was that the UploadFile() method does not check for an existing file with the same name on the specified SharePoint folder.

For this reason, I created a custom function that returns to me the list of files in a SharePoint Folder. I could then use this to warn the user if a file with the same name already exists on the SharePoint folder and have him/her take a manual action. The function uses the SharePoint List Web Service GetListItems() method and parses the XML in order to get the files in the folder queried.

Enjoy!

Private Function GetListOfFilesInSPFolder(ByVal listsWS As WebSvcLists.Lists, _
         ByVal folderPath As String) As List(Of String)
        Dim _files As List(Of String) = New List(Of String)

        ' set up xml  doc for getting list of files under a folder
        Dim doc As XmlDocument = New XmlDocument()
        Dim queryOptions As XmlElement = doc.CreateElement("QueryOptions")
        queryOptions.InnerXml = "<Folder>" & folderPath & "</Folder>"

        ' get the list of files
        Dim listItemsNode As XmlNode = listsWS.GetListItems( _
        WssDocumentLibraryRootFolder, Nothing, _
        Nothing, Nothing, Nothing, queryOptions, Nothing)

        Dim xmlResultsDoc As XmlDocument = New XmlDocument()
        xmlResultsDoc.LoadXml(listItemsNode.OuterXml)
        Dim ns As XmlNamespaceManager = New XmlNamespaceManager(xmlResultsDoc.NameTable)
        ns.AddNamespace("z", "#RowsetSchema")

        For Each row As XmlNode In xmlResultsDoc.SelectNodes("//z:row", ns)
            _files.Add(row.Attributes("ows_LinkFilename").Value)
        Next

        Return _files
End Function