ãGASãã¡ãã»ãŒãžåå/転éïŒæçš¿ïŒ/ãªã¢ã¯ã·ã§ã³ããSlack Appã®äœãæ¹
ååã®èšäºã®ç¶ãã®ãããªãã®ã«ãªããŸãã
ååã®èšäºã§ã¯ãã1.4 Botã®éçºãã2.2 Event API䜿çšã®ããã®æºåãã2.4 Appã®éçºãã®ç®æã§ãå
·äœçãªå®è£
ã«ã€ããŠã¯èšèŒããŠããªãã£ãããããã¡ãã®èšäºã§ã¯Google Apps ScriptïŒGASïŒã«ããå®è£
ã«ãã©ãŒã«ã¹ããŠæžããŠãããããšæããŸãã
ïŒã¡ãªã¿ã«ãç§ãå®è£
ãããšãã«ã¯åã®èšäºã®é çªã§ã¯ãªãã2.2â1.4ãš2.4䞊è¡ãšãã£ãæãã§å®è£
ããã®ã§ããã®èšäºã§ãå®è£
ãèããé ã«èª¬æããŸããïŒ
ã©ããªAppïŒBotïŒãäœãã®ïŒ
ãç¹å®ã®ã¯ãŒããå ¥ã£ãã¡ãã»ãŒãžãæçš¿ããããããã®ã¡ãã»ãŒãžã«ãªã¢ã¯ã·ã§ã³ãä»ããåŸããã®ã¡ãã»ãŒãžã®ãªã³ã¯ãç¹å®ã®ãã£ã³ãã«ã«æçš¿ããïŒä»¥éã転éããšåŒã¶ïŒãBotãäœããŸããããŸãæ©èœãšããŠã転éããã¡ãã»ãŒãžã®å 容ãªã©ãã¹ãã¬ããã·ãŒãã«èšé²ããŸãã
ãã®Botã®çšéãšããŠããiOSã«é¢ãã質åã§ãããšããã¯ãŒããå«ãã¡ãã»ãŒãžãæçš¿ãããã#question-iosãã£ã³ãã«ã«ããAndroidã«é¢ãã質åã§ãããšããã¯ãŒããå«ãã¡ãã»ãŒãžãæçš¿ãããã#question-androidãã£ã³ãã«ã«ããhogeïŒä»ã®æ¡ä»¶ã«åœãŠã¯ãŸããªãæååïŒã«é¢ãã質åã§ãããšããã¯ãŒããå«ãã¡ãã»ãŒãžãæçš¿ãããã#question-othersãã£ã³ãã«ã«ããããã®ã¡ãã»ãŒãžãžã®ãªã³ã¯ãæçš¿ãããšãã£ãéçšãããŸããããªã¢ã¯ã·ã§ã³ã¯è»¢éæžã¿ã®èšŒãã¹ãã¬ããã·ãŒãã®èšé²ã¯åŸã»ã©äœ¿ããããããªãã®ã§å¿µã®çºSlackããæ¶ããŠãæ®ãããã«ãããã£ãâŠãããªæ±ãã§ãã
åçŽã«èšãã°ãããŠãŒã¶ããã®ã¡ãã»ãŒãžæçš¿ãåãåãããã®ã¡ãã»ãŒãžã«ãªã¢ã¯ã·ã§ã³ãä»ããïŒãã®ã¡ãã»ãŒãžå 容ã«å¿ããŠBotãã¡ãã»ãŒãžæçš¿ãããïŒã¹ãã¬ããã·ãŒãã«ã¡ãã»ãŒãžã®æ å ±ãèšé²ããããšãããã®ã§ãã®ã§ãå¿ èŠãªéšåã ãæãåºãã°ä»ã®äœ¿çšäŸã«ãå¿çšããããããšæããŸãã
ã³ãŒãå
šäœã¯ä»¥äžã®GitHub Repositoryã§å
¬éããŠããŸãã
åºæ¬çã«ã¯ãã¡ãã®ã³ãŒããåç
§ãããã®èšäºã§ã¯ãã®ã³ãŒãã«è³ã£ãèãæ¹ãè£è¶³ãªã©ã確èªããŠããã ããã°ãšæããŸããïŒãã®èšäºã®æç« äžã«ã¯ãããŸãã³ãŒããèŒã£ãŠããŸããâŠïŒ
ãšããããšã§ã以äžã®æµãã§äœã£ãŠãããŸãã
- Events APIãBotã®æ å ±ãèšå®ããïŒåã®èšäºã®2.2ã®å 容ãå«ãïŒ
- 転ééšåãäœã
- ãªã¢ã¯ã·ã§ã³éšåãäœã
- å±¥æŽèšé²éšåãäœã
- ã¡ãã»ãŒãžæçš¿ãåãåãéšåãªã©ãäœã
â»ä»åã¯ãã¹ãã¬ããã·ãŒããäœæããŠãã¹ã¯ãªãã ãšãã£ã¿ãããGASã®ã³ãŒããæžãåæã§é²ããŸã
1. Events APIãBotã®æ å ±ãèšå®ãã
1.1 ã¹ã¯ãªããã®ããããã£èšå®
Bot User OAuth Access TokenãAppã®Verification Tokenã¯ãã³ãŒãå
ã«èŒãããšãªã³ã©ã€ã³ã§å
¬é/管çããéã«ãããããªãã§ãã
GASã®å Žåã¯ããããã£ãå€ããã¹ã¯ãªããã®ããããã£ãã«èšå®ããŸãã
以åã¯UIäžããèšå®å¯èœã ã£ãã®ã§ãããç§ããã®BotãéçºããŠããææãããã«GASã®Web UIãå€ãããã©ãããUIäžã§èšå®ã§ããªããªã£ãããã§ãããã®ãããPropertiesService.getScriptProperties().setPropertyãPropertiesService.getScriptProperties().setPropertiesãªã©ã§ã³ãŒãäžã§èšå®ããæ¹æ³ããçŸç¶èŠã€ãã£ãŠããŸããã
ããããã£èšå®çšã®é¢æ°ãäœããå
¬éãããšãã«ã¯ãã®éšåãé€å€ããã®ãè¯ãã§ããããâŠïŒïŒãã®ãããã®ç¥èŠã¯ããŸããªãã®ã§ãè¯ãæ¹æ³ãç¥ã£ãŠããæ¹ãããã°æããŠäžããïŒïŒ
ãšããããä»åã¯ä»¥äžã®ãããªæãã§ãBot User OAuth Access Token, Verification Token, ãããŠã¯ãŒã¯ã¹ããŒã¹ã®URLã®äžéšïŒxxx.slack.comã®xxxéšåïŒãèšå®ããŸããã
function setProperties() {
PropertiesService.getScriptProperties().setProperty("bot_token", "xoxb-xxx...");
PropertiesService.getScriptProperties().setProperty("verification_token", "xxx...");
PropertiesService.getScriptProperties().setProperty("workspace", "xxx...");
}
ãã¡ãããPropertiesã®ã»ãã䜿ã£ãŠãŸãšããŠèšå®ããŠãè¯ãã§ããããã®å Žåã¯å ¬åŒããã¥ã¡ã³ããåç §ããã°ã§ãããšæããŸãã
ãããŠã¡ã€ã³ãšãªã颿°ã§ããdoPost(e)ã®åºç€ã§setProperties()ãåŒã³åºãã°èšå®ã§ããŸãã
ã¡ãªã¿ã«ãæ§UIã«æ»ããŠèšå®ããå Žåã¯ããã¿ã³ïŸïŸïŸïŸïŸïŸããã®å ¥åã§èšå®ã§ããŸãã
1.2 Events APIçšã®èšè¿°
ãç¹å®ã®ã¯ãŒããå
¥ã£ãã¡ãã»ãŒãžãæçš¿ããããïœãã®éšåã®äžå°ãšããŠãdoPost(e)å
ã§Events APIã䜿ãããã®èšè¿°ãããŸãã
// Events APIããã®POSTãååŸ
// åèâhttps://api.slack.com/events-api
const json = JSON.parse(e.postData.getDataAsString());
// Events APIããã®POSTã§ããããšã確èª
if (prop.getProperty("verification_token") != json.token) {
throw new Error("invalid token.");
}
// Events APIã䜿çšããååããµãŒãã®ååšç¢ºèªïŒã¿ãããªã®ãããã®ã§ããã®ããã®èšè¿°
if (json.type == "url_verification") {
return ContentService.createTextOutput(json.challenge);
}
ã»ãŒååèšäºã®2.2ãšåãã§ããâŠ
ãã®ãããªæãã§ãPOSTãååŸãããŒã¹ããããšããããEvents APIããã®POSTã§ããããšã確èªãããã®åŸååã®url_verificationã«å¯ŸåŠããããã®èšè¿°ãããŠããŸãã
2. 転ééšåãäœã
ã³ãŒãäžã® forwardMessage 颿°ã«ãããéšåã§ãã
2.1 åºæ¬çãªã¡ãã»ãŒãžæçš¿éšåã®èšè¿°ã«ã€ããŠ
ã³ãŒãäžã«ã³ã¡ã³ãã§èšèŒããŠããéããã¡ãã»ãŒãžãéããšãã¯https://api.slack.com/methods/chat.postMessage ãåç §ããŠå¿ èŠãªæ å ±ãçšæããŸãããã
äžèšãµã€ãã§å¿
é ïŒRequiredïŒãšèšèŒãããŠããã®ã¯tokenãšchannelã®2ã€ã®ã¿ã§ãããçŸå®çã«ã¯textãå¿
èŠã§ãããã
ä»åã®ã³ãŒãã§ã¯ãpayload倿°ã«token channel textãèšå®ããŠããŸãã
ä»åã¯ãEvents APIã§ååŸããã¡ãã»ãŒãžã®ãªã³ã¯ãlinkãšãã宿°ã«ä»£å
¥æžã¿ãšããŠã
let payload = {
"token" : token,
"text" : link
};
ãããªæãã§payloadã®åæåæã«æž¡ããŠããŸãã
channelã¯ãã®åŸã®foræå
ifæã®æ¡ä»¶ã«ãã£ãŠã©ã®ãã£ã³ãã«ã«éããæ±ºããæã«payloadã«æž¡ããŠããŸãã
ïŒãããæžããŠããããchannelã®å€ã¯é©åœãªå®æ°ã«ä»£å
¥ããŠãããŠãforæçµãã£ãåŸã«payloadã®åæåèªäœãããã°ãpayloadã宿°ã§è¯ãã£ããªâŠãšãããparamsã«çŽæ¥ä»£å
¥ãå¯èœã ã£ããªâŠããšæ°ã¥ããŸãããïŒ
ãããŠäžèšã®æ
å ±ãAPIãšã³ããã€ã³ãã«POSTããŸãã
GASã®UrlFetchAppã¯ã©ã¹ã®fetchã¡ãœããã䜿ããŸããïŒå
¬åŒãªãã¡ã¬ã³ã¹ïŒ
const params = {
"method" : "post",
"payload" : payload
};
const r = UrlFetchApp.fetch(forward_url, params);
ãããªæãã§postãšå
çšã®payloadãparamsã«ä»£å
¥ããUrlFetchApp.fetchã®åŒæ°ã«æž¡ãã°OKã§ãã
ã¬ã¹ãã³ã¹ã¯åŸã»ã©ããã®POSTãæåãããã®å€å®ã«äœ¿ãããšãèŠè¶ããŠãrã«ä»£å
¥ããŠãããŸãã
2.2 ãã®çšéç¬èªã®éšåã«ã€ããŠ
åºæ¬çã«ã¡ãã»ãŒãžæçš¿ã¯2.1ã®å 容ã§ã§ããŸãããä»åã®çšéã®ããã«èšè¿°ããéšåã念ã®çºããã€ã説æããŸãã
ä»åã®Botã§ã¯ãç¹å®ã®ã¯ãŒããã«å¿ããŠãç¹å®ã®ãã£ã³ãã«ãã«ã¡ãã»ãŒãžãæçš¿ããããããã®ã¯ãŒããšãã£ã³ãã«ã®å¯Ÿå¿ãkey/valueãšããŠchannelsã«ä»£å
¥ããŠããŸããïŒä»ã«è¯ãæ¹æ³ãæãã€ããªãã£ãâŠïŒ
ãããŠãforæå
ã§ãåãåã£ãã¡ãã»ãŒãžã«channelsã®keyã®ãããããå«ãŸããŠããããå€å®ããå«ãŸããŠããã°è»¢éãããã£ã³ãã«ã®IDãpayloadã«ä»£å
¥ããããã«ããŠããŸãã
channelsã®valueã«äœ¿ããã£ã³ãã«ã®IDã¯ã以äžã®ããã«ããã£ã³ãã«åãå³ã¯ãªãã¯ããããªã³ã¯ãã³ããŒãã§ååŸã§ããŸãã
ãŸããä»åBotã§æçš¿ããã¡ãã»ãŒãžã®å
容ã¯ããŠãŒã¶ãæçš¿ããã¡ãã»ãŒãžãžã®ãªã³ã¯ã§ãã
ã¡ãã»ãŒãžã®ãªã³ã¯ã¯
ã¯ãŒã¯ã¹ããŒã¹ã®URL + /archives/ + æçš¿ãããã¡ãã»ãŒãžã®ãã£ã³ãã«ID + /p + ã¡ãã»ãŒãžã®ã¿ã€ã ã¹ã¿ã³ã
ãšãã£ãæååã§æ§æãããŠããŸãã
ã¯ãŒã¯ã¹ããŒã¹ãšãã£ã³ãã«ãšã¿ã€ã ã¹ã¿ã³ãã§ã¡ãã»ãŒãžãäžæã«ç¹å®ã§ãããšããããšã§ããïŒ
ããã§å¿
èŠãšãªããã£ã³ãã«IDãšã¡ãã»ãŒãžã®ã¿ã€ã ã¹ã¿ã³ãã¯ãEvents APIçµç±ã§ååŸãããŠãŒã¶ãæçš¿ããã¡ãã»ãŒãžã®æ
å ±ã«å«ãŸããŠããŸãã
ã¿ã€ã ã¹ã¿ã³ãã¯.ãå«ãŸãã圢åŒã§ååŸããããã®ã®ãURLäžã§ã¯.ã䜿çšãããªããããä»åã®ã³ãŒãã§ã¯replace(".","")ãçšããŠ.ãåãé€ããŠããŸãã
3. ãªã¢ã¯ã·ã§ã³éšåãäœã
ã³ãŒãäžã® addReaction 颿°ã«ãããéšåã§ãã
ã³ãŒãäžã«ã³ã¡ã³ãã§èšèŒããŠããéããã¡ãã»ãŒãžã«çµµæåãªã¢ã¯ã·ã§ã³ãã€ããå Žåã¯https://api.slack.com/methods/reactions.add ãåç
§ããŠå¿
èŠãªæ
å ±ãçšæããŸãã
å¿
é é
ç®ã¯token channel name timestampã§ãã
nameã¯çµµæåã®ååã§ããïŒæ¥æ¬èªã䜿ãããã¯æªç¢ºèªã§ããããŠãŒã¶ãç»é²ããçµµæåãæ¥æ¬èªåããä»ããŠããªãå Žåããããšæãã®ã§ã察å¿ããŠããããªâŠïŒïŒ
channelãštimestampã¯ããªã¢ã¯ã·ã§ã³ãä»ãã察象ãšãªãã¡ãã»ãŒãžãæçš¿ããããã£ã³ãã«ãšã¿ã€ã ã¹ã¿ã³ãã衚ããŠããŸããã¡ããã©2.2ã§èª¬æããã¡ãã»ãŒãžã®ãªã³ã¯ãæ§æããããã«å¿
èŠãªæååãšåãã§ããªã¢ã¯ã·ã§ã³å¯Ÿè±¡ãšãªãã¡ãã»ãŒãžãäžæã«ç¹å®ããããã®æ
å ±ã§ãã
ãããã®å¿
é é
ç®ãçšæã§ããããããšã¯ã»ãŒã¡ãã»ãŒãžæçš¿ïŒè»¢éïŒãšåãããã«UrlFetchApp.fetchã§POSTããã°OKã§ãã
4. å±¥æŽèšé²éšåãäœã
ã³ãŒãäžã® recordHistory 颿°ã«ãããéšåã§ãã
ãã®éšåã¯3ãŸã§ãšç°ãªããã¹ãã¬ããã·ãŒãã®æ±ãã«ã€ããŠã®èª¬æã«ãªããŸãã
ãŸããèšé²å
ã®ã¹ãã¬ããã·ãŒããååŸããŸãã
let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
次ã«ãäžã«åãã£ãŠè¿œèšããŠãããããããã¹ãã¬ããã·ãŒãã®æçµè¡ãååŸããŸãã
let lastrow = sheet.getLastRow();
ïŒã³ãŒãå
ã§ã¯äžèšã®2è¡ãdoPost(e)å
ã§å®è¡ããŠããŸããããrecordHistoryå
ã§ãã£ãŠãè¯ãã£ãããªãšæããŸããïŒ
æåŸã«ãæçµè¡ã®æ¬¡ã®è¡ãæžã蟌ã¿ããåãæå®ããŠãã®ç®æã«æžã蟌ã¿ããæååãã»ããããŸããïŒäžèšã®äŸã§ã¯æçµè¡ã®æ¬¡ã®è¡ã®3åç®ã«textãæžã蟌ãïŒ
sheet.getRange(lastrow+1,3).setValue(text);
以äžã§ããç°¡åã§ããïŒ
5. ã¡ãã»ãŒãžæçš¿ãåãåãéšåãªã©ãäœã
æåŸã®ä»äžããšããŠãã¡ã€ã³ã§ããdoPost(e)ã«æ»ããã¡ãã»ãŒãžæçš¿åãåãâåçš®é¢æ°åŒã³åºããå®è£
ããŸãã
ã¡ãã»ãŒãžæçš¿ã®åãåãã¯ã1.2ã§çšæããEvents APIã䜿çšããŸãã
ã³ãŒãäžã«ã³ã¡ã³ãã§èšèŒããŠããéããhttps://api.slack.com/events/message.channelsãåç
§ãããšãã©ã®ãããªåœ¢åŒã§æ
å ±ãåŸããããããããŸãã
ä»åã¯ãïŒèªèšŒã®ããã«tokenãå¿
èŠãªã®ã¯åœç¶ãšããŠãïŒeventå
ã®type channel text tsãä»ã®é¢æ°ã®ããã«å¿
èŠãšãªããŸãã
const json = JSON.parse(e.postData.getDataAsString()); ã§JSONãããŒã¹ããã®ã¡ãjson.event.typeãªã©ã®æå®ã§å¿
èŠãªæ
å ±ãåãåºããŸãã
ãããŠã¡ãã»ãŒãžã®è»¢éãããããã«ã2ã§äœæããforwardMessageãåŒã³ããã®çµæïŒresponseïŒãæ£åžžã ã£ãå Žåã¯addReaction recordHistoryãåŒã³ãŸãã
以äžã§ãã
ä»åã®å
容ãã§ããã°ãä»ã«ãç°¡åãªå¿çãããŠãããBotãªãäœãããšæããŸãïŒ
å®éã«ç§ã¯ããè€ããŠãšã¡ãã»ãŒãžæçš¿ãããããªã¢ã¯ã·ã§ã³ãããŠããã©ã³ãã ã«è€ããã¡ãã»ãŒãžãæçš¿ããŠãããBotããåæ§ã®åœ¢åŒã§å®è£
ããŠãç 究宀ã®ã¯ãŒã¯ã¹ããŒã¹ã§çšŒåãããŠããŸããïŒè€ãbot ver.2ïŒ
ååã®èšäºãšåæ§ã質åãå°ã£ãããšãããã°ãæ°è»œã«ã©ããïŒ
Discussion