Keeping track of Emails with EWS and K2

I haven’t posted anything in a while as I have been working on another project, which I am hoping to unveil sometime very soon. In the meantime though  I wanted to talk about K2 and Exchange. Now we all know that K2 can talk to exchange and send emails and receive replies back in the form of SmartActions out of the box.

But what if we wanted to keep track of the emails sent from a K2 app then this gets a bit tricky. We could save the message in a database using  a SmartObject Event and then use the email Event to send the email. Which is an ok approach, but I think something could be done better, where we don’t need to have this two step/event approach.

So lets have a think about about what i want the assembly to do?

  1. Send an email
  2. View the mailbox
  3. View an email

We could modify the existing email event to do what I am suggesting below, but that would be a pain as we would need to do it every time we use the email event and would also require the person building the workflow to be able to write code.  With the approach  I am going to go through, it  will allow anyone to be able to build a workflow where it would track what emails are being sent without having to write code and more importantly every app will be able to see it’s own emails it has sent out.

We are going to create a Email Endpoint Assembly that will allow a workflow to send an email and reference a primary key , SN, Process Instance Id or  application type (see framework) and view it’s mailbox by same type of information.

Getting Started

We will need the following

  1. Visual Studio 2015+
  2. Microsoft exchange web service (EWS URL)
  3. Exchange version
  4. UserAccount specifically setup just to be used for K2 mailbox (I normally create a service account, that just has a mailbox)
  5. User Account Email Address
  6. Microsoft.Exchange.Webservices.dll

To do this i need use the assembly Microsoft.Exchange.Webservices.dll which you can get from here .

Once we have the above we can start building the new email endpoint assembly.

EWS Code

To setup the connection to exchange server,  it is important to identify which version of exchange we are talking too.

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);

When we have created an instance of the exchange service, we then give the instance the exchange web service url.

service.Url = new Uri(“Web service”);

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.Credentials = new WebCredentials("Username", "Password");

service.Url = new Uri("Web service");
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "Email Address");

We have now got a connection to exchange server via it’s web service and we can do a number of different things such as

  1. Send Email
  2. View mailbox contents , such as the inbox or sent items
  3. View an email
  4. We can also do things such as create meeting requests

We will look at the basic code for sending an email

Sending an Email

To send an email we need to create an instance of the EmailMessage object and pass in the Exchange Service Object.

EmailMessage email = new EmailMessage(service);

Once we have done that we can access the properties and methods of EmailMessage object.

So we can give are email a subject email.Subject = “Subject”;

We can also give the email body and decide whether we want to send a plain text or a HTML message.

email.Body = new MessageBody(BodyType.HTML, Body);

EmailMessage email = new EmailMessage(service);
email.Subject = "Subject";
email.Body = new MessageBody(BodyType.HTML, Body);

To add recipients (To, Cc, Bcc) we just need to add the following code

  • email.ToRecipients.Add(“address”);
  • email.CcRecipients.Add(“address”);
  • email.BccRecipients.Add(“address”);

If you have more than one email address for ‘To’ or ‘Cc’ or the ‘Bcc’ then we can simply loop through the correct address method parameter. Like in the example below.

 if (To.Contains(";"))
 {
 String[] to = To.Split(';');
 foreach (var address in to)
 {
 email.ToRecipients.Add(address);
 }
 }
 else
 {
 email.ToRecipients.Add(To);
 }

To send the email we simply use .Send(); method

 email.SendAndSaveCopy();

Now we can send a basic email. So let us have a look how we can now extend this email so it can contain some additional properties that relate to the workflow it is being sent from.

The EmailMessage object allows us to add properties called extend properties and they are really simple to create. The only thing you need to remember is that the GUID used to identify the property must be the same every time we an email is sent and needs to be the same for when when we retrieve the mailbox.

So in this example i am going to bind the process instance id to the email message. We will then be able to search the sent items mailbox and retrieve all the messages that relates to that process instance id.

Creating extend properties.

This is the most important part , extend properties is what allows the ability to be able to group emails by the process Instance I’d, business key etc.. 

Create a Guid called ‘ProcessInstanceId’ and assign it a GUID.

Guid ProcessInstanceId_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc")

We then have to define the extend property by giving the property a name in this case the property is called ‘ProcessInstanceId’ and we define the data type of the property as a ‘String’.

 ExtendedPropertyDefinition ProcessInstanceId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessInstanceId_PropertySetId, "ProcessInstanceId", MapiPropertyType.String);

 

Now that we have defined the property , we can now populate the email with the process instance id. In code example below I am checking to see if the ‘ProcessInstanceId’ is greater than 0 or is not null and if true it will assign the property the value of the ‘ProcessInstanceId’ and if it is false it will assign the property a 0.

email.SetExtendedProperty(ProcessInstanceId_ExtendedPropertyDefinition, (ProcessInstanceId > 0 | ProcessInstanceId != null ? ProcessInstanceId : 0));

 

Now every time we send an email, it will now contain the process instance id.  In the complete code example of the ‘Send Emall’ method below I have also added some additional properties to contain the following

  1. Primary Key of the main business data
  2. ProcessTypeId (framework see here)
  3. Foilo of the process instance
  4. MessageId, so we can identify each email
public static string SendEmail(string Subject,string Body, string To, string Cc,string Bcc,int importance, string sn,string Folio, int? ProcessInstanceId, string ProcessTypeId, string BusinessKey)
 {
 string result = string.Empty;
 ExchangeService service = ConnectToExchange();
 try
 {
 if (To != null || To.Length != 0)
 {
 EmailMessage email = new EmailMessage(service);
 email.Subject = Subject;
 email.Body = new MessageBody(BodyType.HTML, Body);

Guid SN_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition SN_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(SN_PropertySetId, "SN", MapiPropertyType.String);
 email.SetExtendedProperty(SN_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(sn) ? sn : "0_0"));

Guid Folio_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
ExtendedPropertyDefinition Folio_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(Folio_PropertySetId, "Folio", MapiPropertyType.String);
 email.SetExtendedProperty(Folio_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(Folio) ? Folio : "Email Message"));

Guid ProcessInstanceId_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition ProcessInstanceId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessInstanceId_PropertySetId, "ProcessInstanceId", MapiPropertyType.String);
 email.SetExtendedProperty(ProcessInstanceId_ExtendedPropertyDefinition, (ProcessInstanceId > 0 | ProcessInstanceId != null ? ProcessInstanceId : 0));

