import * as express from 'express';
import { Express, Request, Response } from 'express';
import * as bodyParser from 'body-parser';
import * as Slack from '@slack/web-api';
import * as SlackWebApi from 'seratch-slack-types/web-api';
type ConversationsReplies = SlackWebApi.ConversationsRepliesResponse;
type ChatPostMessage = SlackWebApi.ChatPostMessageResponse;
import * as SlackEventsApi from 'seratch-slack-types/events-api';
type ReactionAdded = SlackEventsApi.ReactionAddedPayload;
import * as SlackAppToolkit from 'seratch-slack-app-toolkit';
const Op = SlackAppToolkit.EventsApi.EventsApiOperation;
type OpArgs<A> = SlackAppToolkit.EventsApi.EventsApiOperationArgs<A>;
export const slackApi = new Slack.WebClient(process.env.SLACK_API_TOKEN);
const slackEventsOperator = new SlackAppToolkit.EventsApi.EventsApiOperator();
export const app: Express = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
import { Translate as GoogleTranslateApi } from '@google-cloud/translate';
const googleApiCredentials = {
projectId: process.env.GOOGLE_PROJECT_ID,
key: process.env.GOOGLE_KEY
}
const googleApi: GoogleTranslateApi = new GoogleTranslateApi(googleApiCredentials);
const debug: boolean = true;
import { langcode } from './langcode';
slackEventsOperator.add('reaction_added', new Op<ReactionAdded>(
function (args: OpArgs<ReactionAdded>) {
const payload = args.payload;
const res = args.response;
if (debug) {
console.log(payload.event);
}
if (payload.event.item.type !== 'message') {
return res.status(200);
}
const reactionName = payload.event.reaction;
let country: string = null;
if (reactionName.match(/flag-/)) {
country = reactionName.match(/(?!flag-\b)\b\w+/)[0];
} else {
const flags = Object.keys(langcode.All);
if (flags.includes(reactionName)) {
country = reactionName;
} else {
return res.status(200);
}
}
const lang: string = langcode.All[country];
if (!lang) {
return res.status(200);
}
if (debug) {
console.log(`Detected country: ${country}, lang: ${lang} from reaction: ${reactionName}`);
}
const channelId: string = payload.event.item.channel;
const messageTs: string = payload.event.item.ts;
slackApi.conversations.replies({
channel: channelId,
ts: messageTs,
inclusive: true
})
.then((repliesRes: ConversationsReplies) => {
if (debug) {
console.log(repliesRes.messages);
}
const messages = repliesRes.messages;
const message = messages[0];
if (message.text) {
googleApi.translate(message.text, lang)
.then((array) => {
const [translatedText, googleApiRes] = array;
if (debug) {
console.log(`Response from Google Translate API: ${JSON.stringify(googleApiRes)}`);
}
let alreadyPosted: boolean = false;
messages.forEach(messageInTheThread => {
if (!alreadyPosted && messageInTheThread.text && messageInTheThread.text === translatedText) {
alreadyPosted = true;
}
});
if (alreadyPosted) {
return;
}
slackApi.chat.postMessage({
channel: channelId,
text: translatedText,
as_user: false,
username: "Reacjilator Bot",
thread_ts: message.thread_ts ? message.thread_ts : message.ts
})
.then((postRes: ChatPostMessage) => {
if (postRes.ok) {
console.log(`Successfully posted a translated message (ts: ${postRes.ts})`);
} else {
if (debug) {
console.error(postRes);
}
console.error(`Got an error from chat.postMessage (error: ${postRes.error})`);
}
})
.catch(reason => {
console.error(`Failed to post a message because ${reason}`);
})
})
.catch(reason => {
console.error(`Failed to call Google Translate API because ${reason}`);
})
} else {
console.log(`Skipped the message because it doesn't have text property (ts: ${message.ts})`);
}
})
.catch(reason => {
console.error(`Failed to fetch message replies because ${reason}`);
});
return res.status(200).json({ ok: true });
}
));
app.post('/events', function (req: Request, res: Response) {
slackEventsOperator.dispatch(req.body, req, res);
});