【初心者】slackで指定日付の投稿をPDFダウンロードするbotをGASで作ってみた


参考

初心者がGASでSlack Botをつくってみた

slackとgasを連携して自動応答するなどは、全て↑の手順通りに行わせていただきました

Slack BotをGASでいい感じで書くためのライブラリを作った - Qiita

また、↑こちらのライブラリを使用させていただきました


私はslack、gasの初心者です。間違っていたりもっと良いやり方などありましたら指摘いただけるとありがたいです。

botの動作

  1. slackで指定の語を(今回は「ポチ:」と)投稿する
  2. GASのdoPost関数が実行される
  3. Google Spreadsheetに、slackの指定日の投稿を書き込む
  4. Google Spreadsheetのurlに/export?format=pdfと加えたリンクをbotが返答する
  5. slackでリンクをクリックするとPDFをダウンロードできる

コード

function doPost(e) {
  var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN');
  var bot_name = "ポチ";
  var bot_icon = PropertiesService.getScriptProperties().getProperty('BOT_ICON');

  if (PropertiesService.getScriptProperties().getProperty('VERIFY_TOKEN') != e.parameter.token) {
    throw new Error("invalid token.");
  }

  var app = SlackApp.create(token);

  var message = getMessage(app, e.parameter, token)

  // slackにメッセージを送信
  return app.postMessage(
    '#' + e.parameter.channel_name,
    message, 
    {
        username: bot_name,
        icon_url: bot_icon
    }
  );
}

function getMessage(app, parameter, token) {
  var dateMatch = parameter.text.match(/\d{4}\/\d{2}\/\d{2}/)
  if (!dateMatch) {
    return "読み取れませんでした、「ポチ: XXXX/XX/XX #チャンネル名」の形式で投稿する";
  }

  var channelIdMatch = parameter.text.match(/#(.+?)\|/);
  if (!channelIdMatch) {
    return "読み取れませんでした、「ポチ: XXXX/XX/XX #チャンネル名」の形式で投稿する";
  }

  // slackのユーザー名を取得
  var userData = app.usersList().members.reduce(function(obj, cur) {
    obj[cur.id] = cur.profile.display_name
    return obj
  }, {});

  // 投稿を取得する時間の範囲をタイムスタンプで取得する
  var oldest = new Date(dateMatch[0]).getTime() / 1000
  var latest = oldest + (24 * 60 * 60)

  // 指定した日のslackの投稿を取得
  var url = "https://slack.com/api/channels.history?token="+token+"&channel="+channelIdMatch[1]+"&oldest="+oldest+"&latest="+latest;
  var response = UrlFetchApp.fetch(url);
  var json = response.getContentText();
  var postData = JSON.parse(json)
    .messages
    .reverse() // 新しい投稿順のようなので、古い順からにするために逆にする
    .map(function(item) {
      return {
        user: userData[item.user],
        text: item.text,
        date: new Date(item.ts * 1000).toLocaleString(),
      };
    });

  // シート内削除
  var Spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var Sheet = Spreadsheet.getSheetByName('シート1');
  Sheet.clear();

  // チャンネル名を取得
  var tille = parameter.text.match(/\|(.+?)>/)[1] + '_' + dateMatch[0].split('/').join('');

  // シートに入力  
  Sheet.getRange(1, 1).setValue(tille);
  postData.forEach(function(item, i) {
    Sheet.getRange(i+3+(i*3), 1).setValue(item.date);
    Sheet.getRange(i+4+(i*3), 1).setValue(item.user);

    // 本文が50文字以上の場合は改行する(※折り返しの設定をしても良さそう)
    var chars = [];
    item.text.split('\n').forEach(function(splitTxit) {
      for (var j = 0; j < splitTxit.length; j += 50) {
        chars.push(splitTxit.substring(j, j + 50));
      }
    })
    Sheet.getRange(i+5+(i*3), 1).setValue(chars.join('\n'));
  })

  // シート名がダウンロードするファイル名になるので、シート名を変更
  Spreadsheet.rename(tille)

  // PDFダウンロードのリンクを返す
  return 'ワンワン!\nご主人様完了しました。\nリンクをクリックしてPDFをダウンロードするんだワン!\n'+'https://docs.google.com/spreadsheets/d/'+Spreadsheet.getId()+'/export?format=pdf&size=A4&fzr=false&portrait=true&fitw=true&gridlines=false';
}

Google SpreadsheetをPDFダウンロードする際のパラメータは以下を参考にさせていただきました。


見ていただいてありがとうございましたm(_ _)m