Google ToDo+GAS+Twitterで自分を監視！達成共有自動ツイートでライフハックしよう。

## 背景

様々な新しい習慣を始めたいなと思いつつも、どうしてもその習慣が続けられなくて悩んでいたので、GoogleToDoとTwitterを使った自己監視システムを作ってみました。タスク管理は、外に発信することで自分に対して強制力を持たせることができるので、ぜひ活用してみてください！

![スクリーンショット 2021-08-20 11.10.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/ba51cc53-771d-0e18-f520-5ad02d7fbf68.png)


## 作ったもの
GoogleToDoの達成状況を毎週まとめて集計し、毎週定時に自動的にツイートするシステム。

## 利用したフレームワーク

- Google ToDoリスト
- Google Apps Script + Task API
- twitter + twitter API

今回作ったGoogle App ScriptのソースコードはGitHubリポジトリで公開してますので是非参考にしてください。
https://github.com/kchan0514/MyTaskManagementWithSNS

## 参考にした記事
今回は開発にあたり下記の記事を参考にさせていただきました。

- [Google Apps ScriptからGoogle Tasks を操作する](https://www.virment.com/use-google-tasks-from-script/)
- [GoogleAppsScript から Twitter に投稿する](https://qiita.com/szaking/items/466101cbe9b3846ba0f4)
- [GASのスクリプトプロパティをコードで設定する方法(setPropertyメソッド)](https://auto-worker.com/blog/?p=2365)


## Google ToDoにタスクを入れる

まずは、Google ToDoリストに自分が今週実施したいと思うタスクを期限付きで入れましょう。タスク期限はその週中に設定する必要は必ずしもありません。Google ToDoリストはGoogleカレンダーの中から入ることができます。今回はデフォルトリストというリストを使ってToDoタスクを設定しました。

<img width="300" alt="mojikyo45_640-2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/1fe41e78-5bda-065b-ab8d-98831f4cad72.png">

## Twitterアカウントの用意＋Twitter APIの用意

次にTwitterの方を準備します。Twitterアカウントを持っていない場合はまずTwitterアカウントを作成します。その上で、下記のサイトを参考に、[TwitterDeveloperPortal](https://developer.twitter.com/en/portal/dashboard)にて、Appを作成し、Twitter APIを使うためのconsumer api keyとconsumer api secretを取得してください。
[GoogleAppsScript から Twitter に投稿する](https://qiita.com/szaking/items/466101cbe9b3846ba0f4)

![スクリーンショット 2021-08-20 12.03.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/f7ee6486-363b-a128-16df-711f33ba8682.png)


## Google Apps Scriptの作成
API keyとsecretを取得したら、Google Apps Scriptで実装を始めます。空のGoogle App Scriptプロジェクトを用意していただき、まずは、先ほど取得したtwitter用のAPI keyとSecret をプロパティに設定しましょう。

```
// プロパティにtwitter API用の認証情報を保存する。
function setVal(){
  PropertiesService.getScriptProperties().setProperty("CONSUMER_API_KEY", "your key");
  PropertiesService.getScriptProperties().setProperty("CONSUMER_API_SECRET", "your secrect");
}
```
setVal関数を実行し、プロパティ設定を完了させます。
![スクリーンショット 2021-08-20 12.12.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/c4b5de54-a9d4-fbee-e41d-f4218f31301b.png)


次にTwitterのOAuthを使ってアプリの認証を完了させます。まずは、OAuthを使うのに必要なライブラリをGASに「導入しましょう。
[GoogleAppsScript から Twitter に投稿する](https://qiita.com/szaking/items/466101cbe9b3846ba0f4)の「GASでOAuth認証を行うライブラリを追加」を参考にしてください。完了したら、下記のコードを記述します。

```
// OAuthでtwitterの認証用のURLを取得する関数
function getOAuthURL() {
  Logger.log(getService_().authorize());
}
 
//twitterサービス取得用のAPI
function getService_() {
  return OAuth1.createService('Twitter')
      .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
      .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
      .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
      .setConsumerKey(PropertiesService.getScriptProperties().getProperty("CONSUMER_API_KEY"))
      .setConsumerSecret(PropertiesService.getScriptProperties().getProperty("CONSUMER_API_SECRET"))
      .setCallbackFunction('authCallback_')
      .setPropertyStore(PropertiesService.getUserProperties());
}

```
getOAuthURLを実行すると、consoleにurlが表示されますので、そのurlにブラウザでアクセスし、twitter認証を完了させてください。

![スクリーンショット 2021-08-20 12.18.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/cc4f713c-3320-314a-d289-480d364dfcbf.png)

次に実装に必要なAPI群を導入します。まずはGoogle ToDoの情報を取得するのに必要な

下記の記事を参考にし、Tasks APIというものを有効にしましょう。
[Google Apps ScriptからGoogle Tasks を操作する](https://www.virment.com/use-google-tasks-from-script/)


ここまでできたら下準備はOK。実装に入っていきます。
まず、Google ToDoリストから、現在の１週間のタスクを取得する部分を実装します。
特定のタスクはtwitterで何回やったか言及したいので、タスク名に対してのmapを作り、回数をカウントする仕組みも合わせて作ります。

```

// 明示的にツイートしたいタスク名リスト
const taskNames = ['瞑想', '筋トレ', "メモ書き"]
const taskMap = new Map();

// 完了したタスクのカウント変数
let num_complete=0;
// 完了したマップ外タスク
let num_others_completed =0;

for (let i = 0; i < taskNames.length; i++) {
    // マップの生成
    taskMap.set(taskNames[i], 0)
}

.
.
.


function TweetAchievements(){
  var myTaskLists = getTaskLists_();
  Logger.log( myTaskLists );
  var myTasks  = getWeekTasks_( myTaskLists[0].id )
}


// GoogleのTask listを取得する関数
function getTaskLists_() {
  var taskLists = Tasks.Tasklists.list().getItems();
  if (!taskLists) {
    return [];
  }
  return taskLists.map(function(taskList) {
    return {
      id: taskList.getId(),
      name: taskList.getTitle()
    };
  });
}

// GoogleのTask listの中の各taskを取得する関数
function getWeekTasks_(taskListId) {
  var tasks = Tasks.Tasks.list(taskListId, {
      showCompleted: true,
      showDeleted: true,
      showHidden: true,
      
    }).getItems();
  if (!tasks) {
    return [];
  }
  
  Logger.log(tasks);
  var week_tasks = [];
  
  let this_monday = getMondayOfThisWeek_();
  let next_monday = getMondayOfNextWeek_();
  Logger.log("対象開始日:"+this_monday);
  Logger.log("対象終了日:"+next_monday);
  if (tasks.length) {
    Logger.log("length:"+tasks.length);
    for (var i = 0; i < tasks.length; i++) {
      var task = tasks[i];
      Logger.log("取得したタスクタイトル:"+task.title);
      Logger.log("取得したタスク期限:"+task.due);
      Logger.log("取得したタスクステータス:"+task.status);
      // 今日が含まれる月曜日〜日曜日の１週間タスクだけを対象に抽出する。
      if (new Date(task.due) >= this_monday && new Date(task.due) < next_monday) {
        week_tasks.push(task);
        
        Logger.log("今週のタスクリストにpush");   
        if(task.status == "completed"){
          num_complete++;
          isFoundinMap = false;

          for (let i = 0; i < taskNames.length; i++) {
            　// マップに該当するタスクはカウントを増やす。
              if(task.title == taskNames[i]){
                var newValue = taskMap.get(taskNames[i])+1;
                taskMap.set(taskNames[i], newValue)
                Logger.log("set:"+'key:' + taskNames[i] + ' value:' + newValue);   
                isFoundinMap = true;
                break;
              }
          }

          // マップに該当するものが見つからない場合はその他に振り分ける
          if(isFoundinMap == false){
            num_others_completed++;
          }
        }
      }
    }
  }

  if (!week_tasks) {
    Logger.log("今週のタスクは見つかりませんでした。");
    return [];
  }

  Logger.log("今週のタスクの数:"+week_tasks.length);
  Logger.log("今週終わったタスクの数:"+ num_complete);

  return week_tasks.map(function(task) {
    return {
      id: task.getId(),
      title: task.getTitle(),
      notes: task.getNotes(),
      completed: Boolean(task.getCompleted()),
      due: task.due,
    };
  }).filter(function(task) {
    return task.title;
  });
}

// 今週の月曜日を取得する関数
function getMondayOfThisWeek_(){
  let today = new Date();
  let this_year = today.getFullYear();
  let this_month = today.getMonth();
  let date = today.getDate();
  let day_num = today.getDay();
  let this_monday = date - day_num + 1;
  let this_monday_date = new Date(this_year, this_month, this_monday);
  return this_monday_date;
}

// 翌週の月曜日を取得する関数
function getMondayOfNextWeek_(){
  let today = new Date();
  let this_year = today.getFullYear();
  let this_month = today.getMonth();
  let date = today.getDate();
  let day_num = today.getDay();
  let this_monday = date - day_num + 1;
  let next_monday = this_monday + 7;
  let next_monday_date = new Date(this_year, this_month, next_monday);
  return next_monday_date;
}

```

ここまでで、その週に行う予定だったタスクの数と、実際に達成したタスクの数、そして各タスク（マップに記載したもの）がそれぞれ何回行われたか、という情報が取得できます。
あとはこれをツイートするだけです。　今回は達成率に合わせて、コメントも一緒に記載できるような仕組みにしました。

```
// 成果をツイートするメイン関数
function TweetAchievements(){
  
  var myTaskLists = getTaskLists_();
  Logger.log( myTaskLists );
  var myTasks  = getWeekTasks_( myTaskLists[0].id )

  var tweettext="今週のGoogleTask達成率:\n";
  tweettext+="達成:"+num_complete +"/ 当初予定:" +myTasks.length+"\n";

  var percentage = (num_complete / myTasks.length) * 100;

　// 達成度に応じたコメント
  if(percentage < 30){
    tweettext+= percentage+"％！全然できてない！気合を入れよう！";
  }
  else if(percentage < 50){
    tweettext+= percentage+"％！もっと頑張ろう！";
  }
  else if(percentage < 80){
    tweettext+= percentage+"％！半分は超えた！できなかったものを見直そう！";
  }
  else if(percentage < 100){
    tweettext+= percentage+"％！かなりいい！合格レベル！";
  }
  else if(percentage == 100){
    tweettext+= percentage+"％！全コンプ！素晴らしい！";
  }

  tweettext+="\n";

  taskMap.forEach(function(value, key) {
    console.log(key + ' = ' + value)
    tweettext+=key+"を"+value+"回\n";
  });
  tweettext+="その他を"+ num_others_completed+"回\n";
  
  tweettext+="\n";
  tweettext+="やりました。\n";

  // タグ関連はここ
  //tweettext+="#ゼロ秒思考 #メモ書き #瞑想 #習慣";

  Logger.log( myTasks );
  Logger.log( tweettext );

  tweetText_(tweettext);

}
.
.
.

// ツイートする関数
function tweetText_(text) {
  var twitterService = getService_();
  
  if (twitterService.hasAccess()) {
    var twMethod = { method:"POST" };
    twMethod.payload = { status: text };
    Logger.log("request");
    var response = twitterService.fetch("https://api.twitter.com/1.1/statuses/update.json", twMethod);
    
    Logger.log(response.getContentText());
 
  } else {
    Logger.log(response);
  }
}
```
この「TweetAchievements」が実行できることを確認できましたら、毎週決まった時間にツイートできるようにトリガーを設定します。Google Apps Scriptからトリガーを選び設定しましょう。![スクリーンショット 2021-08-20 11.31.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/9933b6ee-acea-07a2-1d29-3db1df187a7c.png)


これで下記のようなツイートが毎週実装されるはずです。

![スクリーンショット 2021-08-20 11.10.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111483/881ea0dc-d921-c819-5041-81f8b452297e.png)

いかがでしょう？作ったソースコードはこちらのGithubリポジトリで確認できますので、ぜひ参考にしてください。
https://github.com/kchan0514/MyTaskManagementWithSNS

結局作ったところで習慣を続けられるかは自分次第・・・、頑張りましょう！