Knowledgeの更新通知を、GAS経由で、Slackで受け取る方法


私は，QiitaのクローンであるOSS、Knowledge（以下URL参考）を社内運用している。
https://information-knowledge.support-project.org/ja/

Knowledgeには記事投稿やコメントをTriggerとしてWebhookを投げる機能が備わっているが、KnowledgeのJSONフォーマットがSlackのIncomingWebhookで受け付けるJSONフォーマットと一致していないため、Slackへ変更通知を出すには変換をする中継地点が必要である。

本記事では、GoogleAppsScript(GAS)を中継地点として利用して、Knowledge更新通知をSlackに投稿する方法を紹介する。

## Knowledgeの設定
Webhookの設定をするだけ．
宛先URLはGASをWebアプリとして公開しているURL

## Slackの設定
IncomingWebhookで，通知受取用のエンドポイントURLを設定しておく．
このURLをGASから叩く

## GAS
以下の点を考慮してスクリプトをコーディングした

- SlackのIncomingWebhookのURLはスクリプトプロパティに格納した
    - →Qiitaにコードをコピペする際に、気にする必要がなくて楽だった
- 非公開の記事については通知を出したくない
    - →public_flag=2（公開範囲保護設定）の記事のみを対象とした．
- コメントや記事の内容は知りたいけど，長いポストはしたくない
    - →最初の100文字だけSlack通知に含めるようにした．
- せっかくなので，Attachmentsで少し目立つ通知になるように工夫したい．
    - →コメント・新規投稿・過去投稿の更新，の３つで色分け
- ついでに，スプレッドシートに投稿記録を貯めたい．
    - →誰が，どのくらい投稿しているか，等を見える化出来たら良いなと考え中．．．


### doPost
KnowledgeのWebhookを受け取って実行される関数

```js
function doPost (e) {
  
  // << PostData の処理 >>
  var org_post = e.postData.contents;
  var contents = JSON.parse(org_post);
  var knowledge = contents;
  var sheet = sheet_knowledge;
  
  // << 分岐 >>
  // <1.comment>
  if (contents.hasOwnProperty("comment")){
    var sheet = sheet_comment;
    recordComment(contents)
    // 保護：Slack通知
    if (contents.knowledge.public_flag == 2){
      var type = "[Posted new comment]";   //通知の種類
      var knowledge = contents.knowledge; 　
      var comment = contents.comment;　　　　　　　　　　//コメント
      var user = contents.insert_user;    //投稿者
      var date = contents.insert_date;    //日時
    // 非公開の記事へのコメント：Slack通知しない
    } else {
      checkSuccess(sheet,"Not notified")
      return;
    }
  
  // <2.knowledge-update>
  }else if(knowledge.public_flag == 2 && knowledge.status == "updated"){
  //}else if(knowledge.status == "updated"){ // Test用
    recordKnowledge(contents)
    var type = "[Updated knowledge]"  //通知の種類
    var user = knowledge.update_user; //投稿者
    var date = knowledge.update_date; //日時
  
  // <3.knowledge-created>
  }else if(knowledge.public_flag == 2 && knowledge.status == "created"){
  //}else if(knowledge.status == "created"){ // Test用
    recordKnowledge(contents)
    var type = "[Created new knowledge]"; //通知の種類
    var user = knowledge.insert_user;    //投稿者
    var date = knowledge.insert_date;    //日時
  
  // <4.others>
  }else{
    recordKnowledge(contents)
    checkSuccess(sheet,"Not notified")
    return;
  }
  var content = knowledge.content; // Knowledgeの本文
  var title = knowledge.title;     // Knowledgeのタイトル
  var link = knowledge.link;       // Knowledgeへのリンク

  
  // << POST data の準備 >>
  var attachments = [
    {
      "callback_id": "knowledge",
      "fallback": "Notification from Knowledge",
      "attachment_type": "default",
      "title": title,//インデント内に表示されるタイトル
      "title_link": link,
      "color":"good",
      "fields": [
        {
          "title": "Date",
          "value": date,
          "short": "true"
        },
        {
          "title": "User",
          "value": user,
          "short": "true"
        }
      ]
    }
  ]
  // Comment/Content追加
  if (contents.hasOwnProperty("comment")) {
    attachments[0].fields[3] = {
      "title": "Comment",
      "value": comment.slice(0,100).replace(/\r\n|\r|\n/g, '\n')+" ................."
    }
    attachments[0].color = "warning";
  } else {
    attachments[0].fields[3] = {
      "title": "Knowledge",
      // 100文字に限定
      "value": content.slice(0,100).replace(/\r\n|\r|\n/g, '\n')+" ................."
    }
    if (knowledge.status == "updated") {
      attachments[0].color = "bad";
    }
  }


  // << Slack >>
  var payload = {
    "attachments": attachments,
    "text": type
  }
  
  // URL
  var properties = PropertiesService.getScriptProperties();
  var url = properties.getProperty("url_knowledge"); // 本番用：#knowledge
  //var url = properties.getProperty("url_test"); // Test用：#knowledge_test

  var option = {
    "method": "POST",
    "payload": JSON.stringify(payload),
    "contentType": "application/json"
  }
  // Slack Incoming WebhookへPost
  UrlFetchApp.fetch(url, option)
  // Spreadsheetに保存
  checkSuccess(sheet,"Success")
}
```