Open2

🍊Slack×GAS:チャンネル名をリネームしたい

ピン留めされたアイテム
barusubarusu

ハマったので供養。

やりたいこと

スラッシュコマンドから発火し、特定のチャンネルをリネームしたい

実現イメージ

  • /rename [対象チャンネル名] [新名]
     一致するチャンネルがリネームされる

  • /rename [新名]
     実行したチャンネルがリネームされる

想定の流れ

  1. スラッシュコマンド実行
  2. GASで受付:doPost(e)
  3. コマンドの引数に応じて分岐
  4. 対象のチャンネルを判別してリネーム
  5. 完了

これでいけるはずだったのに...

未解決課題

  • チャンネルリネームにはチャンネルのオーナーor作成者orワークスペース管理者である必要がある
  • bot、アプリからのユーザー代理操作は受け付けない

解決済課題

  • conversations.renameAPI実行時にnot_in_channelが返る

    • 原因:BotUserが対象チャンネルに属している必要がある
  • conversations.list API実行時に invalid_authが返る

    • → authの範囲を追加する必要がある

ソースコード(未リファクタ)

メイン関数

function doPost(e){

  var verificationToken = e.parameter.token;
  if (verificationToken != 'xxxxxxxxxx') { // AppのVerification Tokenを入れる
     throw new Error('Invalid token');
  }
  var command = e.parameter.command;
  var text = e.parameter.text;
  var userId = e.parameter.user_id;
  var commandAtChannelid = e.parameter.channel_id;

switch(command){

case '/addch':
try{
var addCh = createChannels(text)
var addRes = addUserToChannels(userId,addCh);

if( addRes!=false){

 var response = {text:text + 'チャンネルを作成しました:https://pleiades-lab.slack.com/archives/'+addCh};
 return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
}
  var kekka2 = '作成できませんでした'
  var response = {text:text + 'chを作成できませんでした'};
  return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
}
catch(addchError){
var kekka2 = '作成できませんでした:' + error;
  var response = {text: kekka2};
  return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);

}
break;
case '/renamech':
  try{
  
  if ( text.match(/ /)) {
  //textに区切り文字を含む場合の処理
    const array = text.split(' ');
    const newName = array[0];
    const targetCh = array[1];

  //targetChで対象のチャンネルを検索
  var targetChId = searchChannels('',targetCh);
}
  else{
    const newName = text;
    var targetChId = commandAtChannelid;
}

const resultRename = renameChannels(targetChId);
  if( resultRename == true){
    var response = {text:'Rename Finished.'};
    return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
    }
      else{
      var response = {text:'Rename Failed.'+ resultRename};
      return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON); 
        }
  }
  catch(renamechError){
  var response = {text:text + renamechError.message};
  return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);

  }

  break;

default:

  var response = {text:text + '分岐しませんでした'};
  return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);

  break;
}
}

チャンネル検索用関数

function searchChannels(cursor,chName) {
  
  const slack_app_token = "xoxb-xxxxxxxxxxxxxx";
  const limit =500;
  const options = {
    "method" : "get",
    "contentType": "application/x-www-form-urlencoded",
    "payload" : { 
      "token": slack_app_token,
      "cursor": cursor,
      "limit":limit
    }
  };
  const url = "https://slack.com/api/conversations.list";
  const response = UrlFetchApp.fetch(url, options);
  var channels = JSON.parse(response).channels;

for (const channel of channels){
  if (channel.name == chName) {
Logger.log(channel.id)
return channel.id;
 }
}
  if( responseMeta = JSON.parse(response).response_metadata.next_cursor != ''){
    searchChannels(JSON.parse(response).response_metadata.next_cursor,chName);
  }
  Logger.log('null');
  return null;
}

チャンネル名を変更する関数

function renameChannels(chId,name){
addUserToChannels('botUserId',chId); // 作業対象チャンネルにBotユーザーを追加する
  const slack_app_token = "xoxb-xxxxxxxxxxxxxx";
  const options = {
    "method" : "POST",
    "contentType": "application/x-www-form-urlencoded",
    "payload" : { 
      "token": slack_app_token,
      "channel": chId,
      "name": name
    }
  };
  const url = "https://slack.com/api/conversations.rename";
try{
    const response = UrlFetchApp.fetch(url, options);
    const resText = JSON.parse(response).channel;
    Logger.log(response);
    const chId = resText.id;
    return true
}

チャンネルにユーザーを追加する関数

function addUserToChannels(userId,chId){

  const slack_app_token = "xoxb-xxxxxxxxxxxxxx";
  const options = {
    "method" : "POST",
    "contentType": "application/x-www-form-urlencoded",
    "payload" : { 
      "token": slack_app_token,
      "channel": chId,
      "users": userId
    }
  };
    const url = "https://slack.com/api/conversations.invite";
try{
    const response = UrlFetchApp.fetch(url, options);
    const resText = JSON.parse(response).channel;
    const chId = resText.id;

if(JSON.parse(response).ok){
    return true;
}
    return false;
}
catch(e){
  return e;
}
barusubarusu

今後のTodo

回避策を考える

仮説(検証する)

A案:チャンネルのオーナー情報を書き換えてリネーム
B案:管理者ユーザーの代理でAPI実行する方法
C案:別のAPIを探す(Admin系とか怪しそうなんだよな)