import * as express from 'express' ; import { Express , Request , Response } from 'express' ; import * as bodyParser from 'body-parser' ; export const app = express ( ) ; app . use ( bodyParser . urlencoded ( { extended : true } ) ) ; import * as Slack from '@slack/web-api' ; const { verifyRequestSignature } = require ( '@slack/events-api/dist/' ) ; import * as SlackWebApi from 'seratch-slack-types/web-api' ; import * as SlackEventsApi from 'seratch-slack-types/events-api' ; import * as SlackAppToolkit from 'seratch-slack-app-toolkit' ; type ReactionAdded = SlackEventsApi . ReactionAddedPayload ; 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 ( ) ; import { Translate as GoogleTranslateApi } from '@google-cloud/translate' ; const googleApiCredentials = { projectId : process . env . GOOGLE_PROJECT_ID , key : process . env . GOOGLE_KEY } ; const googleApi = new GoogleTranslateApi ( googleApiCredentials ) ; const debug = true ; import { langcode } from './langcode' ; slackEventsOperator . add ( 'reaction_added' , new Op < ReactionAdded > ( function ( args ) { 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 = 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 = langcode . All [ country ] ; if ( ! lang ) { return res . status ( 200 ) ; } if ( debug ) { console . log ( `Detected country: ${ country }, lang: ${ lang } from reaction: ${ reactionName }` ) ; } const channelId = payload . event . item . channel ; const messageTs = payload . event . item . ts ; slackApi . conversations . replies ( { channel : channelId , ts : messageTs , inclusive : true } ) . then ( ( repliesRes ) => { 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 = 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 ) => { 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 ( '/slack/events' , function ( req , res ) { if ( debug ) { console . log ( req . body ) ; } const requestBody = req . body . toString ( ) ; try { verifyRequestSignature ( { signingSecret : process . env . SLACK_SIGNING_SECRET , requestSignature : req . get ( 'X-Slack-Signature' ) , requestTimestamp : req . get ( 'X-Slack-Request-Timestamp' ) , body : requestBody } ) ; } catch ( verificationErr ) { return res . status ( 401 ) . json ( { ok : false } ) ; } slackEventsOperator . dispatch ( JSON . parse ( requestBody ) , req , res ) ; } ) ;