Category Archives: Uncategorized

Lazy Approval with SharePoint – approve task via email part 3

 

Part 1: https://realworldsharepoint.wordpress.com/2012/06/27/lazy-approval-with-sharepoint-part-1-approve-task-via-email/

Part 2: https://realworldsharepoint.wordpress.com/2012/06/28/lazy-approval-with-sharepoint-approve-task-via-email-part-2/

Building Visual Studio workflows can be a little intimidating at first, but the workflow we will be making in this post is very simple.  The purpose of this workflow is to take the emails as they come into the “Workflow Response” library we setup in step 1 and process them.  This means that the workflow will auto-start on item creation, look at the contents of the mail, get the subject like, parse the 4 variables out, and take action as needed.

Step 1:  Create a Visual Studio Sharepoint 2010 sequential workflow, and call it “ApproveViaEmailWF” or something appropriate.

Step 2:  Add a single “Code” action in the workflow immediately after workflow_activated.  In this example, i also put two LogtoHistory actions around the execute code activity, so i can see what happened on the workflow history page for this workflow item.  Basically, the first one says “Begin workflow”, and the second says “End workflow”.

Now let’s take a look at the code that parses the email:

Double-click the code activity, and you will see the execute code activity method.  You need to include system.io in your code as well:

( this isn’t the cleanest code in the world, but it works.  update as you see fit. )

________________________________________________________________

Imports System.ComponentModel

Imports System.ComponentModel.Design

Imports System.Drawing

Imports System.Workflow.ComponentModel.Compiler

Imports System.Workflow.ComponentModel.Serialization

Imports System.Workflow.ComponentModel

Imports System.Workflow.ComponentModel.Design

Imports System.Workflow.Runtime

Imports System.Workflow.Activities

Imports System.Workflow.Activities.Rules

Imports Microsoft.SharePoint.Workflow

Imports Microsoft.SharePoint.WorkflowActions

Imports System.Net.Mail

Imports System.IO

Public Class Workflow1

Inherits SequentialWorkflowActivity

Public workflowProperties As New SPWorkflowActivationProperties

Public HistoryDescription1 As System.String = Nothing

Public Counter1 As Integer

Public Sub New()

MyBase.New()

InitializeComponent()

End Sub

Private Sub onWorkflowActivated1_Invoked(sender As System.Object, e As System.Workflow.Activities.ExternalDataEventArgs)

HistoryDescription1 = “STARTING WORKFLOW v2.  Pause for 5 minutes for workflow tasks to be unlocked.”

End Sub

Private Sub codeActivity1_ExecuteCode(sender As System.Object, e As System.EventArgs)

Dim obj As Object

Dim sSite As String = “”

Dim sList As String = “”

Dim file As SPFile = workflowProperties.Item.File

obj = workflowProperties.Item

Dim areader As StringReader = New System.IO.StringReader(file.ToString)

Dim breader As StreamReader = New StreamReader(Me.workflowProperties.Item.File.OpenBinaryStream)

Dim str As String = breader.ReadToEnd

Dim tempstr As String = “”

Dim listid As String = “”

Dim taskid As String = “”

Dim sEmailBody As String = “”

Dim pos As Integer = 0

Dim aitem As SPListItem

Try

    Dim msgObj As New System.Net.Mail.MailMessage

Catch ex As Microsoft.SharePoint.SPException

End Try

   Dim testString As String = str

pos = InStr(str, vbCrLf & vbCrLf)

Try

sEmailBody = Mid(str, pos, 100)

Catch ex As Microsoft.SharePoint.SPException

End Try

pos = InStr(str, “Subject: “)

If pos = 0 Then Exit Sub

tempstr = Mid(str, pos + 9, 120)

   Dim firstdash = InStr(tempstr, “+”)

   Dim UserAction = Left(tempstr, firstdash – 1)

tempstr = Right(tempstr, Len(tempstr) – firstdash)

firstdash = InStr(tempstr, “+”)

    Dim thisTask = Mid(tempstr, 3, firstdash – 3)

tempstr = Right(tempstr, Len(tempstr) – firstdash)

firstdash = InStr(tempstr, “+”)

sSite = GetSite(tempstr)

sList = GetList(tempstr)

   Dim gList As New Guid(sList)

