Slackに投稿されたファイルを一定期間経過後にGoogleDriveに自動保存する

Slackフリープランのストレージ5GBの制限を解決するために、ファイルがSlackにアップロードされた後、指定した期間が経過したファイルをGoogleDriveに保存してSlackから削除するプログラムの導入方法を説明します。

GoogleDriveの指定したフォルダ内に、チャンネルごとにファイルがアップロードされるので、フォルダの共有リンクをワークスペースで共有することをおすすめします。

ただし、アップロードしたファイルを自動で削除するために、ワークスペースの管理者以上の権限を持ったユーザーが行ってください。

## 手順1 Slackにアプリを作成する

### 1.1 アプリを作成
https://api.slack.com/apps から**Create an App**を選択、作成するアプリ名（自由）を入力、ワークスペースを選択して**Create App**。

![001.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419349/6ab478c1-61f5-fbe3-1ca5-009a14886996.png)

### 1.2 スコープを設定

Basic Informationのページに移動するので左のメニューから**OAuth & Permissions**を選択。下にスクロールして

**Bot Token Scopes**に
「channels:read」・・・チャンネル名の取得に必要
「files:read」・・・ファイルの情報の取得に必要

**User Token Scopes**に
「files:write」・・・ファイルの削除に必要

を追加してください。下の画像のようになればOKです。
![002.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419349/6bf78764-6875-4c04-01d8-48101f6cd03a.png)

### 1.3 ワークスペースにインストール

ページを上にスクロールして**Install App to Workspace**を選択、下の確認画面で許可を押すとワークスペースにアプリがインストールされます。

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419349/86539324-493a-98fd-6ab8-74f0473d28c5.png)

### 1.4 トークンを確認

OAuth & Permissionsのページに**Tokens for Your Workspace**が表示されています。これを2つともコピーして控えておきます（漏洩のないように気を付けてください）。
「xoxp-」から始まるのがOAuth Access Token、「xoxb-」から始まるのがBot User OAuth Access Tokenです。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419349/0a22d296-7a48-d2cf-ddb9-e0160deb0eb4.png)

## 手順2 GoogleAppsScriptにアプリを作成する

### 2.1 GoogleDriveにファイルを保存するフォルダを作成する

GoogleDriveに、ファイルを保存するためのフォルダを作成してください。
フォルダを作成したら、そのフォルダのURLを確認してください。

`https://drive.google.com/drive/u/0/folders/《ここ》`

《》内の英数字がフォルダのIDです。これを控えておいてください。

### 2.2 GoogleDriveにスクリプトファイルを作成する

GoogleDriveを表示して新規>その他>GoogleAppsScriptを選択。
（もし一覧に無い場合は、その他>アプリを追加 から、GoogleAppsScriptを選択して追加してください。）

エディタに以下のコードをコピペして、《OAuth Access Token》、《Bot User Access Token》《フォルダのID》を先ほど控えたものに置き換えてください。
また、5行目のstoreDaysはファイルが削除されずにSlack上に保存される日数です。任意の日数に変更してください。

入力が完了したらCtrl+Sで適当な名前を付けて保存してください。