Guid BusinessKey_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition BusinessKey_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(BusinessKey_PropertySetId, "BusinessKey", MapiPropertyType.String);
 email.SetExtendedProperty(BusinessKey_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(BusinessKey) ? BusinessKey : "0"));

Guid ProcessTypeId_PropertySetId = Guid.Parse("d6520129-3c59-4191-b9d7-4f5160329e4f");ExtendedPropertyDefinition ProcessTypeId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessTypeId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);
 email.SetExtendedProperty(ProcessTypeId_ExtendedPropertyDefinition, (!String.IsNullOrEmpty(ProcessTypeId) ? ProcessTypeId : "00000000-0000-0000-0000-000000000000"));

Guid MessageId_PropertySetId = Guid.Parse("6e997d14-d9b3-4516-8d14-0a10b0aa74aa");
 string MessageId = Guid.NewGuid().ToString();
 ExtendedPropertyDefinition MessageId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(MessageId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);
 email.SetExtendedProperty(MessageId_ExtendedPropertyDefinition, MessageId);



if (To.Contains(";"))
 {
 String[] to = To.Split(';');
 foreach (var address in to)
 {
 email.ToRecipients.Add(address);
 }
 }
 else
 {
 email.ToRecipients.Add(To);
 }



if (!string.IsNullOrEmpty(Cc))
 {
 if (Cc.Contains(";"))
 {
 String[] to = Cc.Split(';');
 foreach( var address in to)
 {
 email.CcRecipients.Add(address);
 }
 }
 else
 {
 email.CcRecipients.Add(Cc);

}
 }

if (!string.IsNullOrEmpty(Bcc))
 {
 if (Bcc.Contains(";"))
 {
 String[] to = Bcc.Split(';');
 foreach (var address in to)
 {
 email.BccRecipients.Add(address);
 }
 }
 else
 {
 email.BccRecipients.Add(Cc);

}
 }

if (importance > 0)
 {
 email.Importance = (importance == 1 ? Microsoft.Exchange.WebServices.Data.Importance.Normal : Importance.High);
 }

email.SendAndSaveCopy();

result = email.Id.ToString();
 }
 }
 catch(Exception ex)
 {
 result = "Error: " + ex.Message.ToString(); 
 }
 finally
 {

}
 return result;
 }

Retrieving an Exchange Mailbox

Now that we can send emails with K2 related data we now need to be able to retrieve those emails. So we can then view them in a SmartForm.

The first thing we need

public static List<EmailBox> GetMailBox(string MailBoxType,int PageSize)
 {
 ItemView view = new ItemView(PageSize);
 List<EmailBox> list = new List<EmailBox>();

Guid SN_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition SN_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(SN_PropertySetId, "SN", MapiPropertyType.String);

Guid Folio_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition Folio_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(Folio_PropertySetId, "Folio", MapiPropertyType.String);

Guid ProcessInstanceId_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition ProcessInstanceId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessInstanceId_PropertySetId, "ProcessInstanceId", MapiPropertyType.String);

Guid BusinessKey_PropertySetId = Guid.Parse("fc0a27be-f463-472e-bea8-648e62d1d7dc");
 ExtendedPropertyDefinition BusinessKey_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(BusinessKey_PropertySetId, "BusinessKey", MapiPropertyType.String);

Guid ProcessTypeId_PropertySetId = Guid.Parse("d6520129-3c59-4191-b9d7-4f5160329e4f");
 ExtendedPropertyDefinition ProcessTypeId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(ProcessTypeId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);

Guid MessageId_PropertySetId = Guid.Parse("6e997d14-d9b3-4516-8d14-0a10b0aa74aa");
 ExtendedPropertyDefinition MessageId_ExtendedPropertyDefinition = new ExtendedPropertyDefinition(MessageId_PropertySetId, "ProcessTypeId", MapiPropertyType.String);

ExchangeService service = ConnectToExchange();
 view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject, SN_ExtendedPropertyDefinition, Folio_ExtendedPropertyDefinition, ProcessInstanceId_ExtendedPropertyDefinition, BusinessKey_ExtendedPropertyDefinition, ProcessTypeId_ExtendedPropertyDefinition, MessageId_ExtendedPropertyDefinition);

FindItemsResults<Item> findResults = service.FindItems((MailBoxType == "Sent" ? WellKnownFolderName.SentItems : WellKnownFolderName.Inbox), view);
 foreach(Item email in findResults.Items)
 {
 Item mail = Item.Bind(service, email.Id);
 list.Add(new EmailBox
 {
 MailBoxType = MailBoxType,
 Subject = mail.Subject,
 Body = mail.Body,
 Importance = mail.Importance.ToString(),
 Id = mail.Id.ToString(),
 Categories = mail.Categories.ToString(),
 DateTimeCreated = mail.DateTimeCreated,
 DateTimeReceived = mail.DateTimeReceived,
 DateTimeSent = mail.DateTimeSent,
 Cc = mail.DisplayCc,
 To = mail.DisplayTo,
 SN = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[0].Value.ToString():string.Empty),
 Folio = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[1].Value.ToString(): string.Empty),
 ProcessInstanceId = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[2].Value.ToString(): string.Empty),
 BusinessKey = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[3].Value.ToString(): string.Empty),
 ProcessTypeId = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[4].Value.ToString(): string.Empty),
 MessageId = (email.ExtendedProperties.Count > 0 ? email.ExtendedProperties[5].Value.ToString(): string.Empty)

});

}
 return list;

}

d

de

Retrieve an Email

Now that we can retrieve a list of emails from a mailbox we now need to be able to retrieve a single email.

We can do this.ww

public static EmailBox GetEmail(string Id)
 {
 EmailBox email = new EmailBox();
 ExchangeService service = ConnectToExchange();

try
 {
 Item mail = Item.Bind(service, (ItemId)Id);
 {
 email.Subject = mail.Subject;
 email.Body = mail.Body;
 email.Importance = mail.Importance.ToString();
 email.Id = mail.Id.ToString();
 email.Categories = mail.Categories.ToString() ;
 email.DateTimeCreated = mail.DateTimeCreated;
 email.DateTimeReceived = mail.DateTimeReceived;
 email.DateTimeSent = mail.DateTimeSent;
 email.Cc = mail.DisplayCc;
 email.To = mail.DisplayTo;
 email.SN = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[0].Value.ToString(): string.Empty);
 email.Folio = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[1].Value.ToString(): string.Empty);
 email.ProcessInstanceId = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[2].Value.ToString(): string.Empty);
 email.BusinessKey = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[3].Value.ToString(): string.Empty);
 email.ProcessTypeId = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[4].Value.ToString(): string.Empty);
 email.MessageId = (mail.ExtendedProperties.Count > 0 ? mail.ExtendedProperties[5].Value.ToString(): string.Empty);
}
}
 catch(Exception ex)
 { }
 finally
 {

}
 return email;
 }

 

