Skip to content

Instantly share code, notes, and snippets.

@uiur
Created April 18, 2019 00:24
Show Gist options
  • Save uiur/50ba5729cf8e5920e5fbb385392a6543 to your computer and use it in GitHub Desktop.
Save uiur/50ba5729cf8e5920e5fbb385392a6543 to your computer and use it in GitHub Desktop.

Revisions

  1. uiur created this gist Apr 18, 2019.
    154 changes: 154 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,154 @@
    const axios = require('axios')
    const decode = require('decode-html')
    const CHANNEL = '#dev'
    const ISSUE_REPO = 'foo/bar'

    exports.otochan = (req, res) => {
    console.log('Received request:', req.body)

    // slack challenge
    if (req.body.challenge) {
    res.send(req.body.challenge)
    return
    }

    // slack event
    if (req.body.event) {
    handleSlack(req, res)
    return
    }
    }

    function handleSlack(req, res) {
    const event = req.body.event

    if (event.type === 'reaction_added') {
    if (event.reaction === 'イシュー') {
    handleReaction(event)
    .then(() => {
    res.send('ok')
    })
    .catch(err => {
    console.error(err)
    res.status(500).send(err.message)
    })

    return
    }
    }

    res.send('ok: no matched handler')
    }

    async function handleReaction(event) {
    const { channel, ts } = event.item
    const { messages } = await getMessages(channel, ts, 10)
    const message = messages[0]
    const permalink = await getPermalink(channel, message.ts)

    const repo = ISSUE_REPO

    const title = decode(message.text)
    const historyText = messages.reverse()
    .filter(m => m.type === 'message')
    .map(m => decode(m.text))
    .join("\n")

    const body = `${permalink}\n` + '```\n' + historyText + '\n```'

    const issues = await getLatestIssues(repo)
    const foundIssue = issues.find((issue) => {
    return issue.title === title
    })

    if (foundIssue) {
    return
    }

    const issue = await createIssue(repo, { title: title, body: body })
    const slackMessage = `<@${event.user}> ${issue.html_url}`
    await postMessage(channel, slackMessage)
    }

    function apiHeaders(token) {
    return {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
    }
    }

    async function getMessages (channel, ts, count = 1) {
    const token = process.env.SLACK_USER_TOKEN

    const res = await axios.get('https://slack.com/api/channels.history', {
    params: {
    channel: channel,
    latest: ts,
    count: count,
    inclusive: true,
    token: token
    }
    })

    return res.data
    }

    async function postMessage (channel, text) {
    const token = process.env.SLACK_TOKEN

    await axios.post('https://slack.com/api/chat.postMessage', {
    channel: channel,
    text: text,
    icon_emoji: ':chicken:'
    }, {
    headers: apiHeaders(token)
    })
    }

    async function getPermalink (channel, ts) {
    const res = await axios.get('https://slack.com/api/chat.getPermalink', {
    params: {
    channel: channel,
    message_ts: ts,
    token: process.env.SLACK_TOKEN
    }
    })

    return res.data.permalink
    }

    function githubApiHeaders() {
    return {
    ...apiHeaders(process.env.GITHUB_TOKEN),
    'Accept': 'application/vnd.github.v3+json'
    }
    }

    async function createIssue(repo, params) {
    const res = await axios.post(`https://api.github.com/repos/${repo}/issues`, params, {
    headers: githubApiHeaders()
    })

    if (res.status > 300) {
    console.error(res.data)
    throw new Error(res.data.message)
    }

    return res.data
    }

    async function getLatestIssues(repo) {
    const res = await axios.get(`https://api.github.com/repos/${repo}/issues`, {
    params: {
    state: 'all'
    },
    headers: githubApiHeaders()
    })

    if (res.status > 300) {
    console.error(res.data)
    throw new Error(res.data.message)
    }

    return res.data
    }