ベストクラウドさんの スラック+ガスログ保存のコードを解読する
30431 ワード
https://best-cloud.jp/slack-message-log-auto-save-gas/
ベストクラウドさんの スラックの全チャンネルのメッセージを
ガスでスプレッドシートに全て保存する記事を読んで試した
しかし、肝心のコードでは
とあり、わずかなコメントだけだったので解釈してみる
最初に
この関数は
スラックロックアピワントークンに xoxp‐1234などのトークン
フォールドラントIDに グーグルドライブのフォルダ ID
リトルビッグプラネットに -1
これを初手で入れている
これはわかりやすい.
フォールドラントIDと アピワントークンと言う定数に入れ直す.
そしてなかった場合のエラー処理を書く.
先ほど ガスのプロパティに入れたものを出して定数に入れるだけなので
ここもわかりやすい.
作者の自作メソッドの フォルダで、フォルダがない場合は作成する
スプレッドシートがない場合は作成する
この requestMemberList と requestChannelInfo も
後述の著者の自作メソッドなのでかなり難しい.
スプレッドシートの最後のタイムスタンプ?を取得し
スラックからチャンネルのメッセージをチャンネルID ?とそのタイムスタンプで取得し
スプレッドシートのコントローラに渡す
タイムスタンプが 1であればチャンネルの最初で終わる?
チャンネルの中のそのプロパティを出力???ここは意味がわからない
そしてここで 東京工業大学と言う APIリクエストの
先ほどの URLと 今のヘッダーをオプションとして渡し、レスポンスを受け取る
そのレスポンスを JSONにパースしてエラー処理する
ガスの スラックAPIの利用ではしっかりと APIリクエストのラッパーを書いてその呼び出しにも一つ一つロジックを書いていかないと使えないことがわかった
ベストクラウドさんの スラックの全チャンネルのメッセージを
ガスでスプレッドシートに全て保存する記事を読んで試した
しかし、肝心のコードでは
以下のテキストを最初から最後まで全てコピーしてください。
とあり、わずかなコメントだけだったので解釈してみる
setpropertyで スラックラグアピアントトケや フォールドラントIDをセットする
最初に
SerPropoerties()
をしているこの関数は
function SetProperties() {
PropertiesService.getScriptProperties().setProperty(
'slack_api_token',
'xoxp-111-222-333-444'
);
PropertiesService.getScriptProperties().setProperty(
'folder_id', '123ef'
);
PropertiesService.getScriptProperties().setProperty(
'last_channel_no', -1
);
}
ガスの内部プロパティ?に埋め込む setpropertyメソッドを使ってスラックロックアピワントークンに xoxp‐1234などのトークン
フォールドラントIDに グーグルドライブのフォルダ ID
リトルビッグプラネットに -1
これを初手で入れている
これはわかりやすい.
getpropertyで スラックロックアピワントークン や フォールドラントIDでデータを取得して定数に入れる
const FOLDER_ID = PropertiesService.getScriptProperties().getProperty(
'folder_id'
);
if (!FOLDER_ID) {
throw 'You should set "folder_id" property from [File] > [Project properties] > [Script properties]';
}
const API_TOKEN = PropertiesService.getScriptProperties().getProperty(
'slack_api_token'
);
if (!API_TOKEN) {
throw 'You should set "slack_api_token" property from [File] > [Project properties] > [Script properties]';
}
先ほど スラックロックアピワントークンや フォールドラントIDにいれたトークンとフォルダIDをフォールドラントIDと アピワントークンと言う定数に入れ直す.
そしてなかった場合のエラー処理を書く.
先ほど ガスのプロパティに入れたものを出して定数に入れるだけなので
ここもわかりやすい.
グーグルドライブのフォルダ、シート、シートへのコントローラを作成する
let token = API_TOKEN
アピワントークンを今度は小文字の変数に入れるなぜここでコピーしているかは不明.let folder = FindOrCreateFolder(
DriveApp.getFolderById(FOLDER_ID), FOLDER_NAME
);
先ほどの フォールドラントIDと省略した フォールド名の文字列で作者の自作メソッドの フォルダで、フォルダがない場合は作成する
let ss = FindOrCreateSpreadsheet(folder, SpreadSheetName);
中でも同じように、 フォルダとスプレッドシート名からスプレッドシートを探してスプレッドシートがない場合は作成する
let ssCtrl = new SpreadsheetController(ss, folder);
そしてそのスプレッドシートのコントローラーを作成するスラックへのアクセサを作成して
// Slack へのアクセサ
var SlackAccessor = (function () {
function SlackAccessor(apiToken) {
this.APIToken = apiToken;
}
これは 156行目にあった作者の自作クラスlet slack = new SlackAccessor(API_TOKEN);
同じように スラックのアクセサを作る// メンバーリスト取得
const memberList = slack.requestMemberList();
// チャンネル情報取得
const channelInfo = slack.requestChannelInfo();
そこからメンバーリストとチャンネルリストを取得するこの requestMemberList と requestChannelInfo も
後述の著者の自作メソッドなのでかなり難しい.
let first_exec_in_this_channel = true;
for (let ch of channelInfo) {
console.log(ch.name)
let timestamp = ssCtrl.getLastTimestamp(ch, 0);
let messages = slack.requestMessages(ch, timestamp);
ssCtrl.saveChannelHistory(ch, messages, memberList, token);
if (timestamp == '1') {
first_exec_in_this_channel = true;
}
}
そして チャネリングを マップして コンソールにだすスプレッドシートの最後のタイムスタンプ?を取得し
スラックからチャンネルのメッセージをチャンネルID ?とそのタイムスタンプで取得し
スプレッドシートのコントローラに渡す
タイムスタンプが 1であればチャンネルの最初で終わる?
// スレッドは重い処理なので各回に1回のみ行う
const ch_num = (
parseInt(PropertiesService.getScriptProperties().getProperty(
'last_channel_no')
) + 1
) % channelInfo.length;
console.log('ch_num');
console.log(ch_num);
const ch = channelInfo[ch_num]
console.log(ch);
最後のチャンネル名、-1を入れたものに +1をしてチャンネル数で割るチャンネルの中のそのプロパティを出力???ここは意味がわからない
var p = SlackAccessor.prototype;
前述で作った スラックのアクセサからプロトタイプを取得して p に入れる// API リクエスト
p.requestAPI = function (path, params) {
if (params === void 0) { params = {}; }
var url = "https://slack.com/api/" + path + "?";
var qparams = [];
for (var k in params) {
qparams.push(encodeURIComponent(k) + "=" + encodeURIComponent(params[k]));
}
url += qparams.join('&');
var headers = {
'Authorization': 'Bearer ' + this.APIToken
};
console.log("==> GET " + url);
var options = {
'headers': headers, // 上で作成されたアクセストークンを含むヘッダ情報が入ります
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
if (data.error) {
console.log(data);
console.log(params);
throw "GET " + path + ": " + data.error;
}
return data;
};
var qparams = [];
for (var k in params) {
qparams.push(encodeURIComponent(k) + "=" + encodeURIComponent(params[k]));
}
クエリパラーメータの配列をエンコードして &= でくっつけるこのロジックはかなり便利そう.そしてここで 東京工業大学と言う APIリクエストの
https://slack.com/api/
の エンドポイント URL でのラッパーを作成する.p.requestAPI = function (path, params) {
var url = "https://slack.com/api/" + path + "?";
var qparams = [];
for (var k in params) {
qparams.push(encodeURIComponent(k) + "=" + encodeURIComponent(params[k]));
}requestAPI
url += qparams.join('&');
引数からクエリとパスを受け取り、それらをエンドポイントの基礎 URLに加算する var headers = {
'Authorization': 'Bearer ' + this.APIToken
};
var options = {
'headers': headers,
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
if (data.error) {
console.log(data);
console.log(params);
throw "GET " + path + ": " + data.error;
}
return data;
}
そして HTTPヘッダーの認証情報で 「ベアラー」+ apichenトークンをつけて先ほどの URLと 今のヘッダーをオプションとして渡し、レスポンスを受け取る
そのレスポンスを JSONにパースしてエラー処理する
// チャンネル情報取得
p.requestChannelInfo = function () {
var response = this.requestAPI('conversations.list');
response.channels.forEach(function (channel) {
console.log("channel(id:" + channel.id + ") = " + channel.name);
});
return response.channels;
};
// 特定チャンネルのメッセージ取得
p.requestMessages = function (channel, oldest) {
var _this = this;
if (oldest === void 0) { oldest = '1'; }
var messages = [];
var options = {};
options['oldest'] = oldest;
options['count'] = HISTORY_COUNT_PER_PAGE;
options['channel'] = channel.id;
var loadChannelHistory = function (oldest) {
if (oldest) {
options['oldest'] = oldest;
}
var response = _this.requestAPI('conversations.history', options);
messages = response.messages.concat(messages);
return response;
};
この APIのラッパーをチャンネル情報の取得とメッセージの取得で使用する// チャンネル情報取得
p.requestChannelInfo = function () {
var response = this.requestAPI('conversations.list');
response.channels.forEach(function (channel) {
console.log("channel(id:" + channel.id + ") = " + channel.name);
});
return response.channels;
};
// 特定チャンネルのメッセージ取得
p.requestMessages = function (channel, oldest) {
var _this = this;
if (oldest === void 0) { oldest = '1'; }
var messages = [];
var options = {};
options['oldest'] = oldest;
options['count'] = HISTORY_COUNT_PER_PAGE;
options['channel'] = channel.id;
var loadChannelHistory = function (oldest) {
if (oldest) {
options['oldest'] = oldest;
}
var response = _this.requestAPI('conversations.history', options);
messages = response.messages.concat(messages);
return response;
};
まとめ
ガスの スラックAPIの利用ではしっかりと APIリクエストのラッパーを書いてその呼び出しにも一つ一つロジックを書いていかないと使えないことがわかった
Reference
この問題について(ベストクラウドさんの スラック+ガスログ保存のコードを解読する), 我々は、より多くの情報をここで見つけました https://dev.to/kaede_io/slack-api-kara-gas-de-menbatotiyanneruwoqu-de-suru-3a5hテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol