【GAS】Google Classroomの投稿をLINEに転送

#Google Classroomとは
Googleが開発した教育向けWebアプリで、先生と生徒間でお知らせの投稿や課題の作成や配布ができるサービス。現時点で導入している高校も多数あり、今後ギガスクール構想によって、導入する学校が増えると思われる。

##Google Classroomの問題点
先生が投稿したお知らせは、すぐにメールやアプリで通知されるが、生徒が投稿したお知らせは通知されない。

→ほとんどの生徒が日常から使用しているLINEに転送すれば、先生のお知らせも見逃さず、生徒が投稿したお知らせもわかる。

#Google Apps ScriptでClassroom APIを使用
https://developers.google.com/classroom

Classroom APIというものがあり、GASでそれを使用しコードを書いた。Classroom APIについて日本語の情報があまりなかった。
このClassroom APIを活用すれば、Classroomに投稿することもできる。

##LINE Messaging APIでLINEに送信
APIを叩けばLINEに送信できるようになる（月最大1000件無料）
他の説明は割愛。
なお、LINE Developersで見れる、Channel access tokenが必要なのでメモ。

#仕様
スプレッドシートを作成し、そのスクリプトエディタを使用した。
トリガーを使用して、新しい投稿がないかチェック。

###コード
プログラミング初心者なのでミスがあるかもしれませんがご了承ください。