```Javascript

function deleteOldFiles() {
  var OAuthAccessToken = "《OAuth Access Token》"; 
  var BotUserAccessToken = "《Bot User Access Token》";
  var rootFolder = "《フォルダのID》";
  var storeDays = 90;
  
  // 第一引数: ファイルのSlack上での保存期間
  var res = filesList(storeDays, BotUserAccessToken);
  console.log("対象ファイル数" + res.files.length);
  if(res.files.length == 0){
    console.log("対象ファイルはありませんでした。");
    return;
  }

  var rootFolder = DriveApp.getFolderById(rootFolderId);
  
  for (var i = 0; i < 10; i++){
    var file = res.files[i];
    console.log(file);
    console.log("変換と削除を行います。 ID=" + file.id + ", title=" + file.title + ", Size=" + file.size);
    
    // 50MB以上のときfalse(gasの処理できる上限)
    if (moveFiles(file,BotUserAccessToken,rootFolder)){
      filesDelete(file.id,OAuthAccessToken);
    }
  }
}

// slack上のファイル一覧を取得
function filesList(days, token){
  var params = {
    token: token,
    ts_to: elapsedDaysToUnixTime(days),
  };
  return execute('files.list', params);
}

// slackからファイルを削除
function filesDelete(id,token){
  var params = {
    token: token,
    file: id,
  }
  return execute('files.delete', params);
}

// apiを実行
function execute(apiName, params){
  var options = {
    'method': 'POST',
    'payload': params,
  }
  var res = UrlFetchApp.fetch('https://slack.com/api/' + apiName,options);
  return JSON.parse(res.getContentText());
}

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


function moveFiles(file,token,rootFolder){
  // ファイル情報取得
  var fileId = file.id;
  var channelId = file.channels[0];
  var groupId = file.groups[0];
  var imId = file.ims[0];

  // フォルダ名を設定する
  if (!(channelId) && (groupId || imId)){
    var channelName = "DM,グループ";
  }
  else if (!(channelId || groupId || imId)){
    var channelName = "削除済みチャンネル";
  }
  else{
    var res = execute('channels.info',{
      token: token,
      channel: channelId,
    });
    // 自分が入ってる鍵付きチャンネルを判別
    if (res.ok){
      var channelName = res.channel.name;
    }
    else{
      var channelName = "DM,グループ";
    }
  }

  // gasの処理できる上限
  if(file.size > 50000000){
    return false;
  }

  // Slackからファイル取得
  var dlUrl = file.url_private;
  var headers = {
    "Authorization" : "Bearer " + token,
  };
  var params2 = {
    "method":"GET",
    "headers":headers,
  };
  var dlData = UrlFetchApp.fetch(dlUrl, params2).getBlob();


  // GoogleDriveにファイルをアップロードする
  var targetFolder = rootFolder.getFoldersByName(channelName +"_slackItems");
  // 対象フォルダがない場合は新しく作成
  if(targetFolder.hasNext() == false){
    var targetFolderId = rootFolder.createFolder(channelName +"_slackItems");
    }
  else {
    var targetFolderId = DriveApp.getFolderById(targetFolder.next().getId());
    }

  // 名前をつける
  var date = Utilities.formatDate(new Date(file.timestamp * 1000), "JST", "yyyy/MM/dd_HH:mm:ss");
  dlData.setName(date + "_" + file.title);

  // ファイルをアップロード
  var driveFile = targetFolderId.createFile(dlData);
  console.log("アップロード完了  "+ channelName + "_" + file.title);

  Utilities.sleep(500);
  return true;
}

```

### 2.4 GoogleAppsScriptの認証をする

エディタ画面の上のタブの「**関数を選択**」のプルダウンから「**deleteOldFiles**」を選択して左の実行ボタン（三角形）を押してください。（この時点ではまだファイルの削除は行われません。）

![005.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419349/d2d4585b-4c86-2808-5e52-5aaeb5bb2743.png)

上のようなウィンドウが出るので、許可を確認>Googleアカウントを選択>詳細>《プロジェクト名》（安全ではないページに移動）>許可 と進んでください。

### 2.5 GoogleAppsScriptのトリガーを設定する

プログラムの自動実行を設定します。

エディタの**編集**>**現在のプロジェクトのトリガー**を開き、**トリガーを追加**を押してください。

トリガーのタイプが日付ベースなら毎日、週ベースなら毎週プログラムが自動で実行されます。1回の実行で処理できるファイルは**最大10個**なので、利用頻度に合わせて設定してください。

![006.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419349/3070e173-0000-68be-ac4a-0b97ab8aa323.png)

## 手順3 Slackのチャンネルにアプリを追加する

ファイルの自動削除を実行したいチャンネルにこのアプリを追加してください。UIが頻繁に変わるため詳細の説明は省きますが、おそらくチャンネルの詳細画面から追加できます。

このアプリが追加されていないチャンネルではプログラムは実行されません。

---

以上で導入は完了です。
お疲れさまでした。

注意点として、50MB以上のファイルは手動で削除するなどする必要があります。


以下のサイトを参考にさせていただきました。
>SlackのファイルをGASで自動削除する - Crieit
>https://crieit.net/posts/Slack-GAS

>Slackのストレージを消費せずにファイルをアップロード ～アップロードされたファイルを即座にGoogle Driveに転送する～ - Qiita
>https://qiita.com/GMA/items/7e3e7cedcb880f2c1dc9


補足：トークンをスクリプトに直書きすることはセキュリティの点で非推奨です。
[GASのProperties Serviceを使ってスクリプトのプロパティを読み書きをする](https://qiita.com/unsoluble_sugar/items/ec5c935c4bfc2e06b246)
上の方の記事のように、スクリプトのプロパティに格納するのがおすすめです。