All files / controllers slack.js

14.29% Statements 9/63
0% Branches 0/18
7.14% Functions 1/14
15.79% Lines 9/57

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 9615x     15x 15x 15x 15x   15x 15x   15x                                                                                                                                                                   15x    
module.exports = function(crowi, app) {
  'use strict'
 
  const debug = require('debug')('crowi:routes:slack')
  const url = require('url')
  const { slack } = crowi
  const Page = crowi.model('Page')
 
  const actions = {}
  const api = (actions.api = {})
 
  api.handleEvent = function(req, res) {
    if (req.body.type != null && req.body.type == 'url_verification') {
      verifyChallenge(req, res)
      return
    }
 
    const { type } = req.body.event
    switch (type) {
      case 'link_shared':
        unfurl(req, res)
        break
      default:
        break
    }
  }
 
  function verifyChallenge(req, res) {
    res.send(req.body.challenge)
  }
 
  function parseLink(link) {
    const { pathname, query } = url.parse(link, true)
    const pagePath = decodeURIComponent(pathname) || null
    const revisionId = query.revision || null
    return { pagePath, revisionId }
  }
 
  function parseLinks(links) {
    const results = {}
    links.forEach(({ url }) => {
      const { pagePath, revisionId } = parseLink(url)
      results[pagePath] = { url, pagePath, revisionId }
    })
    return results
  }
 
  async function unfurl(req, res) {
    const { event } = req.body
    const { links, channel, message_ts: ts } = event
    const results = parseLinks(links)
    const keys = Object.keys(results)
 
    const isObjectId = key => new RegExp('/([0-9a-fA-F]{24})').test(key)
    const extractObjectId = key => (isObjectId(key) ? RegExp.$1 : null)
    const isCreatablePath = key => Page.isCreatableName(key)
 
    const pageIds = keys.map(extractObjectId).filter(key => key !== null)
    const pagePaths = keys.filter(isCreatablePath)
 
    const getResult = ({ _id, path }) => (_id && results[`/${_id}`]) || (path && results[path])
 
    try {
      const pagesById = await Page.findUnfurlablePagesByIds(pageIds)
      const pagesByPaths = await Page.findUnfurlablePagesByPaths(pagePaths)
      const pages = [...pagesById, ...pagesByPaths]
 
      if (pages.length === 0) {
        const pageNotFoundError = new Error('Page Not Found')
        pageNotFoundError.name = 'Crowi:Page:NotFound'
        throw pageNotFoundError
      }
 
      const revisionIds = pages.map(page => getResult(page).revisionId)
      const pagesData = await Page.populatePagesRevision(pages, revisionIds)
 
      const unfurls = {}
      pagesData.forEach(page => {
        const { url } = getResult(page)
        const { path: title } = page
        const text = slack.prepareAttachmentTextForCreate(page)
        unfurls[url] = { title, text }
      })
 
      await slack.unfurl(channel, unfurls, ts)
 
      res.sendStatus(200)
    } catch (err) {
      debug('Failed to unfurl link:', err)
      res.sendStatus(404)
    }
  }
 
  return actions
}