Click here to Skip to main content
15,896,606 members
Articles / Web Development / ASP.NET

Send scheduled Reminder/Alerts by email in SharePoint

Rate me:
Please Sign up or sign in to vote.
4.87/5 (14 votes)
24 Mar 2009CPOL12 min read 595.1K   2.1K   67  
Learn how to create a SharePoint Job that queries lists and sends results via email.
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using System.Runtime.InteropServices;
using System.ComponentModel;
using Microsoft.SharePoint;
using Mullivan.SharePoint.WebControls;
using System.Web.UI.WebControls;
using System.Xml;
using System.Web;
using System.Web.UI;
using Microsoft.SharePoint.WebPartPages.Communication;
using System.Security;
using Microsoft.SharePoint.WebControls;

namespace Mullivan.SharePoint.WebParts
{
    [Guid("90f69852-2345-8786-8aad-35f177b7aaaa")]
    [XmlRoot(Namespace = "ListQueryWebPart")]
    public class ListQueryWebPart : Microsoft.SharePoint.WebPartPages.WebPart, IWebEditable
    {
        private const uint DEFAULT_PAGESIZE = 20;
        private string _errorMessage = null;
        private SPList _list = null;
        private Button _btnSearch = null;
        private XmlDocument _xDocQuery = null;
        private List<InputField> _inputFields = null;

        public ListQueryWebPart()
            : base()
        {
            this.PageSize = DEFAULT_PAGESIZE;
        }