sList = Replace(sList, ” “, “%20”)

    Dim site As New SPSite(sSite)

    Using web As SPWeb = site.OpenWeb()

      Try

        Dim alist As SPList = web.Lists(gList)

aitem = alist.GetItemById(CInt(thisTask))

    If UserAction = “APPROVE” Then

        Dim ht As New Hashtable()

ht(“Completed”) = “TRUE”

ht(“PercentComplete”) = 1

ht(“Status”) = “Completed”

ht(SPBuiltInFieldId.WorkflowOutcome) = “Approved”

ht(“Outcome”) = “Approved”

ht(“TaskStatus”) = “Approved”

ht(SPBuiltInFieldId.Description) = “Approved by email.  User comment: “ & sEmailBody

web.AllowUnsafeUpdates = True

        SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

ElseIf UserAction = “REJECT” Then

        Dim ht As New Hashtable()

ht(“Completed”) = “TRUE”

ht(“PercentComplete”) = 0

ht(“Status”) = “Completed”

ht(“Outcome”) = “Rejected”

ht(“TaskStatus”) = “Rejected”

ht(SPBuiltInFieldId.Description) = “Rejected by email.  User comment: “ & sEmailBody

ht(“FormData”) = SPWorkflowStatus.Completed

web.AllowUnsafeUpdates =True

        SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

End If

HistoryDescription1 = “END WORKFLOW.  id=” & thisTask & “: list=” & gList.ToString & “: site=” & sSite & “: action=” & UserAction

    Catch ex As Microsoft.SharePoint.SPException

HistoryDescription1 = ex.Message

       Dim ht As New Hashtable()

ht(“Completed”) = “FALSE”

ht(“PercentComplete”) = 0

ht(“Status”) = “Error”

ht(“Outcome”) = “Error”

ht(“TaskStatus”) = “Error”

ht(SPBuiltInFieldId.Description) = “Error: “ & ex.Message

ht(“FormData”) = SPWorkflowStatus.ErrorOccurred

SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

    End Try

End Using

End Sub

Private Function GetSite(fullString As String) As String

    Dim pos As Integer = InStr(fullString, “SITE”)

    Dim dsh As Integer = InStr(pos, fullString, “+”)

    Dim s As String = Mid(fullString, pos + 4, dsh – 5)

    Return s

End Function

Private Function GetList(fullString As String) As String

    Dim pos As Integer = InStr(fullString, “+LIST”)

    Dim tmp As String = Mid(fullString, pos + 5, 36)

Return tmp

End Function

End Class

_________________________________________________________________________

THAT’S ABOUT IT!   In this code, I didn’t show some of my code, but there are functions to get the taskid, list, site, and action out of the email message.  Also, i am not showing a else clause that handles the REJECTION, but it is pretty much the same code, but sets the percent complete to 0, and the outcome and task status to “Rejected”.  I also do not show how i am setting the log to history, but this is easy…I dynamically set a field called HistoryDescription1 and the log actions simply show what i set it to. The line of code that updates the task is:

SPWorkflowTask.AlterTask(TryCast(aitem, SPListItem), ht, True)

Since this isn’t a post about how to develop in Sharepoint, I wont be covering how to setup a development environment, how to test, how to deploy a solution to the production server, or any of that jazz…perhaps that is for a different post.

If this compiles, then you are ready to test it.  Start an approval process on a fake document you put in that “shared documents” library.  Once you receive the email, click the link in it to ACCEPT and send the message.  It should make its way to the “workflow response” library.   From there, you can copy the eml file to your testing environment and work with it.

If all goes right, when you have deployed this to your production server, you should be able to attch the workflow to the “workflow response” library, and have it launch on new item creation.   when the email drops in the library, the workflow runs, updates the task, and exits.  If there was an error, the log will show the error message.  If it completes, then the log shows ‘END GETEMAILCONTENTS’.

 

Lazy Approval with SharePoint – approve task via email part 2

So at this point, you should have a document library that accepts emails.

We need to hop into Sharepoint Designer to set up a workflow that sends out an approval task to employees.  In this example, I have set up a workflow on my IT site in my site collection (this is where i play).  It is a very simple list workflow with one task in it….”Start Approval Process”.  NOTE:  this is only available in the enterprise license of Sharepoint.  You may create custom approvals in other versions of Sharepoint.  The important thing is that it is a task content type (either infopath or native task form).

