質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • JavaScript

    16447questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • API

    1525questions

    APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

  • Google Apps Script

    847questions

    Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

  • Slack

    179questions

    Slackは、Tiny Speckという企業からリリースされたコミュニケーションツールです。GoogleDriveやGitHubなど、さまざまな外部サービスと連携することができます。

GASでSlackBotを作りたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 240

TOMOMI33

score 1

 前提・実現したいこと

素人ですが、GASでslack用に自動のログ・ファイル削除botを作りたく、奮闘しております。

http://lyncs.hateblo.jp/entry/2017/06/04/191421
https://qiita.com/yoccan/items/46b2a068807d79b59a61
https://teratail.com/questions/126798

上記を参照して過去の質問ベースでコピペし作ったのですが、下記のエラーメッセージが発生しました。

 発生している問題・エラーメッセージ

 undefined のメソッド「forEach」を呼び出せません。(行 120、ファイル「osouji1」)

⇒【listAll.forEach(function(a){】の部分を指摘されています。

おかげさまで解決いたしました。
また別件にて問題が上がっており、下記ご参照頂けますようお願いいたします。

 該当のソースコード

/* 引数 */
var BOT_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty("BOT_ACCESS_TOKEN");
var SLACK_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty("SLACK_ACCESS_TOKEN");
var OAuth_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty("OAuth_ACCESS_TOKEN");
var LEGACY_TOKEN = PropertiesService.getScriptProperties().getProperty("LEGACY_TOKEN");
var days = 1; // 日以上経過したら削除
var ignoreType = "images,pdfs"; // 削除対象にしないファイル形式
var targetChannels = ['osouji2nd']// 対象にしたいチャンネル


/* 削除処理 */
function deleteOldFile(){
  targetChannels.forEach(function(channelName){
    var channelId = SlackDelFileApp.getId(channelName, 'channels') || SlackDelFileApp.getId(channelName, 'groups');
    if(channelId === ''){
    Logger.log('Not found "' + channelName + '". Skip');
    return -1; // チャンネルが無ければ終了
    }
    Logger.log('Found "' + channelName + '"(id => "' + channelId + '")');

    var deleteFiles = SlackDelFileApp.getFileListWithOutOption(channelId, days, ignoreType); // 削除対象を取得

    deleteFiles.files.forEach(function(file){ // 削除
      var data = SlackDelFileApp.deleteFile(file.id);
      if (data.error){
        Logger.log('  Failed to delete file ' + file.name + ' Error: ' + data.error);
      } else {
         Logger.log('  Deleted file "' + file.name + '"(id => "' + file.id + '")');
      }
    });
  });
}

/* メッセージ送信 */
function postDeleteFileMessage(channelId, botName, message){

  targetChannels.forEach(function(channelName){
  Logger.log(SlackDelFileApp.postConfirm(channelName, days, ignoreType));
  });
}

/* スコープを与える */
var SlackDelFileApp = {}

/* SLACKのTOKENを読み込み */
SlackDelFileApp.OAuth_ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty('OAuth_ACCESS_TOKEN');// slackで発行したTOKENをGASの環境変数に設定

/* soundTricker/SlackApp を使うよりurlからAPI叩いたほうが早いらしいので */
SlackDelFileApp.execute = function(method, params){
  if (params === undefined ) params = {'token' : SlackDelFileApp.OAuth_ACCESS_TOKEN};
  var options = {
    'method': 'POST',
    'payload': params
  }
  var res = UrlFetchApp.fetch('https://slack.com/api/' + method, options);
  return JSON.parse(res.getContentText());
}

/* 翌日の削除対象ファイルの確認 */
SlackDelFileApp.postConfirm = function(channelName, days, ignoreType){
  var channelId = SlackDelFileApp.getId(channelName, 'channels') || SlackDelFileApp.getId(channelName, 'groups');
  var deleteFiles = this.getFileListWithOutOption(channelId, days + 1, ignoreType); // 翌日の削除対象を取得
  var nullMsg = '明日の削除対象ファイルはないみた~い(「・ω・)「';
  var listMsg = '明日の削除対象ファイルは以下の通りで~す(「・ω・)「 ' + deleteFiles.files.length + ' 件のファイルだよ~👀';

  deleteFiles.files.forEach(function(f){
    listMsg +=  "\n\t・" + f.name ; 
  });

  var params = {
    'token': SlackDelFileApp.OAuth_ACCESS_TOKEN,
    'channel': channelName,
    'username' : 'OMURA', //投稿するbotの名前
    'text'     : deleteFiles.files.length == 0 ? nullMsg : listMsg //投稿するメッセージ
  }
  return this.execute('chat.postMessage', params);
}

/* ファイルの削除*/
SlackDelFileApp.deleteFile = function(id){
  var params = {
    'token': SlackDelFileApp.OAuth_ACCESS_TOKEN,
    'file' : id // delete対象はidで指定
  }
 return this.execute('files.delete', params);
}

/* ファイルのリスト取得 */ // unused
SlackDelFileApp.getFilesList = function(params){
  params.token = SlackDelFileApp.OAuth_ACCESS_TOKEN;
   return this.execute('files.list', params);
}

/* チャネル名(グループ名)からidを取得 */
SlackDelFileApp.getId = function(name, type) {
  return "GBH2C79N0";
}

/* 日付 -> 秒変換 -> 日時*/
SlackDelFileApp.elapsedDaysToUnixTime = function(days){  
  var date = new Date();
  var now = Math.floor(date.getTime()/ 1000); // unixtime[sec]
  return now - 8.64e4 * days + '' // 8.64e4[sec] = 1[day] 文字列じゃないと動かないので型変換している
}

/* 指定したタイプ以外のファイルを削除 */
SlackDelFileApp.getFileListWithOutOption = function(channelId, days, ignoreType, count){
  if(count === undefined) count = 1000;
  var params = {
    'token'    : SlackDelFileApp.OAuth_ACCESS_TOKEN,
    'count'    : count,
    'ts_to'    : SlackDelFileApp.elapsedDaysToUnixTime(days),
    'channel'    : channelId,
  }
  var allFiles = this.execute('files.list', params); // まず、全てのファイルを取ってくる
Logger.log(allFiles)
  params.types = ignoreType; // typeを指定
  var ignoreFiles = this.execute('files.list', params); // 指定した形式のファイルを取ってくる

  var getDiffs = function(listAll,listIgnore){
    var diffs = [];
    listAll.forEach(function(a){
      var exist = false;
      listIgnore.forEach(function(i){
        if (a.id === i.id) exist = true;
      });
      if ( !exist ) diffs.push(a);
    });
    return diffs;
  }
Logger.log(allFiles)
  allFiles.files = getDiffs(allFiles.files, ignoreFiles.files) // 指定したタイプ以外のファイルを取得
  return allFiles;
}

 試したこと

if、forEachに関して調べてみたのですが、そもそもjavasctiptを触るのも今回が初めてで殆ど理解できていない状況です。
途中に出てくる(a)や(i)が何を指しているのかもわからず…。

丸投げで申し訳ございませんが、何卒よろしくお願いいたします。

⇒LEGACY TOKENを入れてみたり、TOKENの権限を増やしてみたりしましたが上手くいかず、難航しておりましたが、
「OAuth_ACCESS_TOKEN」を入れることで当初のエラーは無くなりました。
アドバイス頂きありがとうございました。
(※引数にある各TOKENの違いはよくわからないまま、とりあえずすぐに引っ張って来られるように書いて有ります…。)

しかし、チャンネル内の削除対象がうまく削除されません…。
(この場合は画像・pdfを残しメッセージを削除したい)

[18-07-03 21:06:07:505 PDT] {files=[], paging={total=0, pages=0, count=1000, page=1}, ok=true}
[18-07-03 21:06:07:633 PDT] {files=[], paging={total=0, pages=0, count=1000, page=1}, ok=true}
[18-07-03 21:06:07:729 PDT] {channel=GBH2C79N0, ok=true, message={subtype=bot_message, text=明日の削除対象ファイルはないみた~い(「・ω・)「, type=message, bot_id=BBJCJT7M2, username=OMURA, ts=1530677167.000127}, ts=1530677167.000127}

ログには上記のように出ております。

細かい入力項目を確認したり、各ソースコードの意味と役割を調べたりもしているのですが、なまじエラーが出ていない分どこが間違っているのか判別がつかない状況です。
重ね重ね恐縮ですが、お知恵を貸して頂けますと幸いです。

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • papinianus

    2018/07/05 11:11

    すみません。質問を誤解していたんですが、消したいのはファイル(画像)ではないのですか?メッセージを消したいのでしょうか?だとしたら、参考元が全く参考にならないと思うのですが…

    キャンセル

  • TOMOMI33

    2018/07/05 14:23

    こちらこそ、ご説明が足りず申し訳ございません。現在のところ、画像・pdfを残しその他のチャットは消したいという仕様です。7行目【var ignoreType = "images,pdfs"; // 削除対象にしないファイル形式】でその設定にしたつもりでしたが、何か理解が間違っておりましたでしょうか…。

    キャンセル

回答 1

checkベストアンサー

0

120行目がどこか分かりませんが、エラーとforEachの位置からして、

  1. allFilesが取れてない
  2. allFiles.filesが空(そのチャンネルにファイルがない)
  3. ignoreFilesが取れてない
  4. ignoreFiles.filesが空(無視すべきファイルがない)
    などが想像できます。

必要に応じて、Logger.log()も使ってください。

呼び出しコードが不明なので、全体的にソースを提示していただいたほうがいいと思います(最低でもどこが120行なのかは追記してほしいです)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/03 14:54 編集

    ご回答ありがとうございます。
    練習用のチャンネルを使用しているため、2. 4. は可能性としてありそうです。
    1. 3. Logger.log()に関しましては不勉強で恐縮ですが、私の方でも調べてみます。

    また、全体のソースをご提示した上で、120行目を太字にいたしました。
    ご面倒をおかけいたしますが、ご検討いただけますと幸いです。
    よろしくお願いいたします。

    キャンセル

  • 2018/07/03 15:12

    120行目がそこなら「2.」じゃないですかね?
    下から4行目(allFiles.files = getDiffs(allFiles.files, ignoreFiles.files) // 指定したタイプ以外のファイルを取得のすぐ上)の空行にLogger.log(allFiles.files);と書いて実行してみて、スクリプトエディタの表示→ログを見てください。

    キャンセル

  • 2018/07/03 15:20

    そのチャンネルにごく小さいファイルを添付して実行するのも一つです。(ほんとにやるまでには、必ずファイルが消えるかテストするステップを何度かやると思うので、消すものと除外するものの2パターンのファイルは事前に作っておいて損はないと思います)

    キャンセル

  • 2018/07/03 15:56

    ありがとうございます!

    Logger.log(allFiles.files);を入れて実行したところ、
    [18-07-03 15:27:26:749 JST] undefinedとだけ出ました。
    また、2.の体で、削除しても差し支えのない別チャンネルでテストを試みたのですがエラーの内容は同様でした。
    せっかくご回答頂いているにもかかわらず、申し訳ございません…。

    キャンセル

  • 2018/07/03 16:02 編集

    [18-07-03 15:27:26:749 JST] undefined → この出力はファイルの抽出をして、なかったということになるかと思うのですが、試してみた別のチャンネルには必ずファイルはあると思っていいですか?
    もちろん1日以上経過しているファイルが、です。

    キャンセル

  • 2018/07/03 16:24 編集

    はい、そのチャンネルでは普メッセージ投稿・画像投稿があります。
    (メッセージ投稿だけを消すチャンネルを作りたい)
    var ignoreType = "images,pdfs"; // 削除対象にしないファイル形式
    で画像・pdfを指定していたため、pdfの無いチャンネルでpdfsの表記が入るのがまずかったのかと思い、一度外してみたのですが、結果は変わらずでした…。

    キャンセル

  • 2018/07/03 17:58 編集

    ちなみになんですが、TOKENの権限って足りてますよね?(どのページからどんなボタンをおしたかorTOKENの取得でどこを参照したかの情報をいただけないでしょうか)
    あとLogger.log(allFiles)にしてみていただけませんか?

    キャンセル

  • 2018/07/03 19:18

    TOKENの権限は一応見よう見まねでいじってみたのですが、もしかすると不足があるかもしれません…。
    かなり手間取ったので、確認に少しお時間頂きます。
    取り急ぎ、手元のメモでは
    read,files:write:user,bot
    ・あなたのパブリックチャンネルのコンテンツにアクセス
    ・あなたのワークスペースのファイル、コメント、および関連情報にアクセスする
    ・ファイルのアップロードと変更を行います
    と記録があります。もし不足がございましたらご教示頂けますと幸いです。

    Logger.log(allFiles)を挿入したところ
    [18-07-03 19:17:14:259 JST] {ok=false, error=invalid_auth}が表示されました。

    キャンセル

  • 2018/07/03 23:21

    ログからは認証に失敗してますね。レガシートークンってのを検索して、そちらのトークンで試すとうまくいくかもしれない

    キャンセル

  • 2018/07/04 13:28

    ありがとうございます!
    質問本文にも記載いたしましたが、OAuth_ACCESS_TOKENを使用することでエラーがなくなりました。
    papinianus様に丁寧に教えて頂きましたおかげです。

    ただ、今度はソースコードの実行内容が反映されておらず…。
    チャンネル内にメッセージと画像があり、画像を残してメッセージを消したいという趣旨で作ったはずなのですが、削除対象のファイルが無いとみなされております。

    ご面倒をおかけして恐縮ですが、もう少しだけ、ご協力頂けますでしょうか。

    キャンセル

  • 2018/07/18 10:34

    当初の質問から趣旨が変わってきましたため、一旦〆切らせて頂きます。
    おかげさまで最初の壁は解決できましたので、改めて御礼申し上げます。

    私も精進いたしますので、またご縁があればお力添え頂けましたら幸いです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    16447questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • API

    1525questions

    APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

  • Google Apps Script

    847questions

    Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

  • Slack

    179questions

    Slackは、Tiny Speckという企業からリリースされたコミュニケーションツールです。GoogleDriveやGitHubなど、さまざまな外部サービスと連携することができます。