Skip to main content
Version: v5.0

How to set up a notification

Overview#

This page describes how to set up the Notification Service to send an email to interested users when a particular system event occurs. In this example, the system event is when an orchestrator run has completed. This page also describes how to create a subscription email and register a user to receive notifications.

Useful concepts#

There are some key concepts related to the Notification Service that will help with understanding this example:

Steps for setting up an email subscription to notify users of a system event#

To set up an email subscription, do the following:

  1. Create a subscription email template

  2. Create a sender

  3. Create a group

  4. Retrieve your default email device (or create a new one)

  5. Create a subscription

  6. Accept the subscription

  7. Create a notification email template

  8. Create a trigger

  9. Invoke the trigger

Step 1: Create a subscription email template#

First you will need to create a template that will be used to generate the email that will be sent to a user when their email subscription is created. This email is always sent first whenever a new subscription is created, and the user must confirm their interest in the subscription in order to receive further emails.

Write the templates using the Velocity template format. See the Templates page for more information.

To create a SUBSCRIBE_VERIFY email template, refer to the example below.

Note: The most important part of the SUBSCRIBE_VERIFY email template is the ${acceptLink} reference. This is the link that the user must follow in order to accept a newly-created subscription.

const subscribeVerifyBody = "<html>  <body>    <h2>Subscription Verification - $applicationName</h2>    <p>Your device: $device.email.address</p>    <p>      <a href="$acceptLink">Confirm Subscription</a>    </p>    <p>Request details: $request</p>    #if($group)      <p>Group: $group.name</p>    #end  </body></html>";
const subscribeVerifyTemplate = await IafNotification.createTemplate({    _namespaces: project._namespaces,    _transport: "EMAIL",    _name: "susbcribe_verify",    _format: "VELOCITY",    _locale: "en-GB",    _email: {        _subject: "New subscription created, please accept",        _body: subscribeVerifyBody    }}, ctx);
console.log("Created template:", subscriberVerifyTemplate);

Step 2: Create a sender#

A sender represents the "From" identity for notifications, the source of the emails. It also references the templates that will be used for internal actions, like the SUBSCRIBE_VERIFY action used for creating a template.

