HowTo:Send Notification Messages to Followers

From AgileApps Support Wiki
Revision as of 23:42, 6 October 2014 by imported>Aeric (→‎Setup and Testing)

This code sample sends an email to everyone who registered themselves as a "follower" of a Case (or any other object where the application designer allows it).

To follow the record, a "related record" with the user's email address is added to the Followers object. When the Case (or other record) is updated, an email notification is sent to everyone who is following it, using an API and an email template created for the purpose.

Learn more:

Setup and Testing

  1. Use the Object Construction Wizard to create the Followers object and define an email_address field.
  2. Go to GearIcon.png > Objects > Followers > Fields
  3. Create a new Multi Object Lookup field called related_to.
    Select the objects that can be followed, or choose All Objects.
    (The data in those fields has the format object_id:record_id. That's why you can follow any record in the system.)
  4. Modify the Case form to create a new Related Information section that displays Follower records.
    Select the Followers object
    Link the Follower's Related To field to the object's ID field
    Select Email Address as the field to display
    Sort by email address, in ascending order.
  5. Open a Case record and use that section to manually add yourself as a follower.
  6. Use the sample below to create an Email Template that will be used to send notifications.
    (The sample includes the most recent note added to the record history.)
  7. Record the Template ID:
    While viewing the list of email templates, click the wrench icon and select Edit this View.
    Move the Record ID to the list of selected fields.
    Confirm that you want to make this a global change.
    That value is the Template ID. It now appears as a column in the list of views, where it can be copied.
  8. Create a class using the code below. Fill in the Template ID.
  9. Create a record-updated rule that invokes the notifyFollowers() method defined in the code.
    Name: Send Update Notifications
    Description: Tell anyone who is following the record that a change has occurred.
    Run this Rule: Unconditionally
    Actions to Perform: Invoke Method (Notifications, notifyFollowers)
  10. Update the case record and check your inbox for the notification message.

Next Steps

Here are some things you can do after you get the basic behavior working:

  1. Define a Follow macro for any object in which you want to add Followers:
    In that macro, invoke the addFollower() method defined in the code below.
    The macro will appear in the list of actions available for the record.
    When clicked, the macro will add a Follower record, with all fields filled in.
    Here's what you need for the basic macro:
    Name: Follow
    Description: Add the user who clicks the button to the list of "followers"--people who will receive an email when the record is updated.
    Show: Always
    Action: Invoke Method, Class: Notifications, Method: addFollower
  2. Add a Username field to the Followers object:
    Automatically populate it using the current User's information, when adding a record
    Display it in the Related Information section of forms for objects that can be followed.
  3. Send notifications for a subset of updates
    This is an extra credit assignment.
    To do it, you need to write a method that examines the last activity in the record history, and identifies the type of activity that occurred. Then send a notifications only for some updates--a status or priority change, for example, or don't send them for some kinds of updates.
    Learn more: See the #Add and Access Notes section for the structure of records in the Notes object.
  4. Allow for "unfollowing"
    Users can unfollow a record manually, by clicking their Follower record and choosing the Delete action. Alternatively, you could cannibalize the code below to add a method that searches for a Follower with a matching email_address and related_to field. (But then you have to decide which button to display on the form, which will require JavaScript that uses REST APIs to query the Followers object--all of which adds lag time before the form appears.)

Email Template

Template Name: Update Notification
Type: Case Templates (rather than an SLA template)
From Name: Support System
From Email Address: $custom.support_team_email_address
Subject: Case Record Updated
Template Variables:
Case Record Variables:
$cases.case_number, $cases.modified_id.full_name, $cases.description
Current Note Variable (case history): $__current_note__.description
Custom Variable: $custom.support_team_email_address

Here is a sample Update Notification template that uses those variables:

Case Record# $cases.case_number
was updated by $cases.modified_id.full_name
$__current_note__.description
Case Description:
$cases.description

The source code looks like this:

<syntaxhighlight lang="java" enclose="div">

Case Record# <a href="https://{domain}/networking/servicedesk/index.jsp#_cases/$cases.case_number">$cases.case_number</a> 
was updated by $cases.modified_id.full_name

$__current_note__.description

Case Description:

$cases.description

</syntaxhighlight>

Code

<syntaxhighlight lang="java" enclose="div">

package com.platform.acme.demo;

// Basic imports import com.platform.api.*; import java.util.*;

// Reference static functions without having to specify the Functions class. import static com.platform.api.Functions.*;

import static com.platform.api.CONSTANTS.*;

/**

* Prerequisites: 
*   1. There is a Main object that contains records (e.g. cases) that people 
*      want to "follow"--so they receive a notification when there is an update.
*   2. There is an object that has related records, one for each person who is 
*      following records in the Main object. This sample code assumes that the
*      related object is called "Followers".
*   3. A related record is added to that object when someone becomes a follower.
*   4. That object has a Lookup field that points to the thing being followed,
*      and an email address to send the notification to.
*
* Record Management:
*   a. For initial testing, some "related records" can be created by hand.
*   b. In a production setting, a "Follow" action will add a related record.
*   c. To "unfollow", a user can easily delete the related record.
*   d. Ideally, the Form will have OnLoad JavaScript that uses the REST APIs to
*      see if the current user is already a follower, and sets the checkbox state 
*      or state of the buttons accordingly.
*
* Usage:
*   An update Rule on the main object should invoke the notifyFollowers()
*   method defined in this class. The method finds all related records and
*   sends the messages, using an email template defined for the notifications.
*/

public class Notifications {

  public void log(String msg) throws Exception {
    // Put the message in the log.
    Logger.info(msg, "SendMailToFollowers");
  }
       
  public void debug(String msg) throws Exception {
    // Display message in a popup or at top of page, depending on context, and log it.
    Functions.showMessage(msg);
    log(msg);
  }
  public void notifyFollowers(Parameters p) throws Exception
  {
     try {
        // Get information from the current record
        String objectID = p.get("object_id");
        String recordID = p.get("id");  
           
        // Records that point to this one have this in their "related_to" field.
        String lookup_target_record = objectID +":"+ recordID;
        // Message contents. (To get the template ID, modify the templates view
        // to include the Record ID field.)
        String subject = "Record Update Notification";
        String ccList = "";
        String bodyTemplateId = "__ID of the notification template goes here__";
        String relatedObject = "Followers";
             // This is the name of the object with the related records
        
        // Find all related records whose Lookup field targets the current record
        // Format of the criteria string is: related_to = '{object}:{record}'
        Result result = Functions.searchRecords(relatedObject, 
           "email_address", "related_to = '" + lookup_target_record +"'");
        int resultCode = result.getCode(); 
        if (resultCode > 0)
        {
           // Process the records that were found.
           // (If getCode() has a positive number, it was the number found.)
           int count = 0;
           ParametersIterator iterator = result.getIterator();
           while(iterator.hasNext())
           {
              Parameters params = iterator.next();
              String toAddress = params.get("email_address");
              // Send message (nulls are parameters for attachments)
              Result sendEmail = Functions.sendEmailUsingTemplate(
                 objectID, recordID, toAddress, ccList, subject, bodyTemplateId, 
                 null, null);
              if (sendEmail.getCode() < 0)
              {  
                 String msg = "Error sending email: " + sendEmail.getMessage();
                 Functions.throwError(msg);      
              }
              count++;
           }
           debug(count + " update notifications sent"); // Count is one fo
        }
    } catch (Exception e) {
        // Catch surprises, display a popup, and put them in the log.
        String msg = "Unexpected exception";
        log(msg + ":\n" + e.getMessage() );
        Functions.throwError(msg + " - see debug log");      
     }
  }
  
  /*
   * Usage: This method should be called by Macro (i.e. a record Action)
   * on the record that the person wants to follow. (The form that displays
   * the record should also have a Related Information section, so the user
   * can remove their record.
   */
  public void addFollower(Parameters p) throws Exception
  {
    try {
        // Set up the lookup target
        String objectID = p.get("object_id");
        String recordID = p.get("id");  
        String lookup_target_record = objectID +":"+ recordID;
        
        // Get the current user's email address and name
        String email = Functions.getEnv(ENV.USER.EMAIL);
        String name  = Functions.getEnv(ENV.USER.FULL_NAME);
        
        // For extra credit, exit here if a record already exists with those values
        // Additional credit: Make the adjustments to display and store user's name
        Parameters params = Functions.getParametersInstance();
        params.add("email_address", email);
        params.add("related_to", lookup_target_record);
        params.add(PLATFORM.PARAMS.RECORD.DO_NOT_EXEC_RULES,"1");
        Functions.addRecord("Followers", params);
    } 
    catch (Exception e) {
        // Catch surprises, display a popup, and put them in the log.
        String msg = "Unexpected exception";
        log(msg + ":\n" + e.getMessage() );
        Functions.throwError(msg + " - see debug log");      
     }
  }
  

} // end class </syntaxhighlight>