For this excercise, I am using Sharepoint Enterprise, so the approval is a built-in template.  I created a workflow on the “Shared Documents” library.  I used the “Approval – Sharepoint 2010” template and called it “Testing”.  I set this as a manual start only, but you could set to start on item creation or change as well.

Next, I edit the workflow and add one task….”Start Approval Process”.  This allows me to specify a recipient for the approval, which in turn creates a task item in the task list specified in the workflow settings.  I also clicked the default workflow name and gave this task a unique name “DocApproval”.  This isn’t neccessary, but it looks better when the emails get sent out.

One more thing to note is the task list assigned to this workflow.  In this example, a list called “Tasks” is the list to which the workflow will put the approval tasks.  This name could be different or contain spaces.  Take note of the list name, though, as we will be extracting the list GUID.

In your workflow editor, you should see something like the image above.  I set myself as the approver, because it just makes it easier to debug.

Next, we need to dive into the approval step created by this template and edit the email that automatically gets sent out.  Click the “DocApproval” task (or whatever you called it), and you are brought to the customize task process page.

What we want to do here is set the email for the individual task processes created by this workflow, so we will click the link for “Change the behavior of a single task”.  You will then be brought to the “Task Behaviors” screen.  In the “When a task is pending” section of this screen, you will see a section of code that sends an email to the “Current Task:Assigned To”.  Click this link to get to the contents of the message that will be sent.

When clicking the link, you will see the “Define E-mail Message” dialog box:

I added only one line to this auto-generated email…”ACCEPT or REJECT via email”.  These are the links to allow a user on ANY DEVICE to approve through a regular email system.   How were these links created?  Let’s dive into the ACCEPT link to see how I constructed it.

When you click the edit hyperlink button on this dialog, you can set display text and the address.  I simply put APROVE for the display text, but the address is the tricky part.

CLICK the elipses next to the Address to edit the details:

Let’s take a look at what this link is going to do.  First, the MAILTO is an instruction to create a new email message.  All email clients know how to work with this, as it is a standard.  The first parameter is the recipient of the email (‘sharepointsite@domain.com’).  Next, in querystring format, the subject.  The subject is the ONLY THING WE WILL USE, since the body of the e-mail can’t be set through this function.

The subject is going to contain 4 main peices of information: 1) the command, 2)the list id, 3) the task item id and 4) the site from which the approval came.   With these four peices of information, you pretty much have all the info you need to approve the task automatically.  This approval will be done with a Visual Studio workflow (part 3).

All of these “variables” we are putting in this link come from common lookups found in the Sharepoint Designer, such as [%current task: id%], [%workflow context: current site URL%], and others.  The command (first) could be anything you define.  I chose to use APPROVE and REJECT.

The one wierd thing here is that I am setting a GUID to the task list this is associated with.  The reason for this is the GUID will be more reliable than accessing the task list by name (like “Approval Tasks” or “Tasks”).   The GUID for the task list associated with your workflow can be found by going to your task list, click list settings, then go to target audience settings.  The GUID is in the URL for that setting.  Remove the brackets before adding to your modified task email.

Ultimately, the purpose of this whole email thing is so that when a user gets an approval task via email, they now can be on any device (like an iPhone), and simply click the link for approve or reject in the email and send send the email to approve.

Now that we have setup the library, the email settings, the approval process in sdesigner, we are ready to move on to the last step in this process…making the Visual Studio workflow and deploy it to the site.

Part 3:  https://realworldsharepoint.wordpress.com/2012/06/28/lazy-approval-with-sharepoint-approve-task-via-email-part-3/

Squashing BUGS!

Image

Welcome to real-world sharepoint!

Welcome to my Sharepoint blog.   My name is George Hardy, and i have been developing on the .NET platform for about 10 years.  I typically write database applications using vb.net, such as estimating systems, rental applications, equipment service applications and more.

I have recently gotten into Sharepoint at my job, and i would like to share the ups and downs of my experiences working with the system.

SUBJECTS:

EMAIL (LAZY APPROVAL) APPROVAL WITH SHAREPOINT

EMAIL APPROVAL UPDATE – USING AN EVENT RECEIVER (COMING SOON)

PROCESSING DATA FROM INFOPATH (COMING SOON)