```javascript:コード.gs
function myFunction() {
  var lock = LockService.getUserLock();　//多重実行防止のためのロック
  try {
    lock.waitLock(25000);
    
    //****0時から6時まで処理スキップ******
    var day = new Date();
    var hour = day.getHours();
    Logger.log("day_hour:" + day + "_" + hour);
    if(hour >=0 && hour <=6){
      //return;
    }
    //*******************************
    
    var optionalArgs = {　//最大取得コース数
      pageSize: 10
    };
    var courses = Classroom.Courses.list(optionalArgs).courses;　//コースの取得
    var i = 0;
    for (var i = 0; i < courses.length; i++) { //コース別繰り返し処理
      Logger.log("i:" + i);
      var course = courses[i];
      var sheet = SpreadsheetApp.getActiveSheet();//シートOpen
      var announcements = Classroom.Courses.Announcements.list(course.id).announcements;
      var sheet_array = sheet.getDataRange().getValues(); //シートの配列への格納
      Logger.log("sheet_array:" + sheet_array);
      if (announcements && announcements.length > 0) { //投稿件数＞0のときの処理
        Logger.log("announcements.length:" + announcements.length);
        if(announcements.length < 5){ 
          var an_length = announcements.length;　//投稿件数<5のとき取得は投稿件数
        }
        else {
          var an_length = 5;　//投稿件数＞5のとき取得は5件まで
        }        
        Classroom繰り返し処理:
        for (var j = 0; j < an_length; j++) {　//取得件数まで繰り返し（配列のため初期値0）
          var announcemessage = [];　//取得物格納用1次元配列の定義
          var announcement = announcements[j];//投稿内容（JSON）
          var announcement_updateTimesheet = announcement.updateTime;//投稿(更新）時刻
          var announcement_creatoruserId = creatoruId(announcement);//UserIdを名前に変換
          var message_announcement = announcement.text;//投稿メッセージ        
          Logger.log("sheet_array.length:" + sheet_array.length);
          if(sheet_array.length != 1){
            for (var sheet_j = sheet_array.length; sheet_j > 0; sheet_j--){//シートでの一致検索
              Logger.log("sheet_array[sheet_j - 1][2]:" + sheet_array[sheet_j - 1][2]);
              if(sheet_array[sheet_j - 1][2] == message_announcement){//投稿メッセージがシートで発見したら次の投稿へContinue
                continue Classroom繰り返し処理;
              }
            }
          }
          var message_announcement_attachment = "";
          if (announcement.materials != undefined){　//添付物があるときの処理
            if(announcement.materials[0].driveFile != undefined){ 
              message_announcement_attachment = String.fromCharCode(10) + String.fromCharCode(10) +"*添付ファイル*" + String.fromCharCode(10) +  announcement.materials[0].driveFile.driveFile.alternateLink;
            } else 
              if(announcement.materials[0].link != undefined){
                message_announcement_attachment = String.fromCharCode(10) + "*リンク*" + String.fromCharCode(10) +  announcement.materials[0].link.url;
              } else if(announcement.materials[0].youtubeVideo != undefined){ 
                message_announcement_attachment = String.fromCharCode(10) +"*YouTubeVideo*" + String.fromCharCode(10) +  announcement.materials[0].youtubeVideo.alternateLink;
              } else if(announcement.materials[0].form != undefined){ 
                message_announcement_attachment = String.fromCharCode(10) +"*フォーム*" + String.fromCharCode(10) +  announcement.materials[0].form.formUrl;
              }
            if(announcement.materials.length >= 2){　//添付物が2以上のとき
              for(var k = 1; k < announcement.materials.length; k++){
                if(announcement.materials[k].driveFile != undefined){ 
                  message_announcement_attachment = String.fromCharCode(10) + announcement.materials[k].driveFile.driveFile.alternateLink;
                } else 
                  if(announcement.materials[k].link != undefined){
                    message_announcement_attachment = String.fromCharCode(10) +  announcement.materials[k].link.url;
                  } else if(announcement.materials[k].youtubeVideo != undefined){ 
                    message_announcement_attachment = String.fromCharCode(10) +  announcement.materials[k].youtubeVideo.alternateLink;
                  } else if(announcement.materials[k].form != undefined){ 
                    message_announcement_attachment = String.fromCharCode(10) +  announcement.materials[k].form.formUrl;
                  } 
              }
            }
          }
          //***各項目の1次元配列の作成***
          announcemessage.push(announcement_updateTimesheet);//投稿の作成(更新)時刻
          announcemessage.push(announcement_creatoruserId);//投稿者
          announcemessage.push(message_announcement);//投稿メッセージ
          announcemessage.push(message_announcement_attachment);//投稿メッセージの添付
          announcemessage.push("sent");//送信済フラグ
          Logger.log("j_announcemessage:" + j +"_" + announcemessage);
          //*******
          var message = announcemessage[1] + String.fromCharCode(10) + String.fromCharCode(10) + announcemessage[2] + announcemessage[3];//送信メッセージの作成
　　sheet_sent(message)//送信処理
        GmailApp.sendEmail('自分のメールアドレス',"Classroom",message);//メール通知 
      }
      //----------------
          sheet.appendRow(announcemessage);//シート配列への追加
          Logger.log("j_sheet_array:" + j +"_" + sheet_array);
          sheet.sort(1);//シートの並び替え
        }
      } else {　//投稿がないとき
        Logger.log('No announcements found.');
      }       
    }
    
  } catch(e) {
    Logger.log(e);
  } finally {
    lock.releaseLock();//ロック解除
  }
  return;
}


function creatoruId(announcement){
  var creatorusername;
  switch (announcement.creatorUserId){
    case "ClassroomAPIにあるUserId"://それぞれcaseで処理
      creatorusername = "名前";
      break;
  }
  if (creatorusername == undefined){
    creatorusername = announcement.creatorUserId;
  }
  return(creatorusername);
}

function sheet_sent(message){
  var CHANNEL_ACCESS_TOKEN = '(CHANNEL ACCESS TOKENを入れる)';
  var postData = {
        "messages": [{
          "type": "text",
          "text": message,
        }]
      };
  
  var url = "https://api.line.me/v2/bot/message/broadcast";
  var headers = {
        "Content-Type": "application/json",
        'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
      };
  
  var options = {
        "method": "post",
        "headers": headers,
        "payload": JSON.stringify(postData)
      }; 
  var response = UrlFetchApp.fetch(url, options);
  return;
}
```
`GmailApp.sendEmail('自分のメールアドレス',"Classroom",message);`　のところで自分のメールアドレスを入れればそこにも転送できる。また、Classroomの部分が件名になっている。要らなければ消しても問題ない。

`var CHANNEL_ACCESS_TOKEN = '(CHANNEL ACCESS TOKENを入れる)';`の部分で、LINE Developersで取得したChannel access tokenを入れる。

`case "ClassroomAPIにあるUserId"://それぞれcaseで処理
      creatorusername = "名前";`
生徒の権限だと、ユーザー名が取得できなかったので手動で登録。
UserIdが見つからなかったときにスプレッドシートに入るUserIdかLINEで送信されるUserIdをいれる。見つからなかったら名前の代わりにUserIdが送信され、誰が投稿したかわからない。一回は投稿してもらわないと生徒の権限ではUserIdが取得できない。