        [Browsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public string Query
        {
            get;
            set;
        }

        [Browsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public string ListUrl
        {
            get;
            set;
        }

        [Browsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public string ViewFields
        {
            get;
            set;
        }

        [Browsable(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public uint PageSize
        {
            get;
            set;
        }

        public ListQueryData CurrentQuery
        {
            get
            {
                return (ListQueryData)this.ViewState["CurrentQuery"];
            }
            set
            {
                this.ViewState["CurrentQuery"] = value;
            }
        }

        [ConnectionProvider("List Query Provider", "listQueryProvider")]
        public ListQueryData GetQueryData()
        {
            return this.CurrentQuery;
        }

        protected override void OnInit(EventArgs e)
        {
            try
            {
                base.OnInit(e);

                if (string.IsNullOrEmpty(this.ListUrl)
                    || string.IsNullOrEmpty(this.ViewFields)
                    || string.IsNullOrEmpty(this.Query))
                    return;

                _btnSearch = new Button();
                _btnSearch.ID = "btnSearch";
                _btnSearch.Text = "Search";
                _btnSearch.Click += new EventHandler(_btnSearch_Click);

                _list = GetList();

                if (_list == null)
                    return;

                _xDocQuery = new XmlDocument();
                _xDocQuery.LoadXml("<Query>" + this.Query + "</Query>");

                _inputFields = GetInputFields(_xDocQuery);

                Literal litTableStart = new Literal();
                litTableStart.Text = @"<table cellpadding=""1"" cellspacing=""0"">";
                this.Controls.Add(litTableStart);

                int idx = 0;
                foreach (InputField field in _inputFields)
                {
                    AppendFieldControl(field, idx);
                    idx++;
                }

                Literal litButtonRow = new Literal();
                litButtonRow.Text = @"
<tr>
    <td colspan=""3"" style=""padding-top:5px;padding-bottom:5px;text-align:right;"" />";
                this.Controls.Add(litButtonRow);
                this.Controls.Add(_btnSearch);

                Literal litTableEnd = new Literal();
                litTableEnd.Text = "</td></tr></table>";
                this.Controls.Add(litTableEnd);
            }
            catch (Exception ex)
            {
                _errorMessage = ex.ToString();
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);


            //Make sure the consumer only updates when the
            //when the search button is clicked
            ListQueryData lqd = this.CurrentQuery;
            if (lqd != null)
            {
                lqd.IsNew = false;
                this.CurrentQuery = lqd;
            }
        }

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            if (_errorMessage != null)
                writer.Write(HttpUtility.HtmlEncode(_errorMessage).Replace("\n", "<br/>"));
            else
                base.Render(writer);
        }

        protected void _btnSearch_Click(object sender, EventArgs e)
        {
            if (!ValidateInputControls())
                return;

            ListQueryData lqd = new ListQueryData();
            lqd.ListId = _list.ID;
            lqd.ViewFields = this.ViewFields;
            lqd.IsNew = true;
            lqd.PageSize = this.PageSize;
          
            using (SPWeb web = _list.ParentWeb)
            {
                lqd.WebId = web.ID;      
            }

            lqd.Query = BuildQuery();

            this.CurrentQuery = lqd;
        }

        private string BuildQuery()
        {
            int idx = -1;
            foreach (Control c in this.Controls)
            {
                if (c is SPFieldRenderer)
                {
                    idx++;
                    SPFieldRenderer renderer = (SPFieldRenderer)c;
                    string value = renderer.Value;

                    InputField inputField = _inputFields[idx];


                    XmlElement xeValue = inputField.Document.CreateElement("Value");
                    if (!string.IsNullOrEmpty(value) || inputField.ComparerNode.ParentNode.Equals("Where"))
                    {
                        value = SecurityElement.Escape(value);
                        xeValue.SetAttribute("Type", inputField.SPField.TypeAsString);
                        if (inputField.SPField.Type == SPFieldType.DateTime)
                            xeValue.SetAttribute("IncludeTimeValue", "TRUE");
                        
                        xeValue.InnerText = value;
                        //Replace the User Input node with the value node
                        inputField.UserInputNode.ParentNode.ReplaceChild(xeValue, inputField.UserInputNode);
                    }
                    else //If the value is empty then the user doens't want to filter on that value so 
                        //we need to replace it according to the Nest Type
                    {
                        XmlElement xeImpersonateCondition = null;

                        if (inputField.ComparerNode.ParentNode.Name.Equals("And"))
                            //If the Parent Nest is an And then we always want this condition to validate
                            // as true so that if the sibling condition is true then the whole nest will be true
                            xeImpersonateCondition = inputField.Document.CreateElement("IsNotNull");
                        else
                            //If the parent nest is an Or then we always want this condition to validate 
                            //as false so that if the sibling condition is false then the nest will fail as well
                            xeImpersonateCondition = inputField.Document.CreateElement("IsNull");

                        //This all words because the ID fill we never be null... so if we base our condition
                        //of of it being null or not being null then we can control the validation of this nest
                        XmlElement xeFieldRefID = inputField.Document.CreateElement("FieldRef");
                        xeFieldRefID.SetAttribute("Name", "ID");

                        xeImpersonateCondition.AppendChild(xeFieldRefID);

                        inputField.ComparerNode.ParentNode.ReplaceChild(xeImpersonateCondition, inputField.ComparerNode);
                    }
                }
            }

            return _xDocQuery.DocumentElement.InnerXml;
        }

        private bool ValidateInputControls()
        {
            bool isValid = true;

            foreach (Control c in this.Controls)
            {
                if (c is SPFieldRenderer)
                {
                    SPFieldRenderer renderer = (SPFieldRenderer)c;
                    renderer.Validate();
                    if (!renderer.IsValid)
                        isValid = false;
                }
            }

            return isValid;
        }

        private void AppendFieldControl(InputField field, int index)
        {
            SPFieldRenderer renderer = new SPFieldRenderer();
            renderer.ID = "editControl_" + index.ToString() + "_";
            renderer.Field = field.SPField;
            renderer.List = _list;
            renderer.Value = field.SPField.DefaultValue;

            Literal litStart = new Literal();
            litStart.Text = string.Format(@"
    <TR>
		<TD nowrap=""true"" valign=""top"" width=""190px"" class=""ms-formlabel""><H3 class=""ms-standardheader"">
		<nobr>{0}</nobr>
	    </H3>
        </TD>
        <TD nowrap=""true"" valign=""top"" width=""30px"" class=""ms-formlabel"" style=""text-align:right;padding-right:3px"">
		<nobr>{1}</nobr>
        </TD>
		<TD valign=""top"" class=""ms-formbody"" width=""400px"">
", renderer.Field.Title, "&nbsp;");  //field.GetComparerText());



            Literal litEnd = new Literal();
            litEnd.Text = @"
		</TD>
	</TR>";

            this.Controls.Add(litStart);
            this.Controls.Add(renderer);
            this.Controls.Add(litEnd);
        }

        private SPList GetList()
        {
            SPSite site = SPControl.GetContextSite(this.Context);

            using (SPWeb web = site.OpenWeb(GetWebUrl(this.ListUrl)))
            {
                string listName = GetListName(this.ListUrl);
                return web.Lists[listName];
            }
        }

        private string GetWebUrl(string listUrl)
        {
            string webUrl = string.Empty;
            listUrl = listUrl.TrimEnd('/');
            int lastIndex = listUrl.LastIndexOf("/");
            if (lastIndex > -1)
                webUrl = listUrl.Substring(0, lastIndex);

            return webUrl.TrimEnd('/');
        }

        private string GetListName(string listUrl)
        {
            string listName = string.Empty;
            listUrl = listUrl.Trim('/');
            int lastIndex = listUrl.LastIndexOf("/");
            if (lastIndex > -1)
                listName = listUrl.Substring(lastIndex + 1, listUrl.Length - lastIndex - 1);

            return listName;
        }

        private List<InputField> GetInputFields(XmlDocument xDoc)
        {
            List<InputField> inputFields = new List<InputField>();

            XmlElement xeWhere = (XmlElement)xDoc.SelectSingleNode("Query/Where");
            if (xeWhere != null)
            {
                GetInputFields(xeWhere.ChildNodes, inputFields);
            }
            return inputFields;
        }

        private void GetInputFields(XmlNodeList children, List<InputField> inputFields)
        {
            foreach (XmlElement xeChild in children)
            {
                switch (xeChild.Name)
                {
                    case "And":
                    case "Or":
                        GetInputFields(xeChild.ChildNodes, inputFields);
                        break;
                    case "BeginsWith":
                    case "Contains":
                    case "Eq":
                    case "Geq":
                    case "Gt":
                    case "Leq":
                    case "Lt":
                    case "Neq":
                    //case "DateRangesOverlap":
                    case "IsNotNull":
                    case "IsNull":
                        CheckForInputField(xeChild, inputFields);
                        break;
                    default:
                        break;
                }

            }
        }

        private void CheckForInputField(XmlElement xeComparer, List<InputField> inputFields)
        {
            XmlElement xeInput = (XmlElement)xeComparer.SelectSingleNode("UserInput");
            if (xeInput != null)
            {
                XmlElement xeFieldRef = (XmlElement)xeComparer.SelectSingleNode("FieldRef");
                if (xeFieldRef == null)
                    return;

                string internalName = xeFieldRef.GetAttribute("Name");
                if (string.IsNullOrEmpty(internalName))
                    return;

                SPField spField = _list.Fields.GetFieldByInternalName(internalName);
                if (spField == null)
                    return;

                InputField inputField = new InputField();
                inputField.Document = xeInput.OwnerDocument;
                inputField.UserInputNode = xeInput;
                inputField.FieldRefNode = xeFieldRef;
                inputField.ComparerNode = xeComparer;
                inputField.SPField = spField;
                inputFields.Add(inputField);
            }
        }

        #region IWebEditable Members

        EditorPartCollection IWebEditable.CreateEditorParts()
        {
            List<EditorPart> editors = new List<EditorPart>();
            editors.Add(new ListQueryEditor(this.ID));
            return new EditorPartCollection(editors);
        }

        object IWebEditable.WebBrowsableObject
        {
            get { return this; }
        }

        #endregion

    }

    public class InputField
    {
        public XmlDocument Document
        {
            get;
            set;
        }

        public SPField SPField
        {
            get;
            set;
        }

        public XmlElement UserInputNode
        {
            get;
            set;
        }

        public XmlElement FieldRefNode
        {
            get;
            set;
        }

        public XmlElement ComparerNode
        {
            get;
            set;
        }

        public string GetComparerText()
        {
            if (this.UserInputNode == null || 
                this.UserInputNode.ParentNode == null ||
                string.IsNullOrEmpty(this.UserInputNode.ParentNode.Name))
                return "?";

            string comparer = string.Empty;
            switch (this.UserInputNode.ParentNode.Name)
            {
                case "BeginsWith":
                    comparer = "BeginsWith";
                    break;
                case "Contains":
                    comparer = "Contains";
                    break;
                case "Eq":
                    comparer = "==";
                    break;
                case "Geq":
                    comparer = ">=";
                    break;
                case "Gt":
                    comparer = ">";
                    break;
                case "Leq":
                    comparer = "<=";
                    break;
                case "Lt":
                    comparer = "<";
                    break;
                case "Neq":
                    comparer = "!=";
                    break;
                //case "DateRangesOverlap":
                case "IsNotNull":
                    comparer = "!=";
                    break;
                case "IsNull":
                    comparer = "==";
                    break;
                default:
                    break;
            }

            return HttpUtility.HtmlEncode(comparer);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions