Xurrent monitor subscription
Description
Inform all subscriber users per e-mail about every update of an request the users has subscribed, but not about changes in the subscriptions. If a user subscribes to a request send a SUBSCRIBED mail to this user - without the information of all other subscribers. If a user cancels the subscription send a UNSUBCRIBED mail to this user - without the information of all other subscribers. A special template with audit information should be used to show the changed values.
Approach
The subscriber is added to the request by techwork Xurrent Monitor simply by adding the users email address to a array in custom data and update the request. This is done with the users token and triggers the webhook in the users name. Therefore the webhook value source.person_id identifies the subscribing user. Look into the audit data to get the old subscribers and search the user - if the user is available there it is possible a UNSUBCRIBE. Look into the current data to get the current subscribers and search the user - if the user is availabel there it is possible a SUBSCRIBE. Depending on the subscribe information that is calculated send a SUBSCRIBE / UNSUBSCRIBE mail, or send a mail to all users about the changes that are made on this request.
Prerequisites
A html template in the needed language in the Templates tab.
request-watch-all-notes- the name of the template
Templates are used so solve the following problems:
- Special text for mail or notes maintained outside the package code
- Identify the template by simple template names to use exactly the one that is needed
- Different language versions and fallback language versions of the same template are supported
In addition the webhook must be set with following parameters:
- Account: datacenter
- Event: request.update
Information about Audit data:
With the mergeAudit(request) function call the request variable is enhanced by audit information. For each field there are new identifiers with a special prefix:
request.audit_unchanged_subject- if the subject is not changed this variable is filled. if changed it is emptyrequest.audit_changed_subject- if the subject is changed this variable is filled. if not changed it is empty.
This two enhancements are exclusive - only one of them is filled depending if the base value is changed or not in the last update. This makes it easy to write special code that shows the value in a different manner if it is updated.
There are other prefixes that are enhanced by the mergeAudit function:
request.audit_is_changed_subject- indicates if the value is changedrequest.audit_old_subject- the old value before the update. If not changed it is identical to the new value.request.audit_new_subject- the new value after the update. If not changed it is identical to the old value.
In addition there are some variables that give information about the latest update
request.audit_id- the id of the auditrequest.audit_user- the user responsible for the auditrequest.audit_action- the action that leads to the auditrequest.audit_created_at- the date and time the audit is created - this is the date and time of the update
Commented code
//
// send an email if subscribed
//
// write a log at the start of the subscription package execution
log('******* Send Subscription Begin ********');
// enhance the request values with audit data that is used in the templates
// and in the further code
mergeAudit(request);
// get the current subscriber list out of custom data
// This list is written by techwork Xurrent Monitor
// The list contains the E-Mail adresses of all subscribers
let subscribers = request.custom_data.monitor_subscribers;
// prepare flag for further processing
let subscription_flag = null;
// fetch the person that causes the webhook by its id - the source.person_id
let person = fetch('people', source.person_id);
// check if the custom data of the audit is changed
if (request.audit_is_changed_custom_data) {
// get the old and the new subscribers from the custom data
let subscribersOld = request.audit_old_custom_data.monitor_subscribers;
let subscribersNew = request.audit_new_custom_data.monitor_subscribers;
log('subscribersOld=', subscribersOld);
log('subscribersNew=', subscribersNew);
// prepare flags for later processing
let subscribedOld = false;
let subscribedNew = false;
// if there are old subscribers (existence check)
if (subscribersOld) {
// check if the persons primary email is inside the old subscribers
for (let subscriber_email of subscribersOld) {
if (person.primary_email == subscriber_email) {
// then set the $subscribeOld flag to true for later usage
subscribedOld = true;
}
}
}
// do the same with the new subscribers list
for (let subscriber_email of $subscribersNew) {
if (person.primary_email == subscriber_email) {
subscribedNew = true;
}
}
log('subscribedOld=', subscribedOld);
log('subscribedNew=', subscribedNew);
// set the subscription_flag value depending on the values of New and Old
if (subscribedNew && !subscribedOld) {
subscription_flag = 'SUBSCRIBED';
}
if (subscribedOld && !subscribedNew) {
subscription_flag = 'UNSUBSCRIBED';
}
}
log('$subscription_flag=', subscription_flag);
// If there is a subscription flag with a value (existence check) a subscription is done in custom data
if (subscription_flag) {
// in this case a mail is sent to the new subscriber / to the unsubscriber
log('subscription change: ' + subscription_flag + ' ' + person);
let mailData = createTemplateHTMLMail('request-watch-all-notes');
mailData.to = person.primary_email;
mailData.profile = 'xurrent-automation';
sendMail(mailData);
} else {
// if this was not a subscriber action send a mail to each of the current subscribers
// To do this loop through the list of current subscribers
// If there is no list nothing will happen here (existence check)
for (let subscriber of subscribers) {
// log the mail adress to the package log
log('subscription sent to: ', subscriber);
// create the mail by a template
let mailData = createTemplateHTMLMail('request-watch-all-notes');
// set the mail out profile
// this mail out profile is not configured, but there is a default mail out profile that is used instead
mailData.profile = 'xurrent-automation'; // not needed if there is a default profile
// set the mail to address
mailData.to = subscriber;
// send the mail
sendMail(mailData);
}
}
log('******* Send Subscription End ********');
A template similar to the one that is used in this example is explained in example section Template Code
Condensed code
The comments and log entries are helpful, but make the code above quite long. Leaving them out, the code can be condensed to:
// send an email if subscribed
mergeAudit(request);
let subscribers = request.custom_data.monitor_subscribers;
let subscription_flag = null;
let person = fetch('people', source.person_id);
if (request.audit_is_changed_custom_data) {
let subscribersOld = request.audit_old_custom_data.monitor_subscribers;
let subscribersNew = request.audit_new_custom_data.monitor_subscribers;
let subscribedOld = false;
let subscribedNew = false;
if (subscribersOld) {
for (let subscriber_email of subscribersOld) {
if (person.primary_email == subscriber_email) {
subscribedOld = true;
}
}
}
for (let subscriber_email of subscribersNew) {
if (person.primary_email == subscriber_email) {
subscribedNew = true;
}
}
if (subscribedNew && !subscribedOld) {
subscription_flag = 'SUBSCRIBED';
}
if (subscribedOld && !subscribedNew) {
subscription_flag = 'UNSUBSCRIBED';
}
}
if (subscription_flag) {
let mailData = createTemplateHTMLMail('request-watch-all-notes');
mailData.to = person.primary_email;
mailData.profile = 'xurrent-automation';
sendMail(mailData);
} else {
for (let subscriber of subscribers) {
let mailData = createTemplateHTMLMail('request-watch-all-notes');
mailData.profile = 'xurrent-automation'; // not needed if there is a default profile
mailData.to = subscriber;
sendMail(mailData);
}
}
What it does: Subscribe and Unsubcribe Information and mail to all subscribers.
Working with functions
There is an alternative way to develop this with less cascading and therefore easier to read. Since the introduction of functions this is the preferred way of package development. In the main function at the beginning there are cancel conditions followed by meaningful function calls about what is happening in this package. Those functions implement the technical details. The functions get all the information they need from the main function.
// send an email if subscribed
(function () {
let subscription_flag = get_subscription_flag(request, source.person_id);
let subscribers = request.custom_data.monitor_subscribers;
if (subscription_flag) {
send_template_mail(person.primary_email);
} else {
send_template_mail_to_all(subscribers);
}
}());
function get_subscription_flag(request, person_id) {
let subscription_flag = null;
mergeAudit(request);
let person = fetch('people', person_id);
if (request.audit_is_changed_custom_data) {
let subscribersOld = request.audit_old_custom_data.monitor_subscribers;
let subscribersNew = request.audit_new_custom_data.monitor_subscribers;
let subscribedOld = subscribersOld.includes(person.primary_email);
let subscribedNew = subscribersNew.includes(person.primary_email);
if (subscribedNew && !subscribedOld) {
subscription_flag = 'SUBSCRIBED';
}
if (subscribedOld && !subscribedNew) {
subscription_flag = 'UNSUBSCRIBED';
}
}
return subscription_flag;
}
function send_template_mail(send_to) {
let mailData = createTemplateHTMLMail('request-watch-all-notes');
mailData.to = send_to;
mailData.profile = 'xurrent-automation';
sendMail(mailData);
}
function send_template_mail_to_all(subscribers) {
for (let subscriber of subscribers) {
send_template_mail(subscriber);
}
}