VERSION 10 (DRAFT)
PIPEFORCE comes with a comprehensive multi-channel and multi-language framework which allows to generate notification messages dynamically from templates in different multiple languages and send them to multiple channels. Such a target channel for example can be : Email, Slack, Teams, SMS, WhatsApp, Message Queue and many others.
Additionally, this framework includes also push events. This means a user or group of users can subscribe to certain PIPEFORCE events. Every time such an event happens, they will be informed about this on the configured channel in the preferred language.
Target addresses of notifications can be for example email addresses, IAM usernames, IAM group names, chat groups or other custom addresses as further described below.
What is the difference between a message and a notification?
A notification is usually send to a human user. It is a subset of the message class since a message can be any kind of information send to users and or systems.
Quick Start Guides
For those not interested in the details but want to have a quick result, here are the quick start guides for the most common use cases using the notification framework.
Send a plain text email (simple mode)
In case you would like to send a simple plain text email to a given set of email addresses, you can simply use a pipeline like this:
pipeline: - notification.send: to: ["email1@domain.tld", "email2@domain.tld"] cc: ["email3@domain.tld"] bcc: ["email4@domain.tld"] subject: "This is the subject" message: "This is the plain text body." attachments: ["$uri:attachment:path/to/attachment"]
The notification framework will automatically detect the target channel (which is email in this example) and renders and sends the according mime message for you. This is the easiest approach.
Aliases to the notification.send
command are notifcation.put
and mail.send
.
In some cases you might have the requirement to further customize the mime message. For this, see the examples below for more details.
Send a plain text email (customize mode)
In case you would like to further customize the mime headers or the multipart body of an email, you can use this approach instead:
pipeline: - notification.send: input: { "headers": { "to": ["email1@domain.tld", "email2@domain.tld"], "cc": ["email3@domain.tld"], "bcc": ["email4@domain.tld"], "subject": "This is the subject", } "body": { "contentType": "text/plain", "content": "This is the plain text body." } }
Note that the notification input
is a 100% mime message (RFC2045. ) compliant format. This means it is separated into a headers
and a body
section. In the headers section all headers from the MIME standard are supported. They will be forwarded to the target channel, like email client for example. Also the body section is fully compliant with RFC2045 so you can construct any multipart body structure you need for the target client. For further details about such a structure please consult external documentation about how to construct valid multipart mime messages.
Send a mixed-content multipart mime message
In case you would like to compose a multipart mime message with mixed content, you can use this example as a template:
pipeline: - notification.send: input: { "headers": { "to": ["email1@domain.tld", "email2@domain.tld"], "cc": ["email3@domain.tld"], "bcc": ["email4@domain.tld"], "subject": "This is the subject", } "body": { "contentType": "multipart/mixed", "content": [ { "contentType": "multipart/alternative", "content": [ { "contentType": "text/plain; charset=UTF-8", "content": "This is the plain text body." }, { "contentType": "text/html; charset=UTF-8", "content": "$uri:property:global/app/my.app/template/body" } ] }, { "contentType": "image/jpeg", "contentDisposition": "attachment; filename=\"bild.jpg\"", "contentTransferEncoding": "base64", "content": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAHBgoJCAkLC..." }, { "contentType": "application/pdf", "contentDisposition": "attachment; filename=\"dokument.pdf\"", "contentTransferEncoding": "outbound", "content": "$uri:attachment:some-attachment-uuid" } ] } } }
For specific details about the structure of a multipart mime message, please have look at the RFC2045.
As you can see in this example, the body
can be a list of nested content objects.
The content
value itself can be a fixed text, a base64 string or a PIPEFORCE URI pointing to a resource to load.
Attachments
You can also add (file) attachments to notifications. Depending on the target channel they will be provided as downloads or embedded when the notification shows-up in the channel client.
Simple Mode
In order to add (file) attachments to your notification, you have multiple options. The easiest approach is to use the attachments
attribute of the notification.send
command:
pipeline: - notification.send: to: ["email1@domain.tld", "email2@domain.tld"] subject: "This is the subject" message: "This is the plain text body." attachments: ["$uri:attachment:path/file1", "$uri:attachment:path/file2"]
The command will try to autodetect all required attachment information from the list of given attachments and append it to the body content in multipart mime format at the very end. It wont overwrite any existing part there.
Combined Mode
This way you can combine the simplified parameter format with a specific one. For example:
pipeline: - notification.send: to: ["email1@domain.tld", "email2@domain.tld"] subject: "This is the subject" attachments: ["$uri:attachment:path/file1", "$uri:attachment:path/file2"] input: { "body": { "contentType": "text/plain", "content": "This is the plain text body." } }
The final multipart mime message, which will be send to the email channel will be this (since the simplified parameters are merged into the input notification):
{ "headers": { "to": ["email1@domain.tld", "email2@domain.tld"], "subject": "This is the subject" } "body": { "contentType": "multipart/mixed", "content": [ { "contentType": "text/plain", "content": "This is the plain text body." }, { "contentType": "application/pdf", "contentDisposition": "attachment; filename=\"file1\"", "contentTransferEncoding": "outbound", "content": "$uri:attachment:path/file1" }, { "contentType": "application/pdf", "contentDisposition": "attachment; filename=\"file2\"", "contentTransferEncoding": "outbound", "content": "$uri:attachment:path/file2" } ] } } }
Note:
All given values from command parameters will overwrite the values in the mime message if there are any.
In case the section doesn’t exist yet in the mime message, it will be created.
It could be that the original mime message needs to be re-arranged to insert the parameter values: For example in case you would like to add
attachments
via command parameter to an existingtext/plain
input body. In this case, the body will be converted tomultipart/mixed
and the text plus attachments will be nested inside.
Customized Mode
Another option is to create the content JSON objects inside the mime message manually and set the attachments accordingly accordingly to the RFC Mime Messages specification. This is the solution which is most flexible and highly customizable. But it is also the most complex approach.
Attaching content references
You can also use content references loaded into a pipeline scope like vars
or body
as source for attachments. For example:
pipeline: - drive.read: path: "contract.docx" - notification.send: to: "recipient@domain.tld" subject: "This is the contract" message: "Hello, attached you can find the contract for your reference." attachments: ${body}
In this example the file is first loaded (implicitly) to body using the command drive.read
and then linked to the attachments
parameter. You can place any content reference as attachment.
Using this approach it is also possible to create the attachments dynamically on-the-fly in the pipeline (for example by using a template engine) and then add them finally to the email.
Templating Notifications
You can create dynamic notification texts and layouts using templating.
Using a Transformer
You can use a transformer command like transform.ftl in order to render the message. For example:
vars: name: "Sam" email: "recipient@domain.tld" pipeline: - transform.ftl: template: | Hello ${vars.name}, this is an email sent from a pipeline. Greetings - notification.send: to: ${vars.email} subject: "This is for ${vars.name}" message: ${body}
In this example, the message is rendered and then stored in the body using transform.ftl
. The command notification.send
then picks up the rendered message from the body and uses it as email message.
And here is an example to load the template from the property store from location global/app/myapp/template/email
:
vars: name: "Sam" email: "recipient@domain.tld" pipeline: - transform.ftl: template: "$uri:property:global/app/myapp/template/email" - notification.send: to: ${vars.email} subject: "This is for ${vars.name}" message: ${body}
Embedded template URIs
It is also possible to embed the template references inside the mime notification using PIPEFORCE URIs. For example:
pipeline: - notification.send: input: { "headers": { "to": ["email1@domain.tld", "email2@domain.tld"], "subject": "$uri:template:global/app/my.app/template/subject", } "body": { "contentType": "multipart/mixed", "content": [ { "contentType": "multipart/alternative", "content": [ { "contentType": "text/plain; charset=UTF-8", "content": "$uri:template:global/app/my.app/template/body_txt" }, { "contentType": "text/html; charset=UTF-8", "content": "$uri:template:global/app/my.app/template/body_html" } ] } ] } }
In this example the $uri:template:
URI is used. This will load the template from given location in property store and will render it using the template engine which fits the Content-Type of the property. By default, this is the FreeMarker Template Engine. Also all other PIPEFORCE URIs are supported here instead.
Any time the notification is sent, the elements of the mime message will be recursively scanned for PIPEFORCE URIs. In case one is found, it will be called and in case it is supported, the current mime notification object will be auto-passed to the template and can be used there to access all relevant data from the mime message to render the template. Here is an example for a message rendered using the FreeMarker Template Language:
Hello ${headers.to?join(", ")}, this is an email with subject: ${headers.subject} Cheers
The fields in the mime message supporting such $uri:
references are:
headers
to
cc
from
bcc
subject
content
(including all nested ones)
Addresses and Address Resolving
In the headers section of a mime notification you can declare the addresses of the recipients where the notification must be send to. Here is an example how to do this directly inside the mime notification JSON:
pipeline: - notification.send: input: { "headers": { "to": ["email1@domain.tld", "email2@domain.tld"], "cc": ["email3@domain.tld"], "bcc": ["email4@domain.tld"], "subject": "This is the subject", } "body": { "contentType": "text/plain", "content": "This is the plain text body." } }
As an alternative you can also use the simple mode by declaring them as parameters directly on the command:
pipeline: - notification.send: to: ["email1@domain.tld", "email2@domain.tld"] cc: "email3@domain.tld" bcc: "email4@domain.tld" subject: "This is the subject" message: "This is the plain text body."
These address parameters will be converted to a mime notification JSON and placed in its header section for you.
Addresses prefixed with $uri:
By default all addresses are assumed to be valid email addresses. But you can also use other address types to send the notification to a different channel. In case an address is not an email address, it always must be prefixed with $uri:
. Here is an example to use a Slack channel as target address instead:
pipeline: - notification.send: to: "$uri:slack:mychatgroup" subject: "This is the subject" message: "This is the plain text body."
In this example, the message will be send to a Slack channel instead of via email. You can also combine different addresses of different types like this example shows:
pipeline: - notification.send: to: ["$uri:slack:mychatgroup", "email1@domain.tld"] subject: "This is the subject" message: "This is the plain text body."
In this example the notification will be rendered as a Slack message and send to the Slack channel with name mychatgroup
and additionally it will be rendered as email message and send to the email address email1@domain.tld
.
Final and resolving addresses
There can be final and resolving addresses:
Final address: The address can be used by a channel to deliver the message. For example an email address.
Resolving address: The address needs to resolved (expanded) to one or more final addresses first, before it can be used by a channel to deliver the notification. For example an address referring to a user in IAM must first be expanded (resolved) to the user’s email address before the notification can be send.
Here is an example how such a resolving could look like:
Some resolving addresses could also be recursive.
This resolving (expanding) is automatically done by the notification framework.
Some notes about this example:
A: Final addresses. They will be used to send the notification directly to the channels.
B: The supervisor will get this notification via its default email.
C: Any user who is member of group
sales
will get this notification via its preferred notification channel. In this example, this is usermanager1
and his notification channels from IAM aresales1@company.tld
andprivate1@mail.tld
.D: The group
sales
contains another groupadmins
and therefore all members of this role will additionally get the notification via their preferred address.
When the notification is processed, all groups and users will be resolved and the preferred channel will be used to send the notification.
Note: Duplicate addresses will be removed (for example because a user is member of multiple groups or roles configured for the notification, so his address is used only once).
$uri:email:
This final address will send the notification via email. The format is like this:
$uri:email:<email-address>
For example:
$uri:email:foo.bar@logabit.com
This is an alternative to not using the prefix at all. So this is also a valid email address:
foo.bar@logabit.com
$uri:user:
This resolving address will lookup the user with given username in IAM (user management) and be converted to the registered target address of the user which is an email address by default.
The format is like this:
$uri:user:<username>
Whereas <username>
must be an enabled and exiting user in IAM with is username.
For example:
$uri:user:maxhuber
In case the user is disabled or doesn’t exist, this address will be ignored and removed from the address fields.
For example:
Let’s assume as default address of the user maxhuber
in IAM the email address foo.bar@logabit.com
is configured, then an address field like this:
|
|
Will be resolved to this:
|
|
$uri:group:
This resolving address will lookup a group with given name in IAM (user management) and it will be resolved to the default addresses of all user members of this group.
The format is like this:
$uri:group:<groupname>
Whereas <groupname>
must be an enabled and existing group in IAM with this group name. For example:
$uri:group:sales
In case the group is disabled or doesn’t exist, this address will be ignored and removed from the address fields.
For example:
Let’s assume there is a group sales
in IAM with with these member users and their default target addresses configured in IAM:
Username | Target Address |
---|---|
teamlead | teamlead@mail.tld |
user1 | $uri:slack:mychannel |
user2 | $uri:email:user2@mail.tld |
Then, an address field like this:
|
|
Will be resolved to this:
|
|
$uri:slack:
This final address will send the notification to a Slack channel as configured by the connection config id.
The format is like this:
$uri:slack:<connection-config-id>
Whereas <connection-config-id>
must be an id of a valid and enabled connection configuration.
For example:
$uri:slack:sales-channel
$uri:teams:
This final address will send the notification to a Microsoft Teams channel as configured by the connection config id.
The format is like this:
$uri:teams:<connection-config-id>
Whereas <connection-config-id>
must be an id of a valid and enabled connection configuration.
For example:
$uri:teams:sales-team
$uri:message-route:
This is a final address: It will forward the message to the message broker using the given routing key.
The format is like this:
$uri:message-route:<routing-key>
Whereas <routing-key>
is the target routing key where the message must be forwarded to. The mime notification headers will be set as message headers and the body will be serialized as JSON into the playload of the message.
For example:
$uri:message-route:security_audit_queue
$uri:pipeline:
This resolving address will call the pipeline given by path, puts the mime notification into its body and executes it. It expects a JSON array of addresses to be returned, all starting with prefix $uri:
. Otherwise, the address will be ignored. These addresses will then replace the $uri:pipeline:
address in the fields.
The format is like this:
$uri:pipeline:<pipeline-path>
For example:
$uri:pipeline:global/app/my.app/pipeline/dynamic-addresses
The dynamic-addresses
pipeline could look like this example to return addresses dynamically:
pipeline: - body.set: value: ["$uri:email:address1@mail.tld", "$uri:user:someusername"]
$uri:property:
This resolving address will load the property at given path and expects the value to be a JSON array containing the addresses to be returned.
The format is like this:
$uri:property:<property-path>
For example:
$uri:property:global/app/my.app/data/my-addresses
The my-addresses
pipeline could look like this example:
["$uri:email:address1@mail.tld", "$uri:user:someusername"]
Recursive resolving of addresses
Resolving addresses are resolved (expanded) recursively until the final address appears. So for example a resolving address given like this:
|
|
Could return and resolve to:
|
|
Which in term could resolve to this in the next recursion:
|
|
Which resolves to these final addresses:
|
|
Excluding addresses
It is possible to exclude certain addresses from a mime message. To do so, you can use the custom header x-pipeforce-exclude-addresses
and specify the addresses to be excluded. For example:
pipeline: - notification.send: input: { "headers": { "x-pipeforce-exclude-addresses": ["$uri:group:vacation"] "to": ["$uri:group:sales"], "subject": "New lead", } "body": { "contentType": "text/plain", "content": "Hi, a new lead was created." } }
In this example, the New lead
notification will be send to all members of group sales
excluding those users also in group vacation
.
Exclude addresses can be final and resolving addresses.
Multi-Language Notifications (i18n)
The notification framework supports multi language notifications. This means a notification can be send in different languages to the recipients.
How to enable it
In order to enable multi-language (i18n) support, you have to set the header x-pipeforce-multilang
to true
.
How it works
If this header is set, the framework will consider these rules:
It will look for a query param
?locale=<lang>
in each address.
For example:$uri:email:foo@bar.tld?locale=de
. If no locale exists it will useen
as default.If the address is an IAM address like
$uri:group:
or$uri:user:
it will use the value of user attributelocale
from IAM for the locale if exists. Otherwise, it will fallback toen
as default. If both are given (query param and locale attribute in IAM), the query param will have precedence.It will split a notification to multiple notifications for each new language and will manage to split also addresses according to these languages. For example if there are these TO addresses set:
$uri:email:my@mail.tld?locale=de, $uri:email:another@mail.tld?locale=en
this means two emails will be rendered and send: One withde
as language with german text in subject and body and one with english text. Finally, there will be two emails: The DE one is sent tomy@mail.tld
and the EN one sent toanother@mail.tld
. The same is true for addresses in CC and BCC.Any
$uri:template
,$uri:property
or$uri:pipeline
which is used in subject and body of the notification will automatically be suffixed with the selected locale. So for example$uri:template:mytemplate
will become$uri:template:mytemplate_de
in case the locale is set to?locale=de
via address query param or IAM. This way different templates can be provided in the property store and the notification framework will pick-up the one which belongs to the selected language.
Multi-Channel Notifications
The notification framework also supports sending a notification to different channels. This way it is possible beside via email, the same notification can be send to a Slack channel, via SMS and Teams for example. For each channel, different templates can be provided in order to adjust the format of the message so it fits the target channel.
How to enable it
In order to enable multi-channel support, you have to set the header x-pipeforce-multichannel
to true
.
How it works
If multi-channel support is enabled, the framework will handle a notification similar to the multi-language approach:
It will look for the final addresses in the address uri. For example:
$uri:email: →
email
channel$uri:slack: →
slack
channel$uri:teams: →
teams
channel$uri:sms →
sms
channelaso.
It will split a single notification to multiple notification messages: For each new channel and will manage to split also addresses according to these channels. For example if there are these TO addresses set:
$uri:email:my@mail.tld?locale=de, $uri:slack:mygroup
this means two notifications will be rendered and send: One as email and the other one as Slack message. The same is true for addresses in CC and BCC.Any
$uri:template
,$uri:property
or$uri:pipeline
which is used in subject and body of the notification will automatically be suffixed with the selected channel. So for example$uri:template:mytemplate
will become$uri:template:mytemplate_slack
in case the channel is set toslack
via address. This way, different templates can be provided in the property store and the notification framework will pick-up the one which belongs to the selected channel.
In case both multi-lang and multi-channel are enabled for the notification, the channel name and the selected locale will be suffixed as _<channel>_<locale>
. For example $uri:template:mytemplate
becomes $uri:template:mytemplate_slack_de
in case the detected channel from address is slack
and the detected language is de
. This way you can create template specific to channel + language.
Push Notifications
Push notifications are system and business events, a user can subscribe to. Any time there is a match, such an event is automatically converted to a notification and will be send to the registered user's preferred communication channels like email or chat group for example.
A push notification always starts with a message sent with routing key pipeforce.event.#
. All messages having a routing key starting with this prefix will be stored in the pipeforce_push
queue.
By default the pipeforce_push
queue has these restrictions:
Max. number of messages in queue: 20.000
Max. time to life: 48 hours
Max. size of all messages in queue: 100 MB
As soon as one of these restrictions are met, oldest messages will be deleted.
Subscribe to push notifications
In order to receive push notifications, you have to subscribe to event keys, called topics, first.
This is done in PIPEFORCE by creating a JSON document in a folder with name push
inside your app. For example global/app/my.app/push/my-subscription
.
This JSON document is called push subscription and has a structure like this:
{ "enabled": true, "includeTopics": [ "pipeforce.event.#.error.#", "pipeforce.event.#.warn.#", "pipeforce.event.iam.#" ], "excludeTopics": [ "pipeforce.event.iam.refresh.token", "pipeforce.event.iam.admin.create.realm.role" ], "headers": { "to": [ "$uri:group:Administrator (Standard)", "some@mail.tld", "$uri:wf-task-assignee" ] } }
All push subscriptions inside the push
folder of any app will be picked-up automatically and activated on save and deactivated on delete. There is no need to extra register it.
The fields of this JSON are described below.
"enabled"
Is the push subscription enabled (true
)? Default is true
in case attribute is not given.
"includeTopics"
The routing keys of messages inside the pipeforce_push
queue to get informed about.
"excludeTopics"
The routing keys to exclude explicitly (for example if it is sub-pattern of an includeTopic).
Both
includeTopics
andexcludeTopics
support the wildcard pattern from RabbitMQ:* = A single part between two dots .
# = Anything which comes after.
"headers"
Since a push subscription is based on a mime notification it can contain all of its headers such as:
to
: A list of addresses, to send the push notification to.cc
: A list of addresses, to send the push notification to in CC.bcc
: A list of addresses, to send the push notification to in BCC.subject
: The subject to be used for the push notification. If no subject is set, a default subject is generated.x-pipeforce-exclude-addresses
: A list of addresses to exclude from the push notification.
"body"
The multipart body message to be send as the push notification payload. If no body exists, a default body is generated. Everything described for the body of mime notification can also be applied here.
Topics
A topic in a push subscription is a routing key pattern of an event message which always starts with prefix pipeforce.event
, followed by the concrete topic type.
In case the routing key of a an event message matches this pattern, a new push notification will be generated and send to all addresses as configured in the push subscription.
The topic can contain wildcards:
*
= Stands for a single word up to the next period.
#
= Stands for multiple words with multiple periods in between.
For example: pipeforce.event.workflow.#
matches all workflow event messages while pipeforce.event.workflow.*.my.app
matches only workflow event messages inside the app my.app
.
pipeforce.event.iam
This topic group forwards all important events happening inside IAM.
.admin.client.create.client
This event message is send after a new client was created.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.client.create.client
.admin.update.client
This event message is send after a client was updated by an admin.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.update.client
.admin.delete.client.scope.client.mapping
This event message is send after a client scope mapping was deleted.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.delete.client.scope.client.mapping
.admin.create.group
This event message is send after a new group was created.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.create.group
.admin.create.user
This event message is send after a new user was created.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.create.user
.admin.client.create.role
This event message is send after a new role was created.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.create.role
.admin.create.group.membership
This event message is send after a member was added to a group.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.create.group.membership
.admin.create.realm.role.mapping
This event message is send after a resource was mapped to a realm role.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.create.realm.role.mapping
.admin.action.user
This event message is send after a user has done a predefined action.
The full structure of the event message routing key is like this:
pipeforce.event.iam.admin.action.user
.client.login
This event message is send after an OAuth2 client has been logged-in.
The full structure of the event message routing key is like this:
pipeforce.event.iam.client.login
.code.to.token
This event message is send after a code has been exchanged to token.
The full structure of the event message routing key is like this:
pipeforce.event.iam.code.to.token
.login
This event message is send after user has successfully logged-in.
The full structure of the event message routing key is like this:
pipeforce.event.iam.login
.logout
This event message is send after user has successfully logged-out.
The full structure of the event message routing key is like this:
pipeforce.event.iam.login
.refresh.token
This event message is send after a token has been refreshed.
The full structure of the event message routing key is like this:
pipeforce.event.iam.refresh.token
.token.exchange
This event message is send after a token has been exchanged.
The full structure of the event message routing key is like this:
pipeforce.event.iam.token.exchange
.user.info.request
This event message is send after user information have been requested.
The full structure of the event message routing key is like this:
pipeforce.event.iam.user.info.request
pipeforce.event.property
This topic group forwards all property events as push notifications.
Every property topic key can additionally contain dynamic variables which will be replaced at runtime such as:
{path}
= The path of the related property whereas slashes in path of property will become dots. Dots and special chars in origin path will be replaced by underscores. Everything in path is lower-cased.
.created
This event message is send after a new property was created.
The full structure of the event message routing key is like this:
pipeforce.event.property.created.{path}
.deleted
This event message is send after a property was deleted.
The full structure of the event message routing key is like this:
pipeforce.event.property.deleted.{path}
.updated
This event message is send after a property was updated.
The full structure of the event message routing key is like this:
pipeforce.event.property.updated.{path}
pipeforce.event.log
This topic group forwards all important log events of severity level WARN
or higher.
Every log topic key can additionally contain dynamic variables which will be replaced at runtime such as:
{loggerName}
= The name of the logger used internally.
This way you can also listen to events of a certain level and logger type using a pattern. Here is an example which listens for all log levels (warn
and above) happening inside the com.logabit
package: this for example: pipeforce.event.log.*.com.logabit.#
.error
This event message is send after a new log entry of level ERROR
was created.
The full structure of the event message routing key is like this:
pipeforce.event.log.error.{loggerName}
.warn
This event message is send after a new log entry of level WARN
was created.
The full structure of the event message routing key is like this:
pipeforce.event.log.warn.{loggerName}
pipeforce.event.workflow
Every workflow topic key can additionally contain dynamic values which will be replaced at runtime such as:
{appName}
= Will be replaced by the app name the workflow is stored inside (example: io.pipeforce.myapp).
{wfName}
= Will be replaced by the property name of the workflow definition in the workflow folder inside the app (example: myworkflow)
Workflow address variables ($uri:wf-)
In case a push event is a workflow event (pipeforce.event.workflow.#
), these additional address variables can be used in TO, CC and BCC fields to refer to data from the event message:
$uri:wf-process-involved-users
= Returns the$uri:user:<username>
of all users involved in the workflow process.$uri:wf-started-by
= Returns the$uri:user:<username>
of the user who started the workflow.$uri:wf-task-candidate-groups
= Returns the$uri:group:<name>
names of all groups which are set as candidate group of given task. In case there is no candidate group set, the address variable will be removed from all address fields.$uri:wf-task-assignee
= Returns the$uri:user:<username>
of the user who is set as assignee on given workflow task. In case there is no taskAssignee set, the address variable will be removed from all address fields.$uri:wf-task-owner
= Returns the$uri:user:<username>
of the user who is set as assignee on the given workflow task. In case there is no taskOwner set, the address variable will be removed from all address fields.
Duplicate addresses will always be removed.
.comment.create
This event message is send after comment to a workflow process was created.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.comment.create.{appName}.{wfName}
.comment.update
This event message is send after comment to a workflow process was updated.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.comment.update.{appName}.{wfName}
.end
This event message is send after a workflow process have been finished.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.end.{appName}.{wfName}
.task.assignment
This event message is send after the task assignee has changed.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.task.assignment.{appName}.{wfName}
.task.complete
This event message is send after a task was completed.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.task.complete.{appName}.{wfName}
.task.create
This event message is send after a new task in a workflow process was started (created).
The full structure of the event message routing key is like this:
pipeforce.event.workflow.task.create.{appName}.{wfName}
.task.delete
This event message is send after a task was deleted.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.task.delete.{appName}.{wfName}
.task.timeout
This event message is send after a task timeout happened.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.task.delete.{appName}.{wfName}
.task.update
This event message is send after a metadata or variables of a task have been updated.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.task.update.{appName}.{wfName}
.transition
This event message is send after a (task) transition have been occurred from one state to another.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.transition.{appName}.{wfName}
.start
This event message is send after a new workflow process have been started.
The full structure of the event message routing key is like this:
pipeforce.event.workflow.start.{appName}.{wfName}
Custom Topics
You can also send push notifications based on your custom topics.
To do so, you need to configure these steps:
Make sure to send event messages using a routing key format like this
pipeforce.event.<yourName>
usingmessage.send
command. Replace<yourName>
by the custom name you would like to use. Best practise is to use the prefixapp
and the name of the app followed by the concrete event name to not potentially collide with other topics from other apps. For example:pipeforce.event.app.com.company.myapp.myaction
This way it is also easy to filter later using patterns. Examples:pipeforce.event.app.#
= Listens to all events from all apps.pipeforce.event.app.com.company.#
= Listens to all events from all apps from givencompany
.pipeforce.event.app.com.company.myapp.#
= Listens to all events from appmyapp
.pipeforce.event.app.com.company.myapp.myaction
= Listens to the exactmyaction
event.
Create a new push notification configuration inside the
push
folder of your app and make sure to map theincludeTopics
correctly to the recipients.
Example push notification configuration:
{ "includeTopics": [ "pipeforce.event.app.com.company.myapp.#" ], "headers": { "to": [ "$uri:group:my-custom-group" ] } }
This push notification configuration makes sure, every time a custom event for the app myapp
appears, it will be pushed to all users of group $uri:group:my-custom-group
.
Exclude addresses from topics
There is an exclude list to make sure certain push notifications are not sent to these addresses. They can be configured using the header x-pipeforce-exclude-addresses
as described for the mime notification.
Furthermore, it is possible to set the attribute excludeTopic
for a specific user in IAM. In case the addresses $uri:group
or $uri:user
are used and excludeTopic
exists for a matching user, it will be checked whether this user should be excluded from the push notification.
See here as an example:
There can be multiple attributes with name excludeTopics
or the values can be separated by comma. Both approaches work and can also be combined (for example to group certain excludeTopics
).
Templating Push Notifications
Since push notifications are based on Mime Notifications, all rules of mime notifications apply.
In case no subject or body is defined, a default subject and body is created for each push notification.
In case you would like to use a custom text there, you can do so by setting it in the push subscription. For example:
{ "includeTopics": [ "pipeforce.event.app.com.company.myapp.#" ], "headers": { "to": [ "$uri:group:my-custom-group" ], "subject": "This is the subject of the push notification" }, "body": { "contentType": "text/plain; charset=UTF-8", "content": "This is the body of the push notification." } }
It is also possible to refer to templates in subscription and content (which will be rendered later in the process):
{ "includeTopics": [ "pipeforce.event.app.com.company.myapp.#" ], "headers": { "to": [ "$uri:group:my-custom-group" ], "subject": "$uri:property:path/to/my/subject-template" }, "body": { "contentType": "text/plain; charset=UTF-8", "content": "$uri:property:path/to/my/subject-body-template" } }
Global Push Configuration
You can disable / enable global push notifications in admin settings.
Note: If disabled, events will not be catched from the pipeforce_push
queue so outdates, too many event messages there will be deleted.
Also see the restrictions of the queue above.
Default Push Subscriptions
Inside global/app/io.pipeforce.admin/push/
there are default push subscriptions for admins, developers and users.
Add Comment