Skip to content

Commit

Permalink
Adding Message Metadata Support to Bolt JS (#1508)
Browse files Browse the repository at this point in the history
* adding message metadata support
* adding deleted_ts to MessageMetadataDeletedEvent
* adding missing prop deleted_ts to support message_metadata_deleted payload
* adding message metadata simple example
* bumping @slack\types in top-level package.json
  • Loading branch information
dannyhostetler authored Jul 13, 2022
1 parent 2e6e6c0 commit fef721f
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 4 deletions.
4 changes: 4 additions & 0 deletions examples/message-metadata/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# node / npm
node_modules/
package-lock.json
.env
44 changes: 44 additions & 0 deletions examples/message-metadata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Bolt for JavaScript Message Metadata

This is a quick example app to test [Message Metadata](https://api.slack.com/metadata) with Bolt for JavaScript.

Before we get started, make sure you have a development workspace where you have permissions to install apps. If you don’t have one setup, go ahead and [create one](https://slack.com/create). You also need to [create a new app](https://api.slack.com/apps?new_app=1) if you haven’t already. You will need to enable Socket Mode and generate an App Level Token.

## Install Dependencies

```
npm install
```

## Subscribe to Message Metadata events

Go to the Events Subscription page from your app configuration, and subcribe to `message_metadata_deleted`, `message_metadata_posted`, and `message_metadata_updated` bot events. Additionally, go to the App Manifest page and update the `metadata subscriptions` like the following:

```
settings:
event_subscriptions:
bot_events:
- message_metadata_deleted
- message_metadata_posted
- message_metadata_updated
metadata_subscriptions:
- app_id: YOUR_APP_ID
event_type: my_event
```

## Setup Environment Variables

This app requires you setup a few environment variables. You can find these values in your [app configuration](https://api.slack.com/apps).

```bash
export SLACK_BOT_TOKEN=YOUR_SLACK_BOT_TOKEN
export SLACK_APP_TOKEN=YOUR_SLACK_APP_TOKEN
```

## Run the App

Start the app with the following command:

```
npm start
```
51 changes: 51 additions & 0 deletions examples/message-metadata/app-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"display_information": {
"name": "Message Metadata Example"
},
"features": {
"bot_user": {
"display_name": "Message Metadata Bot",
"always_online": false
},
"slash_commands": [
{
"command": "/post",
"description": "Post Message Metadata",
"should_escape": false
}
]
},
"oauth_config": {
"redirect_urls": [
"https://localhost"
],
"scopes": {
"bot": [
"metadata.message:read",
"chat:write",
"commands"
]
}
},
"settings": {
"event_subscriptions": {
"bot_events": [
"message_metadata_deleted",
"message_metadata_posted",
"message_metadata_updated"
],
"metadata_subscriptions": [
{
"app_id": "[app id]",
"event_type": "my_event"
}
]
},
"interactivity": {
"is_enabled": true
},
"org_deploy_enabled": false,
"socket_mode_enabled": true,
"token_rotation_enabled": false
}
}
55 changes: 55 additions & 0 deletions examples/message-metadata/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const { App, LogLevel } = require('@slack/bolt');

const app = new App({
token: process.env.SLACK_BOT_TOKEN,
appToken: process.env.SLACK_APP_TOKEN,
socketMode: true,
logLevel: LogLevel.DEBUG
});

(async () => {
await app.start();
console.log('⚡️ Bolt app started');
})();


// Listen to slash command
// Post a message with Message Metadata
app.command('/post', async ({ ack, command, say }) => {
await ack();
await say({
text: "Message Metadata Posting",
metadata: {
"event_type": "my_event",
"event_payload": {
"key": "value"
}
}
});
});

app.event('message_metadata_posted', async ({ event, say }) => {
const { message_ts: thread_ts } = event;
await say({
text: "Message Metadata Posted",
blocks: [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Message Metadata Posted"
}
},
{
"type": "context",
"elements": [
{
"type": "mrkdwn",
"text": `${JSON.stringify(event.metadata)}`
}
]
}
],
thread_ts
})
});
15 changes: 15 additions & 0 deletions examples/message-metadata/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "bolt-message-metadata-example",
"version": "1.0.0",
"description": "Example app to manage Message Metadata events.",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Slack Technologies, LLC",
"license": "MIT",
"dependencies": {
"@slack/bolt": "^3.12.0"
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@slack/logger": "^3.0.0",
"@slack/oauth": "^2.5.1",
"@slack/socket-mode": "^1.3.0",
"@slack/types": "^2.4.0",
"@slack/types": "^2.7.0",
"@slack/web-api": "^6.7.1",
"@types/express": "^4.16.1",
"@types/node": ">=12",
Expand Down
5 changes: 4 additions & 1 deletion src/types/events/base-events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { View, MessageAttachment, KnownBlock, Block } from '@slack/types';
import { MessageEvent as AllMessageEvents } from './message-events';
import { MessageEvent as AllMessageEvents, MessageMetadataEvent as AllMessageMetadataEvents } from './message-events';

/**
* All known event types in Slack's Events API
Expand Down Expand Up @@ -54,6 +54,7 @@ export type SlackEvent =
| MemberJoinedChannelEvent
| MemberLeftChannelEvent
| MessageEvent
| MessageMetadataEvent
| PinAddedEvent
| PinRemovedEvent
| ReactionAddedEvent
Expand Down Expand Up @@ -585,6 +586,8 @@ export interface MemberLeftChannelEvent {

export type MessageEvent = AllMessageEvents;

export type MessageMetadataEvent = AllMessageMetadataEvents;

export interface PinnedMessageItem {
client_msg_id?: string;
type: string;
Expand Down
66 changes: 65 additions & 1 deletion src/types/events/message-events.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert } from 'chai';
import { BotMessageEvent, GenericMessageEvent, MessageEvent } from './message-events';
import { BotMessageEvent, GenericMessageEvent, MessageEvent, MessageMetadataEvent } from './message-events';

describe('Events API payload types (message events)', () => {
it('should be compatible with bot_message payload', () => {
Expand Down Expand Up @@ -182,4 +182,68 @@ describe('Events API payload types (message events)', () => {
};
assert.isNotEmpty(payload);
});
it('should be compatible with message_metadata_posted payload', () => {
const payload: MessageMetadataEvent = {
type: 'message_metadata_posted',
app_id: 'A222',
bot_id: 'B999',
user_id: 'U123',
team_id: 'T111',
channel_id: 'C111',
metadata: {
event_type: '',
event_payload: {
key: 'value',
},
},
message_ts: '',
event_ts: '',
};
assert.isNotEmpty(payload);
});
it('should be compatible with message_metadata_updated payload', () => {
const payload: MessageMetadataEvent = {
type: 'message_metadata_updated',
channel_id: 'C111',
event_ts: '',
previous_metadata: {
event_type: '',
event_payload: {
key: 'value',
},
},
app_id: 'A222',
bot_id: 'B999',
user_id: 'U123',
team_id: 'T111',
message_ts: '',
metadata: {
event_type: '',
event_payload: {
key: 'value',
},
},
};
assert.isNotEmpty(payload);
});
it('should be compatible with message_metadata_deleted payload', () => {
const payload: MessageMetadataEvent = {
type: 'message_metadata_deleted',
channel_id: 'C111',
event_ts: '',
previous_metadata: {
event_type: '',
event_payload: {
key: 'value',
},
},
app_id: 'A222',
bot_id: 'B999',
user_id: 'U123',
team_id: 'T111',
message_ts: '',
deleted_ts: ''
};
assert.isNotEmpty(payload);
});
});
45 changes: 44 additions & 1 deletion src/types/events/message-events.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MessageAttachment, KnownBlock, Block } from '@slack/types';
import { MessageAttachment, KnownBlock, Block, MessageMetadata } from '@slack/types';

export type MessageEvent =
| GenericMessageEvent
Expand All @@ -19,6 +19,11 @@ export type MessageEvent =
| MessageRepliedEvent
| ThreadBroadcastMessageEvent;

export type MessageMetadataEvent =
| MessageMetadataPostedEvent
| MessageMetadataUpdatedEvent
| MessageMetadataDeletedEvent;

export interface GenericMessageEvent {
type: 'message';
subtype: undefined;
Expand Down Expand Up @@ -281,6 +286,44 @@ export interface ThreadBroadcastMessageEvent {
channel_type: channelTypes;
}

export interface MessageMetadataPostedEvent {
type: 'message_metadata_posted';
app_id: string;
bot_id?: string;
user_id: string;
team_id: string;
channel_id: string;
metadata: MessageMetadata;
message_ts: string;
event_ts: string;
}

export interface MessageMetadataUpdatedEvent {
type: 'message_metadata_updated';
channel_id: string;
event_ts: string;
previous_metadata: MessageMetadata;
app_id: string;
bot_id?: string;
user_id: string;
team_id: string;
message_ts: string;
metadata: MessageMetadata;
}

export interface MessageMetadataDeletedEvent {
type: 'message_metadata_deleted';
channel_id: string;
event_ts: string;
previous_metadata: MessageMetadata;
app_id: string;
bot_id?: string;
user_id: string;
team_id: string;
message_ts: string;
deleted_ts: string;
}

export type channelTypes = 'channel' | 'group' | 'im' | 'mpim' | 'app_home';

interface BotProfile {
Expand Down

0 comments on commit fef721f

Please sign in to comment.