When a link in the SUBSCRIBE_VERIFY email is followed, (the ${acceptLink} reference used in the template, the notification service will transition a subscription from the REQUESTED to the ACCEPTED state.

This new state and it will be able to receive email notifications. The sender also supports setting up a custom redirect URL. After the subscription has been accepted the user will be redirected to the URL for SUBSCRIBE_SUCCESS.

To create a sender, refer to the sample code below.

const sender = await IafNotification.createSender({    _namespaces: project._namespaces,    _transport: "EMAIL",    _name: "sender_1",    _email: {      _address: "[email protected]",      _displayName : "Twinit.dev (INQA1)"    },    _templates: {        "SUBSCRIBE_VERIFY": {            _id: subscribeVerifyTemplate._id        }    },    _redirects: {        "SUBSCRIBE_SUCCESS": "http://example.com/subscribe-success",        "SUBSCRIBE_FAILURE": "http://example.com/subscribe-failure"    }}, ctx);
console.log("Created sender:", sender);

Step 3: Create a group#

Groups represent user audiences interested in specific notifications. Groups are used to organize subscriptions under application-specific topics of interest.

To create a group of users interested in a subscription, refer to the sample code below.

const group = await IafNotification.createGroup({    _namespaces: project._namespaces,    _name: "group_1"}, ctx);
console.log("Created group:"group);

Step 4: Retrieve your default email device (or create a new one)#

Devices are 'owned' by individual users, rather than belonging to a namespace like other resource types.

By default, your registered email address is in the Passport Service and this will be automatically created as a device. You can query the system for your default device, or create a new device with an additional email address.

To retrieve your email device, refer to the sample code below:

const userId = "<your user id>";
const devices = await IafNotification.listDevices({    owner: {        irn: "passportsvc:user:${userId}"    }    transport: "EMAIL"}, ctx);
// Validate that list is non-empty, etc
const device = devices._list[0];
console.log("Got device:", device);

Alternatively, to create a new device, refer to the sample code below:

const device = await IafNotification.createDevice({    _owner: {        _irn: "passportsvc:user:<your user id>"    },    _transport: "EMAIL",    _email: {        _address: "<additional email address>"    }}, ctx);

Step 5: Create a subscription#

Now, you need to subscribe the device to the group. To achieve this, you need to create a subscription, and reference both the group and the device created in the earlier steps.

Refer to the sample code below:

const subscription = await IafNotification.createSubscription({    _namespaces: project._namespaces,    _group: {        _id: group.id    },    _device: {        _id: device.id    }}, ctx);
console.log("Created subscription:", subscription)

Note: The newly created subscription will initially be in the REQUESTED state.

Step 6: Accept the subscription#

The Notification Service will send an email to the address indicated in the device. This email address will be either the user's registered email address, or the additional email address, depending on the action taken in the earlier step.

When you receive the email, click the link to accept the subscription.

The subscription should now be in the ACCEPTED state. You can retrieve the subcription to confirm that it is in the ACCEPTED state. Refer to the sample code below.

const checkSubscription = await IafNotification.getSubscription(subscription.id, ctx);
console.log(checkSubscription);

Step 7: Create a notification email template#

Now, create the template for the notification email which will be sent when a particular system resource is created. The resource event is defined in the next step.

For now, create a generic email body. The email body can contain links to cancel the subscription, or to cancel all existing subscriptions. It is good practice to include those two links, as it allows a user to easily unsubscribe from groups they are no longer interested in, directly from their email client. The Velocity template parameters ${cancelLink} and ${cancelAllLink} respectively are used for these links.

Refer to sample code below.

const templateBody = "<html>  <body>    <h2>Hello from \$applicationName!</h2>    <p>The orchestrator with id \${request.resource.orchestratorId} has just completed.</p>    <p>      <a href="$cancelLink">Cancel This Subscription</a> |      <a href="$cancelAllLink">Cancel All Subscriptions</a>    </p>  </body></html>";
const template = await IafNotification.createTemplate({    _namespaces: project._namespaces,    _transport: "EMAIL",    _name: "template_1",    _format: "VELOCITY",    _locale: "en-GB",    _email: {        _subject: "Orchestrator run completed",        _body: templateBody    }}, ctx);
console.log("Created template:", template);

Step 8: Create a trigger#

A trigger is a rule that determines when a notification is sent. Triggers are matched to incoming events. For an event type trigger, we must indicate the type of event that we are interested in.

In this example, we want the trigger event to match orchestrator runs in the namespace that have moved to the COMPLETED state.

Set up an event filter, referring to the sample code below.

{  "event": "resource.ResourceCreated",  "resource.type": "datasources.OrchestratorRun",  "resource.namespaces": project._namespaces[0],  "resource.after.status": "COMPLETED"}

Note the following:

  • In this example, the event type is resource.ResourceCreated.
  • The resource type, is datasources.OrchestratorRun.
  • The resource namespaces are those of the current project.
  • A filter for resource.namespaces must always be included, and will be validated against the owning namespace of the trigger.
  • We want to match against the orchestrator run status, so the trigger will fire when the orchestrator run transitions to the COMPLETED status.

You can add further conditions to this filter, to look for a specific orchestrator run ID by adding the line below.

{ "resource.orchestratorId": "<orchestrator id>" }

Note: For a full list of all the system events which can be used with the Notification Service, refer to the Notification Service Events page.

Now, create the trigger which will the event filter and also reference the group, sender, and templete which has previously been created. Refer to the sample code below.

const trigger = await IafNotification.createTrigger{    _namespaces: project._namespaces,    _type: "EVENT",    _name: "trigger_1",    _event: {        _filters: {            "event": "resource.ResourceUpdated",            "resource.type": "datasources.OrchestratorRun",            "resource.namespaces": project._namespaces[0],            "resource.after.status": "COMPLETED"        }    },    _senders: [        {            _id: sender.id        }       ],    _groups: [        {            _id: group.id        }       ]    _templates: [        {            _id: template.id        }       ]}, ctx);
console.log("Create trigger:", trigger);

Step 9: Invoke the trigger#

If you now create and run a new orchestrator, when the orchestrator completes, the trigger will match and a notification will be sent to the configured email address.

For testing, create a minimal/empty instant orchestrator, and so the orchestrator run will immediately transition to the COMPLETED state.

const orchestrator = await IafDataSource.createOrchestrator({    "_name": "test-1"    "_description": "test-1",    "_namespaces": project._namespaces,    "_userType": "test-1",    "_instant": true,    "_params": {        "tasks": [        ]    }    }, ctx);
console.log("Created orchestrator:", orchestrator);
const orchestratorRun = await IafDataSource.runOrchestrator(orchestrator.id, {orchestratorId: orchestrator.id}, ctx);
console.log("Created orchestrator run:", orchestratorRun);