Now that we have these methods to send an email, retrieve a mailbox and to retrieve an email. We can now register the library as an endpoint assembly. 

We could extend this to be able to add attachments and we could also look at the calendar meeting requests and doing the same with those and extend their properties 

We can then build a SmartObject around it and then we can use it within are workflows and Smartforms. To make it even easier for people to use the new email SmartObject, we could wrap a SmartWizard around the methods.

The full solution can be downloaded from here 

 

Slack and Simple K2 Integration

One of the big messaging apps for team collaboration is Slack and  is perfect platform to demo how to integrate K2 into it. This will be the first article on how we go about doing this.  Slack is free to use and so is great to demo with and it has an ever growing list of third party integration plugins to play with.

So before we start with the demo,what would we expect a K2 slack plugin to behave? I believe it behave in the following way.

  1. Send notifications of tasks that we have to actiontask
  2. Be notified of when task has been completed and what the action was or the workflow has moved to a certain stage or when there is a workflow escalation.
  3. To be able to action a task from inside Slackhomepage_example_hiretron
  4. To be ask Slack what are my outstanding tasks or what is the status of a certain workflow

So lets starts with points 1 and 2 and deal with simple notifications.

 

Building a Simple messaging app for Slack

Lets start with a simple example, where we can K2 notification messages to Slack, whether its a public message , message to a particular group or a message to an individual person.

First of all we need to sign up for Slack and create a team, which you can down from here . Now we have a slack team, we just need to here  to get access to API for Slack.

api_slack

We are starting simple, so click on “Incoming webhooks” and then click on the link ‘ incoming webhook integration

introwebhooks

Building the web hook url

  1. Choose the channel you want to send the messages to, don’t we will be able to override this later on.

introwebhooks12. Click on the green button ‘Add incoming Webhook integration’

3. You can how see your web hook url, copy that.

introwebhooks24. Further down you can also customize the actual message. I have opted for a K2 look.

introwebhooks35. Click on ‘Save’, we have now created are web hook for incoming messaging.

Slack endpoint assembly

Now we have the web hook, we can how write some code, so K2 can use it. We are going to use a endpoint assembly for this. So we are going to create a class that will take the endpoint and allow us to pass in a message, a optional username and optional group.

private static void PostMessage(Payload payload)
 {
 Encoding _encoding = new UTF8Encoding();
 Uri endpoint = new Uri("web hook here");

string payloadJson = JsonConvert.SerializeObject(payload);
 
 using (System.Net.WebClient client = new System.Net.WebClient())
 {
 System.Collections.Specialized.NameValueCollection data = 
new System.Collections.Specialized.NameValueCollection();
 data["payload"] = payloadJson;

var response = client.UploadValues(endpoint, "POST", data);

//The response text is usually "ok"
 string responseText = _encoding.GetString(response);
 }
 }

Simple code for posting a payload of information to the web hook url

public static void PostMessage(string text, string username = null, string channel = null)
 {
 Payload payload = new Payload()
 {
 Channel = channel,
 Username = username,
 Text = text
 };

PostMessage(payload);
 }

The actual public static method, we will be creating a SmartObject from and then using inside a workflow.

We can then build the solution and take the dll  and now tell K2 about it using the ‘Endpoint Assembly broker’. If you don’t know how to do that view my previous post on creating an Endpoint Assembly.

K2Service

Now just build a SmartObject that uses the service instance you just created.

Slack SMO

We can test it in the SmartObject tester

smotester

When it executes we get this response in Slack

smoslack

No that the SmartObject has been created, we can now use this method inside a workflow

Workflow

I am just going to use a simple workflow for this, that has one task and two actions.

test-workflow

We just going to use a SmartObject event to call the Slack notification SmartObject to send a message to the destination user when a task is generated and then a message to the originator when the task is approved or rejected.

SlackSMOEVENT1

SlackSMOEVENT2.PNG

SlackSMOEVENT4

We do something similar for the approve and reject activities, except we put in the originator name and the message is that the task has been approved or rejected depending on the activity.

When we run the workflow the destination user gets this message in Slack

task

With a link to the task, when they action the task the originator will get this message

task1

Next time we will expand on this by making the notifications more advanced and by allowing the user to ask questions about K2.

The source code for this example can be downloaded from here

Testing a workflow inside a Smartform

So I have posted a few articles on testing in K2, we have looked at Unit Testing,  Testing Smartforms and then just recently more examples of testing a workflow.  After writing that article I realised that there was something missing. What about building a workflow testing tool inside of a Smartform. As it all well and good that we can write unit tests for testing a workflow, but that relies on the workflow developer being able to write code and being that the whole idea of K2 is to build low code , no code solutions. Then there should be away of doing it without the developer having to write code.

There are a number of tools out in the market and they do absolutely fantastic job of testing workflows without having to write code. But I wanted to see if it could be done inside a Smartform.

So my challenge is to build a Smartform App that would test a workflow, with out the tester having to write any code.

The app had to do the following

  1. Start any workflow and check that it has started
  2. Check that tasks have been created and the correct number
  3. Action a task
  4. Checking the task has been completed
  5. Check that the workflow has finished
  6. Check the workflow has gone down the direct path.

The app should all be in Smartforms and should be easy to use.

So lets see how I got on.  So i am going to start with the finished tool and then i will take us through it.

Testing Dashboard

The dashboard shows all the current tests that have been performed and shows the overall percentage of pass and failures.

dashboard

From here you can also click on ‘Create Test’ button to create a new test. Selecting an existing test and clicking on ‘Run Test’ will  run an existing test. Finally double clicking on a test will open up the details about the test.

Test Details

So the test details shows the following information

test details

  1. Workflow being tested
  2. If has already been tested
  3. When it was tested
  4. Overall Pass or Fail
  5. What percentage passed and failed
  6. What was tested and whether each test passed or failed.
  7. It also shows any other tests relating to the workflow being tested.

From the test details you also have the ability to retest the test as well.

Creating a new test

From the dashboard click on ‘Create Test’ button.

test builder.PNG

  1. In the new test form, give the test a name
  2. Select a workflow that you are going to test. Once selected you will then be able to see all the activities of that workflow beneath.test-builder1
  3. Select the activities that the workflow will go throughtest-builder2
  4. The last section is where we build up the actual the tests and what results we expect from those tests.test-builder3

