Skip to content

Instantly share code, notes, and snippets.

@josephdpurcell
Last active January 21, 2023 02:54
Show Gist options
  • Save josephdpurcell/3f1a42ee1fe5b7d298f5862665c7b0f8 to your computer and use it in GitHub Desktop.
Save josephdpurcell/3f1a42ee1fe5b7d298f5862665c7b0f8 to your computer and use it in GitHub Desktop.
How to integrate Directus and Listmonk using Flows

I want a manual trigger that when clicked will create a Campaign in my Listmonk instance, but only if the item is published.

Step 1: Create a Collection

Create a Collection called "Post" with fields:

  • uuid (string, system field added during creation; this is the ID specifier)
  • status (string, system field added during creation)
  • title (string)
  • content (Markdown)

Step 2: Create a Flow

Name: Create Campaign `Trigger: Manual Collections: Post Location: Item Page Only Asynchronous: (not enabled)

Step 3: Read Data Operation

This step is to retrieve the item so the data can be used within the Flow. This is why its the first step.

Name: Get Item Key: get_item Operation: Get Data Permissions: From Trigger Collection: Post IDs: (empty) Query:

{
    "filter": {
        "uuid": {
            "_eq": "{{ $trigger.body.keys[0] }}"
        }
    }
}

Emit Events: (not enabled)

Step 4: Run Script Operation to check if published

This step is to ensure the flow exits if the content is not in a published state.

Name: Is Published Key: is_published Operation: Run Script Permissions: From Trigger Code:

/* https://github.com/directus/directus/issues/14571#issuecomment-1315513057 */
module.exports = async function(data) {
    if (typeof data.$last[0].status !== 'undefined' && data.$last[0].status === 'published') {
        return {...data}
    }
    
    throw new Error('Status is not published.');
}

Step 5: Run Script Operation to prepare request body

This step is necessary to ensure the request body is formatted correctly. (You could simply do this in the request step, but when I did that the request body was malformed. I presume this is because doing it in the request step is embedding a JSON string within another JSON string as opposed to this approach which takes an object and serializes it into JSON, which is probably safer all around.)

Name: Prepare Body Key: prepare_body Operation: Run Script Permissions: From Trigger Code:

module.exports = async function(data) {
    let body = {};
    try {
        body = {
            "lists": [
                123
            ],
            "type": "regular",
            "name": `Directus: ${data.get_item[0].title}`,
            "subject": data.get_item[0].title,
            "body": data.get_item[0].content,
            "status": "draft",
            "content_type": "markdown",
            "messenger": "email"
        };
    } catch (e) {
        body = {
            "error": {
                "message": e.message,
            	"stack": e.stack
            }
        };
    }
    
	return body;
}

Step 6: Run Script Operation to check if request body is OK

This step is to ensure the flow exits if preparing the request body errored.

Name: Is Body OK Key: is_body_ok Operation: Run Script Permissions: From Trigger Code:

module.exports = async function(data) {
    if (typeof data.prepare_body.error !== 'undefined') {
        throw new Error('There was an error in body prepare');
    }
}

Step 7: Webhook / Request URL to create the campaign in Listmonk

This step is to make the HTTP request to create a campaign in Listmonk using the processed request body.

Name: Create Campaign Key: create_campaign Operation: Webhook / Request URL Method: POST URL: https://listmonk.example.com/api/campaigns Headers:

Authorization:  Basic yourbasicauthvalue

Request Body:

{{ prepare_body }}

Bonus: Send notification on failure

At each step, you can send a notification on failure by creating an operation and connecting it to the failure on a step. I used an email notification.

Using a Send Notification operation with User value of {{ $accountability.user }} (dont forget to hit enter!) will create a notification for the user who triggered the Flow, but there is a bug preventing the user from reading it directus/directus#13727.

Name: Send Notification Key: notification_prepare_body_error Operation: Send Email To: [email protected] (don't forget to hit enter to ensure the value is saved!) Subject: Create Campaign: Body prepare error Type: Markdown Body:

Body prepare error, could not create campaign.

The following should contain an error message:

```
{{ prepare_body }}
```

Another tip is that on the failure to send to API you can include the request information in the email (I couldn't figure out how to get the request response):

API errored, so could not create campaign because: {{ create_campaign.message }}.

Request:

```
{{ create_campaign.config.method }} {{ create_campaign.config.url }}

{{ create_campaign.config.data }}
```

Original source: directus/directus#16674 (comment)

Edit 12/2 9:20p ET - Fixed markup a bit, noted in app notification in Bonus section.

@w0kyj
Copy link

w0kyj commented Dec 2, 2022

Nice use case and flow.
In case it helps --> {{$accountability.user}} is the user_id of the person that triggered the flow :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment