@urban-bot/slack
Version:
Create Slack chatbot with urban-bot
367 lines • 15 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UrbanBotSlack = void 0;
/* eslint-disable @typescript-eslint/camelcase */
const events_api_1 = require("@slack/events-api");
const interactive_messages_1 = require("@slack/interactive-messages");
const web_api_1 = require("@slack/web-api");
const body_parser_1 = __importDefault(require("body-parser"));
const format_1 = require("./format");
const utils_1 = require("./utils");
class UrbanBotSlack {
constructor(options) {
this.options = options;
this.type = UrbanBotSlack.TYPE;
this.defaultParseMode = 'markdown';
this.commandPrefix = '/';
this.handleAction = (ctx) => {
if (ctx.actions.length > 0 && ctx.actions[0].type === 'button') {
if (ctx.actions[0].value === undefined) {
return;
}
const adaptedCtx = {
type: 'action',
chat: {
id: ctx.channel.id,
},
from: {
id: ctx.user.id,
username: ctx.user.username,
},
payload: {
actionId: ctx.actions[0].value,
},
nativeEvent: {
type: UrbanBotSlack.TYPE,
payload: ctx,
},
};
this.processUpdate(adaptedCtx);
}
};
this.handleMessage = (ctx) => {
if (ctx.bot_id !== undefined) {
return;
}
const common = {
chat: {
id: ctx.channel,
type: ctx.channel_type,
},
from: {
id: ctx.user,
},
nativeEvent: {
type: UrbanBotSlack.TYPE,
payload: ctx,
},
};
if (ctx.files !== undefined) {
const files = ctx.files.map((file) => {
return {
mimeType: file.mimetype,
width: file.original_w,
height: file.original_h,
id: file.id,
size: file.size,
name: file.name,
};
});
const fileEvent = {
...common,
payload: {
messageId: ctx.client_msg_id,
text: ctx.text,
files,
},
};
const isAllImages = files.every(({ mimeType }) => (0, utils_1.getTypeByMimeType)(mimeType) === 'image');
const isAllVideo = files.every(({ mimeType }) => (0, utils_1.getTypeByMimeType)(mimeType) === 'video');
const isAllAudio = files.every(({ mimeType }) => (0, utils_1.getTypeByMimeType)(mimeType) === 'audio');
if (isAllImages) {
this.processUpdate({
type: 'image',
...fileEvent,
});
}
else if (isAllVideo) {
this.processUpdate({
type: 'video',
...fileEvent,
});
}
else if (isAllAudio) {
this.processUpdate({
type: 'audio',
...fileEvent,
});
}
else {
this.processUpdate({
...fileEvent,
type: 'file',
});
}
return;
}
if (ctx.subtype) {
return;
}
const textEvent = {
...common,
type: 'text',
payload: {
messageId: ctx.client_msg_id,
text: ctx.text,
},
};
return this.processUpdate(textEvent);
};
this.handleCommand = (req, res) => {
const { channel_id, command, text, user_id, user_name, channel_name } = req.body;
const ctx = {
type: 'command',
chat: {
id: channel_id,
title: channel_name,
username: user_name,
},
payload: {
command,
// command has no message_id
messageId: command,
argument: text,
},
from: {
id: user_id,
username: user_name,
},
nativeEvent: {
type: UrbanBotSlack.TYPE,
payload: req.body,
},
};
this.processUpdate(ctx);
res.sendStatus(200);
};
this.client = new web_api_1.WebClient(options.token);
this.events = (0, events_api_1.createEventAdapter)(options.signingSecret);
this.interactions = (0, interactive_messages_1.createMessageAdapter)(options.signingSecret);
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore this.events extends EventEmitter
this.events.on('error', console.error);
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore this.events extends EventEmitter
this.events.on('message', this.handleMessage);
this.interactions.action(/.*/, this.handleAction);
}
initializeServer(expressApp) {
var _a;
const pathnamePrefix = (_a = this.options.pathnamePrefix) !== null && _a !== void 0 ? _a : '';
expressApp.use(`${pathnamePrefix}/slack/events`, this.events.expressMiddleware());
expressApp.use(`${pathnamePrefix}/slack/actions`, this.interactions.expressMiddleware());
expressApp.post(`${pathnamePrefix}/slack/commands`, body_parser_1.default.urlencoded({ extended: false }), this.handleCommand);
}
processUpdate(_event) {
throw new Error('this method must be overridden');
}
async sendMessage(message) {
var _a, _b, _c;
switch (message.nodeName) {
case 'urban-text': {
return this.client.chat.postMessage({
channel: message.chat.id,
text: message.data.text,
});
}
case 'urban-img': {
if (typeof message.data.file !== 'string') {
if (message.data.buttons !== undefined) {
console.error("@urban-bot/slack doesn't support buttons prop with file from file system. Change file to url or send buttons separately.");
}
return this.client.files.upload({
file: message.data.file,
channels: message.chat.id,
filename: message.data.name,
title: message.data.title,
});
}
const blocks = [
{
type: 'image',
title: {
type: 'plain_text',
text: (_a = message.data.title) !== null && _a !== void 0 ? _a : '',
emoji: true,
},
image_url: message.data.file,
alt_text: (_b = message.data.alt) !== null && _b !== void 0 ? _b : 'image',
},
];
if (message.data.buttons !== undefined) {
blocks.push({
type: 'actions',
elements: (0, format_1.formatButtons)(message.data.buttons),
});
}
return this.client.chat.postMessage({
channel: message.chat.id,
blocks,
text: (_c = message.data.title) !== null && _c !== void 0 ? _c : '',
});
}
case 'urban-audio': {
if (typeof message.data.file === 'string') {
throw new Error("@urban-bot/slack doesn't support audio file as string");
}
return this.client.files.upload({
file: message.data.file,
channels: message.chat.id,
filename: message.data.name,
title: message.data.title,
});
}
case 'urban-video': {
if (typeof message.data.file === 'string') {
throw new Error("@urban-bot/slack doesn't support video file as string");
}
return this.client.files.upload({
file: message.data.file,
channels: message.chat.id,
filename: message.data.name,
title: message.data.title,
});
}
case 'urban-file': {
if (typeof message.data.file === 'string') {
throw new Error("@urban-bot/slack doesn't support file as string");
}
return this.client.files.upload({
file: message.data.file,
filename: message.data.name,
channels: message.chat.id,
title: message.data.title,
});
}
case 'urban-animation': {
if (typeof message.data.file === 'string') {
throw new Error("@urban-bot/slack doesn't support animation file as string");
}
return this.client.files.upload({
file: message.data.file,
filename: message.data.name,
channels: message.chat.id,
title: message.data.title,
});
}
case 'urban-buttons': {
const elements = (0, format_1.formatButtons)(message.data.buttons);
const blocks = [];
if (message.data.title !== undefined) {
blocks.push((0, format_1.formatTitle)(message.data.title));
}
blocks.push({
type: 'actions',
elements,
});
return this.client.chat.postMessage({
channel: message.chat.id,
blocks,
text: message.data.title,
});
}
case 'urban-contact': {
const { firstName, lastName, username, phoneNumber } = message.data;
return this.client.chat.postMessage({
channel: message.chat.id,
text: (0, format_1.withRightSpaceIfExist)(firstName) +
(0, format_1.withRightSpaceIfExist)(lastName) +
'\n' +
(0, format_1.withRightSpaceIfExist)(username) +
'\n' +
(0, format_1.withRightSpaceIfExist)(String(phoneNumber)),
});
}
default: {
throw new Error(`Tag '${
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message.nodeName}' is not supported. Please don't use it with slack bot or add this logic to @urban-bot/slack.`);
}
}
}
async updateMessage(message) {
var _a, _b, _c;
switch (message.nodeName) {
case 'urban-text': {
this.client.chat.update({
channel: message.meta.channel,
ts: message.meta.ts,
text: message.data.text,
});
break;
}
case 'urban-img': {
if (typeof message.data.file !== 'string') {
throw new Error('Provide urban-img file as string if you want to edit the image message. @urban-bot/slack');
}
const blocks = [
{
type: 'image',
title: {
type: 'plain_text',
text: (_a = message.data.title) !== null && _a !== void 0 ? _a : '',
emoji: true,
},
image_url: message.data.file,
alt_text: (_b = message.data.alt) !== null && _b !== void 0 ? _b : '',
},
];
if (message.data.buttons !== undefined) {
blocks.push({
type: 'actions',
elements: (0, format_1.formatButtons)(message.data.buttons),
});
}
this.client.chat.update({
channel: message.meta.channel,
ts: message.meta.ts,
blocks,
text: (_c = message.data.title) !== null && _c !== void 0 ? _c : '', // TODO: investigate me
});
break;
}
case 'urban-buttons': {
const elements = (0, format_1.formatButtons)(message.data.buttons);
const blocks = [];
if (message.data.title !== undefined) {
blocks.push((0, format_1.formatTitle)(message.data.title));
}
blocks.push({
type: 'actions',
elements,
});
this.client.chat.update({
channel: message.meta.channel,
ts: message.meta.ts,
blocks,
text: message.data.title,
});
break;
}
default: {
throw new Error(`Tag '${
// eslint-disable-next-line @typescript-eslint/no-explicit-any
message.nodeName}' is not supported to update the message for @urban-bot/slack. You could send a new message every time for this tag.`);
}
}
}
deleteMessage(message) {
this.client.chat.delete({ channel: message.meta.channel, ts: message.meta.ts });
}
}
exports.UrbanBotSlack = UrbanBotSlack;
UrbanBotSlack.TYPE = 'SLACK';
//# sourceMappingURL=UrbanBotSlack.js.map
;