Building a simple test script

The workflow we have selected is a very simple one. It has the following activities

  1. Setup
  2. Task
  3. Approve
  4. Reject
  5. End

test-workflow

Task is where there is a client event which has one slot and goes to the originator.

Now that we have got the basic test details and what route we expect the test to go. We can now build are test script.

  1. Select ‘Start Process’ from the test type drop down list
  2. You will notice that the other text boxes in the row, will be pre populated with information and some will be disabled depending on what information the particular test type requires.
  3. Now we choose comparison sign we are going to use it can be either
    1.  =
    2. >
    3. >=
    4. <
    5. <=
  4. We are going to choose >
  5. In the expected result / comparison box lets enter 0, this is because if workflow starts successfully we expect a value greater than 0.
  6. So ‘Start Process’, needs to know the ‘Folio’ to give the workflow, you can either enter in something. Or if you leave it blank it will take the name we have given earlier to the test.
  7. The next parameter we need to give the test type is the process name. You can either copy the full workflow name and paste into this box or leave it and it will automatically get the workflow name.
  8. The next box is called milliseconds, you can either leave it at 0. Or you can enter in a value. This is useful as it may be your workflow is taking a while to perform an event. So you can enter in a delay to the tests to compensate for this.
  9.  Click on ‘Add’ again , we now what to check the status of the workflow, to make sure that once we started it. It is now active.
  10. So select ‘Get Workflow Status’ from the drop down list
  11. Choose ‘=’ from Sign
  12. Enter ‘Active’ in expected result
  13. We don’t need to enter in anything else
  14. Click on ‘Add’
  15. We now want to check to see if has generated some tasks
  16. Select ‘Get Task Count’
  17. Select ‘=’ in Sign
  18. Expected Result should be 1, as we know it’s only one slot and going to the originator.
  19. ProcessInstanceId, leave that how it is, as the testing framework will replace that with the actual process instance id as run time of the test
  20. Process name either enter in the full name or leave it and it will get automatically populated
  21. Next we can action the task
  22. Select ‘=’ for the sign
  23. In the expected result box enter ‘True’
  24. Where it’s says ‘Action’ we need to enter in the action we expect the test to use. So lets enter ‘Approve’
  25. Where it says ‘Serial Number’ we leave that and like the process instance id, it will be populated by the testing framework at run time.
  26. For Destination user, enter in the destination user that the task is supposed to be for.
  27. When this test type runs it will try and action the task based on the information we have given it (Task Action and Destination User) if the test is successful the actual result will be true.
  28. The last test we are going to do is to check that workflow has gone down the correct path and the correct activities were used. The test will compare the path we expect it to be. which was defined in the ‘Workflow Route’ section to the actual path taken.
  29. Select ‘Compare Activities’ from ‘Test Type’
  30. Select ‘=’ from Sign
  31. Enter in ‘True’ in expected result
  32. Leave ProcessInstanceId and Activities how it is
  33. In the Millisecond box enter ‘4000’ this will make the ‘Compare Activities’ test to wait 4000 milliseconds before starting the test. This will give the workflow time to perform it’s other activities before completing. If this test fails then increase the time. It will then pass.
  34. The test script should now look like thistest-builder4
  35. Now click on ‘Save’
  36. You will now see a read only version of the test
  37. With two buttons ‘Edit Test’ and ‘Run Test’

Running a Test

To run a test, either select a test from the test list and click on ‘Run Test’ or from the test details click on the button ‘Run Test’

Once the test has been completed, you will be displayed the results for each individual test and also the overall test.

resuts

Each individual test will show whether it has passed or failed. If it has passed the status will be true and in green and if had failed it will be false and in red.

For each test that we create we also get the overall test result.

A failed test would be when any of the individual tests has failed

fail

It will show a pie chart showing the % of pass and fail with big black x cross above it.

pass

For an overall Pass we get a tick and of course a 100%

These test results will remain until, you click on ‘Run Test’ again and this will overwrite the previous test results with the new ones.

Continue reading “Testing a workflow inside a Smartform”

Testing Smartforms with the Smartform tester in K2 4.7

There are a number of Smartform testing tools currently on the market to allow developers to test their Smartforms. But in 4.7 there is something hidden away that is just dying to be played with. Like the developer’s best friend SmartObject Service Tester, there is now a tool that will allow you to automate testing of your Smartforms.

How to access it

To access this hidden gem of a tool, go to the K2 Designer and click on ‘show’ link at the bottom of the page and in the pop up click on System.

show-all

How you will notice in the context browser for the designer there is now some additional categories.

This slideshow requires JavaScript.

  1. Expand System
  2. Expand Forms
  3. Expand Smartform tester
  4. Click on ‘SmartForms Tester – Landing Page’
  5. Click on the ‘Runtime URL’ in the properties page
  6. The Smartform Tester Portal will now load up and we can start to build a test case

 

SmartForms Tester Portal

This is where we can manage the automating of the forms from creating new tests to running existing ones.

smartform-tester-form

K2 do give us some examples of how to use the tester portal in the ‘Examples’ folder or what they like to call ‘Suites’

So lets create a ‘Suite’

 

Creating a Test Suite

  1. Click on ‘Test Suites’
  2. A list of options will appear at the top
  3. Click on ‘New Suite’
  4. A pop up window will appear enter in the name of  what your suite is going to be called. I am going to call mine ‘Annual Leave’
  5. Click on ‘Accept’
  6. Click on ‘Refresh List’ button
  7. You will now see the suite you just created in the list

This slideshow requires JavaScript.

 

Creating  a new test

  1. Click on the suite you just created
  2. The list options above will change
  3. Click on ‘New Test’
  4. This will open a new window, from where we can build a new test case
  5. Click on smartform-tester-form25 in the Smartform section and choose the View or Smartform you want to test. In this case i am going to create a simple test to test a view
  6. When you select a view/form it will then appear in the in  top section of the testing  form
  7. Below the name of the select artifact
  8. Is the actions this where will build the test script that the portal will execute for us

 

This slideshow requires JavaScript.

