GoogleAppsScript
gas
Slack
Knowledge

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で少し目立つ通知になるように工夫したい.
    • →コメント・新規投稿・過去投稿の更新,の3つで色分け
  • ついでに,スプレッドシートに投稿記録を貯めたい.
    • →誰が,どのくらい投稿しているか,等を見える化出来たら良いなと考え中...

doPost

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

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")
}