Creating the automated test script

  1. In the actions section, you will see there part of a action already selected
  2. Because i have chosen a view to test. The first drop down list has ‘View’ selected. The 2nd drop down list has ‘Control’ selected.
  3. From the 3rd drop down list we can now choose a control on the view
  4. I am going to choose  the picker control ‘pkrUsername’.
  5. A 4th drop down list appears and should have ‘Change Value’ selected
  6. Text box is also available, where a value can be entered. I am going to enter in ‘sallport’smartform-tester-form8
  7. When we execute this action  the tester, will put ‘sallport’ into the picker control for you.
  8. Click on ‘Add’ to add another action smartform-tester-form26
  9. I am going to select the ‘calStartDate’ control and enter in a date and i am going to the same with for ‘calEndDate’
  10. I am going to add another action so it can ‘select’ a leave type. I am going to enter in ‘Paid leave’
  11. Last of all i am going to select the ‘Button’ control and tell it to click the button.
  12. Now that my simple test script of filling out the view and clicking on the button to submit the data. I am ready to get the tester to run it for me.
  13. But before I do that just click on the smartform-tester-form27 in the top left hand corner and select ‘Save’ from the context menu
  14. ‘Save Test’ pop window will appear, enter in a name for test and make sure the correct suite is selected and click on ‘Ok’

This slideshow requires JavaScript.

Running the test

From the test designer, we can either run the whole script or by clicking one of the actions we can test a particular line.

  1. I am going to run the whole script, so click on ‘Run All’ button. The designer will then carry out the actions line by line.
  2. A report will then be displayed telling you if it was successful or not.
  3. The actions line will also all be green and of course the data inserted into the view will be displayed and of course you can check the SmartObject that was used to save the data.
  4. You can also run the test from main testing portal , by selecting the test from the suite and then clicking on ‘Run Test’ option

This slideshow requires JavaScript.

 

So this is a basic how to use the Smartform tester, and there are other options that I have not covered such as delayed actions and modifying variables and assertions such total count of items in a list etc..

Demo forms can be downloaded from here

Conclusion

What is good about this tool it’s all built using Smartforms, so not only are we seeing some new controls that are not made available yet to in the Smartform designer, such as the context menu, the action list with is probably a more advanced list view. I hope these will made available soon.

The 2nd good thing about this is that the test data is available as SmartObjects which mean we can then use these to build rich testing reports that also take into account business data.

It’s great start to something that will hopefully be fleshed out with further updates in the future. So it would be possible to fill out the form, get a task and action it, all in one test case.

 

 

 

Bill’s Tasking Workflow Pattern

Sending tasks is easy to do in K2, but to make them more adaptable from outside the work is a bit more tricky. A colleague of mine named Bill Irvine, came up with pattern to standardize the way tasking is developed and used.  So taking his idea i have come up with own interpretation of his tasking pattern so this why i am calling this Bill’s  tasking workflow pattern.

 

Getting Started

To get started we need the following SmartObjects, I have included the sql for the tables and store procedures.  When the framework is released it will be included as apart of that.

Tables

Tasking relies on the following tables

tasking-db

Task Library

Contains all the task types. It contains Id of the form that the task will navigate too and also whether task needs to send task notification email

CREATE TABLE [dbo].[TaskLibrary](
[TaskTypeId] [uniqueidentifier] NOT NULL,
[TaskName] [nvarchar](50) NULL,
[FormId] [uniqueidentifier] NULL,
[TaskDescription] [nvarchar](max) NULL,
[EmailNotification] [bit] NULL,
[Escalation] [bit] NULL,
[EscalationTimeId] [uniqueidentifier] NULL,
[EmailTemplateId] [uniqueidentifier] NULL,
[Slots] [int] NULL,
CONSTRAINT [PK_TaskLibrary] PRIMARY KEY CLUSTERED
(
[TaskTypeId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

Note if not using framework change, form id data type from unique identifier to Nvarchar(100).

Task Actions

Task Actions contains all the possible actions for that particular task type

CREATE TABLE [dbo].[TaskActions](
[TaskActionId] [uniqueidentifier] NOT NULL,
[TaskTypeId] [uniqueidentifier] NULL,
[TaskAction] [nvarchar](50) NULL,
[TaskValue] [int] NULL,
CONSTRAINT [PK_TaskActions] PRIMARY KEY CLUSTERED
(
[TaskActionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Tasks

Tasks contains the destination users for the task type, the task’s serial number against a particular task type and process instance Id

CREATE TABLE [dbo].[Tasks](
[TaskId] [uniqueidentifier] NOT NULL,
[WorkflowType] [uniqueidentifier] NULL,
[SN] [nvarchar](50) NULL,
[Username] [nvarchar](50) NULL,
[BusinesObjectId] [nvarchar](50) NULL,
[ProcessInstanceId] [int] NULL,
[TaskTypeId] [uniqueidentifier] NULL,
[TaskAction] [nvarchar](50) NULL,
[DestinationKey] [uniqueidentifier] NULL,
CONSTRAINT [PK_Tasks_1] PRIMARY KEY CLUSTERED
(
[TaskId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

All tables have basic CRUD methods to manage the data and there is also some additional store procedures to help with the tasking pattern

 

The tables and store procedures scripts can be accessed here 

SmartObject 

The tasking SmartObject is called K2C.CMN.SMO.Tasking, and it manages the creation of creating task types and its related task actions. It also manage the destination user’s task details

Properties

Name
Type
Description
TaskId GUID Destination User Task Id for an instance of the task
ProcessTypeId GUID Process Type Id
Username Text FQDN of the destination user
BusinessObjectId Text Primary Key of the main business data
ProcessInstanceId Number Id of the instance of the process
SN Text Serial Number for the task
TaskTypeId GUID Id for the type of task
TaskAction Text Action for the task
TaskActionId GUID Action Id for a particular task type action
TaskValue Number Task value that relates to actual action in the workflow either 1,2 or 3
TaskName Text Name of the task type
FormId GUID Form Id from the form library
TaskDescription Text Description of the task type
EmailNotification Yes/No Whether task needs to send an email

SmartObject Methods

Method Name
Store Procedure
Description
Create Task Action sp_TaskActionsCreate Creates a new action for the task type
Delete Task Action sp_TaskActionsDelete Deletes the action for the task type
Get All Task Actions sp_TaskActionsList Gets a complete list of the task actions
Get Task Action sp_TaskActionRead Gets a action for Task Type
Update Task Action sp_TaskActionUpdate Updates a action in the task type
Create Task Type sp_TaskLibraryCreate Creates a new task type
Delete Task Type sp_TaskLibraryDelete Deletes a task type
Get all Task Types sp_TaskLibraryList Gets all Task Types
Get Task Type sp_TaskLibraryRead Gets a particular task type
Update Task Type sp_TaskLibraryUpdate Updates a task type
Create Task sp_TasksCreate Creates a new task entry
Delete Task sp_TasksDelete Deletes the task
Get All Tasks sp_TaskList Gets a list of tasks
Get Task sp_TaskRead Gets a particular task
Update Task sp_TaskUpdate Updates the task
Get tasks by type sp_TaskActions Gets all actions by task type
Update Task Action sp_TasksUpDateAction Updates the destination user task’s action
Task Result sp_TaskResult Gets result of the task
Create Destination Key so_CreateDataFieldKey Creates a group key for destination users

Workflow

This version is very simple and only works for one slot, but it could be expanded to manage multiple slots.

Process Data Fields

The process data fields needed for this workflow are

Data Field Name
Data Field Type
Description
In or out
TaskId String So we know what task type In
ParentProcessInstanceId Number Parent Process Instance Id In
 DestinationKey  string
Expire Boolean stops start going to expire, set to false Int
ActionResponse String action value returned Out

Simple tasking pattern

task-workflow-v2

Activities

  1. Setup – Links workflow to framework
  2. Send Email, sends email based on a template
  3. Task, creates task based on the task type Id
  4. Action 1 ,2 , 3,  records the action returned
  5. Expire , responds to the task escalating
  6. End, tidies everything up based on framework

 

Setup

The setup activity does all the framework registration

Send Email

This activity will record the task with the notification service. It will also call the Email service and pass in the template id from the task type reference

Task

It will add the Serial Number to the destination user record in tasks and the activity will also have a client event. It will get task url from the form library and the destination user will come from task reference. It will have 3 actions (1,2,3)

Action 1, 2, 3

Will record the action  against the task by getting the action name from the ‘Get Task Action’ method and it will set the data field ‘Action Response’ with the action value

End

Will do the framework clean up, so deleting  external data fields etc…

 

Notes

Remember to audit logs (for the actual task workflow and also for the parent workflow so we can record the action e

Line Rules

Line Rule
Description
LR Email Notification Required If method ‘Is Email Required’ returns true
LR No Email Notification Required If method ‘Is Email Required’ returns false
Start to Expire Data field ‘Expire’ = ‘True’

References

The tasking pattern workflow requires two references

  1. Destination
  2. Task Type

references

Destination Reference

Gets a list of destination users for a particular task type

  1. In the  Data (3rd) tab of the context browser in K2 Studio / Visual Studio
  2. Right click on ‘References’ and click ‘Add’
  3. Give the reference a name ‘Destination’
  4. Select the method ‘K2C.CMN.SMO.Tasking.Get Destination Users’
  5. For the input property use the ‘DestinationId
  6. Click ‘Next and then ‘Finish’

reference

 

Task Type Reference

Gets information about the task type such as whether an email should be sent, which form to use as the task.

  1. In the  Data (3rd) tab of the context browser in K2 Studio / Visual Studio
  2. Right click on ‘References’ and click ‘Add’
  3. Give the reference a name ‘Task Type’
  4. Select the method ‘K2C.CMN.SMO.Tasking.Get Task Type’
  5. For the input property use the ‘Task Id’ data field
  6. Click ‘Next and then ‘Finish’

tasking

Building the tasking workflow

  1. Create an activity on the canvas and name it ‘Setup’
  2. If you are using framework then, add in the related framework events, else just put a  placeholder event in their for now.
  3.  Create another activities called ‘Send Email’ and ‘Task’
  4. Create a line between ‘Setup’ and ‘Send email’ and another line between ‘Setup’ and ‘Task’
  5. Right click on the line between ‘Setup’ and ‘Send Email’
  6. Select properties
  7. In General properties give it the label of ‘LR Email Notification required’
  8. Click on the ‘Line rule’ section greenarrow
  9. Click on ‘Add’
  10. In the rule editor now. In the ‘First Variable’ open the context browser expand the 3rd tab
  11. Expand references, expand ‘Task Type’
  12. Select ‘Email Notification’, either drag it into ‘first variable’ or click on ‘Add’
  13. Comparison operator should be ‘=’
  14. Second variable will be ‘True’
  15. Click ‘Ok’ and then ‘Finish’
  16. We have now added a rule that will check to see if an email notification is required.
  17. We now need to do the same for the other line we created, except call the line ‘LR No email notification required’
  18.  Second variable for this rule should be ‘False’

This slideshow requires JavaScript.

The email event

  1. Add an email event in the ‘Send Email’ activity
  2. Give it a name like ‘send email’
  3. Select ‘originator’ and unchecked ‘specify’ in ‘Recipient’

Task Activity

In the task activity we need to add a ‘SmartObject event’ that records the serial number of the task and we also need to add a client event

Recording the ‘Serial Number’

  1. Drag the ‘SmartObject Event’ into the task event
  2. Give the event a name ‘Add sn’
  3. Select the SmartObject method ‘Add task sn’ from the SmartObject ‘K2C.CMN.SMO.Tasking’
  4. Click ‘Next’
  5. Now in ‘Input Mapping’ for the ‘PSN’ click on ‘Assign’
  6. Expand Process Instance from and select ‘id’
  7. Type in ‘_’
  8. Expand ‘Activity Destination Instance’ and select ‘Id’
  9. Click on ‘pTaskId’ and ‘Assign’
  10. Expand the ‘Destination’ reference and  use Task Id
  11. This will now save the task serial number against the destination user.

This slideshow requires JavaScript.

Adding user task

  1. Drag a ‘Client Event’ in to the task activity
  2. Name it ‘User Task’
  3. Check ‘Task Item URL’
  4. If using framework follow this route
    1. dd
  5. If not using framework follow this route
    1. Click on eclipse
    2. Go to the 3rd tab expand ‘References’
    3. Expand ‘Task Type’
    4. Drag ‘FormId’ or select ‘Form Id’ and click on ‘Add
  6. Click on ‘Next’ and ‘Next’ again
  7. In Actions click on ‘Add’
  8. In the ‘Add Action’ window, enter 1 in name and click on ‘Ok’
  9. Repeat this adding 2 and 3 as a action
  10. Click ‘Next’ and ‘Next’ again
  11. In Destination users click on ‘Add’
  12. Click on eclipse,
  13. In the context browser
  14. Click on 3rd tab
  15. Expand References
  16. Expand ‘Destination’
  17. Click on ‘Username’ and click on ‘Add’
  18. Click ‘Next’ and then ‘Finish’
  19. We have now created a generic task

This slideshow requires JavaScript.

Recording the Action

  1. Create a ‘Default Activity’ and name it ‘1’
  2. Drag a SmartObject Event into the event
  3. Name it ‘Task Action’
  4. For ‘SmartObject  Method’ use ‘Update Task Action’ from ‘K2C.CMN.SMO.Tasking’
  5. Click ‘Next’
  6. In Input Mapping, click on ‘pTaskAction’ and then on ‘Assign’
  7. Click on eclipse, it opens the context browser
  8. Go the 1st tab, expand SmartObject Servers
  9. Expand the SmartObject ‘K2C.CMN.SMO.Tasking’
  10. Expand the method ‘Get Task Action’
  11. Select the ‘TaskAction’ property
  12. Click on ‘OK’
  13. This method requires some additional properties.
  14. ‘pTaskValue’ property needs to be 1
  15. ‘pTaskTypeId’ property needs to be the datafield called ‘TaskId’
  16. Click ‘Next’ and ‘Next’ again
  17. Select ‘Task Action’ and click ‘Next’
  18. Make sure ‘Return a single item’ is checked
  19. Click on ‘Finish’
  20. Click on ‘OK’
  21. What we have just done is get the text value of the action for the task type and of the action value of 1.
  22. pTaskId just needs to be Task Id from the destination reference
  23. Click on ‘Finish’
  24. Copy this Activity and rename it to ‘2’
  25. and change ‘PtaskValue’ to ‘2’
  26. Repeat steps 24 and 25 and change the ‘1’ to a ‘3’
  27. These activities will now record the action of the task against the destination user
  28. We also need to record the action in the data field ‘Action Response. So do to steps 9 to 23 in a data event for each of the 3 activities. This will allow the parent workflow to easily retrieve the action.
  29. Connect the out come lines to the activities we just created
  30. Create an activity called
  31. Last of all create a activity called ‘End’ with a placeholder called ‘End’ and join the 3 activities to the end activity.

 

Your tasking workflow should look something like this

taskingwkf.PNG

 

Download workflow, SmartObject from here

 

The workflow could be extended to allow multiple slots and multiple destinations. The great thing about a tasking pattern is that it just reduces development time and testing and allows actions to be dynamically added and removed, without the need to go into the actual workflow.

It also allows there to be generic task forms that just point to the tasking workflow and they just need the task type id to load up the correct actions for the task type.

Below is a brief explanation of how to use it, but I will go into more details on how to use it in a later article. For now it’s just about exploring the idea of a tasking pattern and how it would it work.

How to use the tasking workflow

To use the tasking workflow follow these simple steps

  1. Add the tasking workflow to the solution
  2. Create a new workflow
  3. Use the SmartObject event with ‘Create destination key’ method and bind the result to a data data field called ‘Destination key’ of type string
  4. Now we need to use the ‘Create Task’ method to add the destination user, task type id and destination key
  5. Add the IPC Event and point it to the tasking workflow
  6. Choose synchronous
  7. Map the following data fields ‘Task Id, Destination Key’
  8. For the return value map ‘Action response’ data field of the tasking workflow to the parent ‘Action response’ data field
  9. Then use a line rule to direct the workflow based on the ‘Action response’

 

 

 

 

 

 

How to: For Each Event

Over the last couple of weeks people have asked me how to use the for each loop event in K2. So I thought i would put this quick demo together.

The demo, that i am going to do is going to loop through a list of subscribers and update their status from ‘Not Sent’ to ‘Sent’.

Getting Started

I have created a simple Smart box  SmartObject for demo purposes that has the following properties

  1. 1. Name of type string
  2. Email of type string
  3. Id of type Auto number and Key
  4. Status of type string

smo

I have inserted 3 rows of data with the status of ‘Not Sent’. We will use this SmartObject to use the ‘For Each’ event to loop through the data.

Creating the workflow

for-each-simple

Adding the ‘For Each’ event

  1. Open K2 Studio or K2 for Visual Studio ( I am going to use K2 Studio)
  2.  Create a new workflow solution called ‘For Each Demo’
  3. Rename the workflow from process 1 to ‘ForEachWorkflow’
  4. Once the workflow canvas has loaded up
  5. Drag the ‘for each’ event on to the canvas
  6. In the event wizard, give the event the name ‘Loop demo’
  7. Click on Source ico icon, so the drop down list disappears  and open the context browser
  8. In the 1st tab (Environment) , expand ‘SmartObject Services’
  9. Go to the SmartObject you want to use and expand the list method you want to use
  10. Drag the property that you want to use, normally the primary key into the event box
  11. The SmartObject wizard loads up, click ‘Next’ and ‘Next’ again
  12. In ‘Select a return property’ make sure the ‘id’ value is selected.
  13. Click ‘Next’, make sure ‘Return all Results that match filter’ is selected.
  14. Click ‘Finish’
  15. For the reference name, enter in the name ‘Dummy Data Reference’
  16. For the index name, enter in the name ‘Dummy Index’
  17. Click on ‘Finish’

This slideshow requires JavaScript.

Interacting with the for each item

  1. Back in the canvas, you will notice there are now two line rules coming out of the activity
  2. Drag the placeholder event on the canvas and name both the event and activity with the name ‘End’
  3. Drag the ‘line’ named ‘No more items’ to the end activity
  4. Create a new activity on the canvas and name it ‘Status Change’
  5. Drag the SmartObject Event into the newly created activity
  6. In the event wizard for the SmartObject event, name it ‘Update Status’
  7. Select the update method for the SmartObject that you used with the ‘for each’ event
  8. Click ‘Next’
  9. For the ‘ID’ property, click assign
  10. In the context browser go to the 3rd tab (Data) and expand ‘Item references’ and then expand ‘ Loop demo reference’
  11. Click on ‘Id’ property and click on ‘Add’
  12. Click on ‘Status’ and click ‘Assign’ and enter in the text ‘Sent’
  13. Click on ‘Next’ and ‘Next’ again and then ‘Finish’
  14. Drag the remaining line named ‘Next item’ to this activity and then create a new line from this activity back to the ‘for each’ activity.

This slideshow requires JavaScript.

That is a simple example of using the ‘For each’ event. Anything that follows the ‘Next item’ line is in side the loop and has the context of the current row the loop is on. You can have multiple activities in this part and the workflow  will move on to the next item once it has completed everything in that section. You must always have a line going back to the activity with the ‘for each’ event in.

Other things to remember

  1. Choose 1 property to return in the for each event. Always best to use a primary or foreign key
  2. Remember to select ‘Return all Results that match filter’ as it will return the complete list back and it doesn’t matter if there is no filter applied.

 

Next step using references with the ‘For Each’ Event

So we have created a simple workflow with a simple for each loop. But what if we wanted to get more data from the for each event and then possibly use it in a line rule.

In the next example, the workflow is going to check the current status of the item it is looking at. If it’s status is already ‘Sent’ it will ignore it and move on to the next item in the list and if the status is ‘Not Sent’ it will then update the status as normal

I am going to use the same workflow as before

Creating the reference

  1. In the context browser, go to the 3rd tab (data)
  2. Right click on ‘References’ and click on ‘Add’
  3. In the ‘SmartObject Method Reference’ click on ‘Next’
  4. In name, give the reference a name , for my example i have used ‘Dummy data’
  5. In SmartObject Method, select a read type method that uses value you have selected in the for each as the input parameter. I am pointing my reference to the read method.
  6. Click ‘Next’
  7. In input mapping, click on Assign and select the id from the item reference for the for each loop.
  8. Click ‘Next’ and ‘Finish’
  9. We have now created a reference to get the related details based on the current row of the ‘for each’ event.

This slideshow requires JavaScript.

 

Editing the ‘for each’ line rule for ‘Next Item’

Now that we have the reference setup, we can edit the line rule for ‘Next Item’

  1. Right click on ‘Next item’
  2. Click on ‘Properties’
  3. ‘Line General Properties’ will load up. Click on  greenarrowthe green arrow for line rules
  4. Click on ‘Add’
  5.  In rule editor, select ‘And’ from ‘Boolean Operator’
  6. In ‘First Variable’ click on eclipse
  7. In the context browser,  go the references in the 3rd tab
  8. Expand References, expand your reference you created in the last section
  9. Drag ‘Status’ into the ‘First Variable’
  10. The ‘SmartObject Wizard ‘ pops up, click on ‘Status’
  11. Click ‘Finish’
  12. Select ‘<>’ from ‘Comparison Operator’
  13. In the ‘Second Variable’ enter ‘Sent’
  14. Click on ‘Ok’
  15. Click on ‘Finish’
  16. We now need to create another rule that is similar to the ‘Next Item’ rule but where the ‘Status’ is equal to ‘Sent’

This slideshow requires JavaScript.

Creating a new line rule for ‘Next Item’ and where status is equal to ‘Sent’

  1. Right click and drag a line from the ‘For Each’ activity to ‘Update Status’
  2. Then drag the line from ‘Update Status’ to ‘For Each’. (We have to do this as line can’t go back on it self without being connected to another activity first)
  3. Right click on the line and click on ‘properties’
  4. In ‘Label’ enter ‘New Item and status is sent’
  5. Click on greenarrow and then click on ‘Add’
  6. In the Rule editor in ‘First Variable’
  7. Click on eclipse and expand the process data fields
  8. Click on ‘Dummy index result’ and click ‘Ok’
  9. Select ‘=’ for the operator
  10. In Second variable enter in ‘True’
  11. Click ‘Ok’
  12. Click on ‘Add’
  13.  In rule editor, select ‘And’ from ‘Boolean Operator’
  14. In ‘First Variable’ click on eclipse
  15. In the context browser,  go the references in the 3rd tab
  16. Expand References, expand your reference you created in the last section
  17. Drag ‘Status’ into the ‘First Variable’
  18. The ‘SmartObject Wizard ‘ pops up, click on ‘Status’
  19. Click ‘Finish’
  20. Select ‘<>’ from ‘Comparison Operator’
  21. In the ‘Second Variable’ enter ‘Sent’
  22. Click on ‘Ok’
  23. Click on ‘Finish’

 

This slideshow requires JavaScript.

 

Download example here 

Using The New Rest Broker

Hooray, it’s finally here, after months and months of beta testing. In 4.7  we finally get to use REST Services, without having to write a load of code to wrap around the REST service and then access it via the Endpoint assembly broker.

It’s really easy to setup and start using REST Services.

K2 Endpoint REST Broker, uses Swagger to define the Service Objects and methods. Swagger is becoming the open standard for describing REST APIS

Getting access to a Swagger Editor

To get a swagger definition of a REST Service you need access to a Swagger editor that can see the REST Service

  1. http://editor.swagger.io/#/ – Online Swagger Editor , if the Rest Service is accessible to the outside world
  2. https://github.com/swagger-api/swagger.io/blob/wordpress/tools/swagger-editor.md  – You can download a copy of the editor to install on a server where the REST service is accessible

swagger

Creating a Swagger definition file

To create a Swagger definition file using the swagger editor (same for both online and local version) follow the following steps

  • Click on ‘File’
  • Click on ‘Import URL’

Swagger1.PNG

  • Enter in the URL
  • If it can’t find the URL, uncheck ‘Use CORS proxy’
  • Once it has found the REST Service , click on ‘Import’
  • If there are no errors, click on ‘File’
  • Click on ‘Download JSON’

swagger2

  •  Take the .JSON file and copy it to the K2 server
  • Create a folder on the C:\  called ‘Swagger’
  • Copy file into the folder
  • Open up the SmartObject Tester Tool
  • Expand ‘ServiceObject Explorer’
  • Right click on ‘Endpoints Rest’ and click on ‘Register Service Instance’
  • In the section ‘Descriptor Location’ enter in the full path of the Swagger file we copied into the Swagger folder

rest

  • Click on ‘Next’ and then click on ‘Add’
  • K2 will now go through the Swagger file and create service objects based on the definitions in the Swagger file
  • You can now create SmartObjects as normal

 

Using K2 Framework (K2F) with Swagger and the REST Broker

K2F provides support for managing the swagger definitions of the REST Broker. It will do this in two ways.

  1. There will be a Web API Handler that accepts Posts, the idea being that when the global registry changes it will post to the service with the new host address and application name. The service then goes into the library and finds the correct swagger definition and updates it with the new host address. It then exports the swagger definition file to the  swagger folder on the server and then updates K2 with the new definition. ToDo
  2. In the portal you can view all the swagger definitions, where new ones can be added and old ones can be edited. Once created in the library, this will then create Swagger JSON file on the K2 Server.

swaggerdefintionlib

Add  a new Swagger file

demoswagger

  1. Click on ‘Add Swagger Definition’
  2. Form loads up where you can enter in the definition name, host address and the definition it self
  3. Click on ‘Submit’
  4. This will save the swagger definition in the library and also create its corresponding JSON file on to the server.
  5. You will still need to create the instance manually using the service object tester tool

savedswagger