문장에서도 알 수 있는, GAS에 의한 수업 통지의 LINE bot 작성

문계에서도 알 수 있는, GAS에 의한 수업 통지의 LINE bot의 작성 그 ③ 의 계속입니다.
이번에 마지막이 됩니다.
  • 문계에서도 알 수 있는, GAS에 의한 수업 통지의 LINE bot의 작성 그 ① ~GAS를 사용한 LINE bot의 작성~
  • 문계에서도 알 수 있는, GAS에 의한 수업 통지의 LINE bot의 작성 그 ② ~GAS와 스프레드시트의 제휴, 일자의 포맷~
  • 문계에서도 알 수 있는, GAS에 의한 수업 통지의 LINE bot의 작성 그 ③
  • 문계에서도 알 수 있는, GAS에 의한 수업 통지의 LINE bot 작성

    setTrigger라고 하는 것을 사용해, 수업 개시 10분전에 통지가 오도록(듯이) 합니다.

    이 기사에서 이해


  • GAS setTrigger 사용
  • Messaging API 푸시 알림 보내기

  • 이번에 할 일


  • 요건 ④ 수업 10분 전에 수업을 통지하는 기능 추가



  • 요구사항 정의


  • 푸시 알림을 보내는 기능 만들기
  • push 통지로 보내는 수업 정보를 취득하는 function를 작성
  • 위의 function이 지정된 시간에 실행되기위한 function을 만듭니다

  • 푸시 알림을 보내는 기능 만들기



    Code.gs
    function push(text, zoom) {
      //メッセージを送信(push)する時に必要なurlでこれは、皆同じなので、修正する必要ありません。
      //この関数は全て基本コピペで大丈夫です。
      var url = "https://api.line.me/v2/bot/message/push";
      var headers = {
        "Content-Type" : "application/json; charset=UTF-8",
        'Authorization': 'Bearer ' + access_token,
      };
    
      //toのところにメッセージを送信したいユーザーのIDを指定します。(toは最初の方で自分のIDを指定したので、linebotから自分に送信されることになります。)
      //textの部分は、送信されるメッセージが入ります。createMessageという関数で定義したメッセージがここに入ります。
      var postData = {
        "to" : user_id,
        "messages" : [
          {
            'type':'text',
            'text':text,
          },
          {
            'type':'text',
            'text':zoom,
          }
        ]
      };
    
      var options = {
        "method" : "post",
        "headers" : headers,
        "payload" : JSON.stringify(postData)
      };
    
      return UrlFetchApp.fetch(url, options);
    }
    
    "messages" : [{}{}] 의 형태로 하는 것으로, 패스워드가 다른 메세지로서 보내 오는 것을 하고 있습니다 (위의 화상 참조). 이렇게 하면 암호를 쉽게 복사할 수 있습니다.

    푸시 알림으로 보낼 수업 정보를 얻는 기능 만들기



    Code.gs
    function pushClassInfo() {
     //function findNextClassを実行
      var classInfos = findNextClass();
      var today = new Date();
      //あとで、現在より15分後の日時を取得します。
      var quarterAfter = new Date();
      var day = today.getDay();
      var array = ["日", "月", "火", "水", "木", "金", "土"];
     //quarterAfterに入っている日時が、現在より15分後になりました。
      quarterAfter.setMinutes(quarterAfter.getMinutes() + 15);
      var hhmmToday = Utilities.formatDate( today, 'Asia/Tokyo', 'HH:mm');
      var hhmmQuarter = Utilities.formatDate( quarterAfter, 'Asia/Tokyo', 'HH:mm');
      console.log(classInfos);
      console.log(classInfos.startTime <= hhmmQuarter); //授業が始まるのは、今から15分後より前、つまりもうすぐ授業が始まる。
     //findNextClassで取得した授業が現在の曜日のものか
      if(classInfos.classDay == array[day] && classInfos.startTime <= hhmmQuarter ){ 
        var message = "もうすぐ次の授業です。\n" + classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime + 
          ")\n授業名:" + classInfos.className + 
            "\nZoomID:" + classInfos.zoomID + 
              "\nPass:" + classInfos.zoomPass;
        console.log(message);
       //function pushを実行
        push(message, classInfos.zoomPass);
      } else {console.log("not upcoming one ");}
    }
    

    흐름으로서는 fuction findNextClass 로 1번 가까운 수업을 취득해, 그것이 시작되는 것이 지금으로부터 15분 이내인지 판별해, true라면 클래스의 정보를 push한다고 하는 느낌입니다.

    지정된 시간에 알림이 전송되도록합니다.



    코드(코피페로 움직입니다)

    Code.gs
    //授業時間が設定されている時、その授業時間の10分前にpushClassInfoを実行するタイマーをセットする
    function setTrigger(){
      var today = new Date();
      var year = today.getFullYear();
      var month = today.getMonth();
      var date = today.getDate();
      for(let i=3; i <= 27; i+=4) {
        if(sheet.getRange(i, 1).getValue()){
          var classStart = sheet.getRange(i, 1).getValue();
          var startMinutes = classStart.getMinutes();
          classStart.setFullYear(year);
          classStart.setMonth(month);
          classStart.setDate(date);
          classStart.setMinutes(startMinutes - 10);
          console.log(classStart);
          ScriptApp.newTrigger('pushClassInfo').timeBased().at(classStart).create();
        }
      }
    }
    
    function delTrigger() {
      var triggers = ScriptApp.getProjectTriggers();
      for(let i=0; i < triggers.length; i++) {
        if (triggers[i].getHandlerFunction() == "pushClassInfo") {
          ScriptApp.deleteTrigger(triggers[i]);
        }
      }
    }
    

    트리거 사용법


    ScriptApp.newTrigger('function名').timeBased().at(時間).create()에서 트리거라는 것을 설정하는 것이 가능합니다. 이 트리거를 사용하면 지정된 날짜와 시간에 함수를 실행할 수 있습니다.
    단, 세트한 트리거는 계속 남아 버리므로 deleleTrigger 로 삭제합니다.
    그리고는, function setTrigger를 이른 아침에, delTrigger를 자정에 실행하는 설정을 하면 완료입니다.

    setTrigger와 delTrigger를 매일 호출



    h tps://이웃이 다른 t. 작은 m/가 s-t 리깅 r- 등 t/#와 C4
    이 기사의 「5. 매일 지정 시간의 Date 객체를 작성한다」를 참고로, setTrigger를 이른 아침(1한 이전의 시간)에, delTrigger를 자정(7한 이후의 시간)에 세트 해 제발. 즉, 기사의 작업을 2회 행합니다.
    덧붙여서 1~4도 ScriptApp.newTrigger 에 대해 자세하게 해설해 주고 있으므로, 읽으면 공부가 됩니다.

    이것으로 완성입니다!
    마지막으로 업데이트를 잊지 마세요.

    최종 코드의 전체 이미지



    모두 작성한 후의 코드는 다음과 같습니다.

    Code.gs
    var access_token = "アクセストークン"
    // 自分のユーザーIDを指定します。LINE Developersの「Your user ID」の部分です。
    var user_id = "ユーザーID"
    
    //★★スプレッドシートID★★
    var ss = SpreadsheetApp.openById("スプレッドシートID");
    //★★シート名★★
    var sheet = ss.getSheetByName("シート名");
    
    function doPost(e) {
      var event = JSON.parse(e.postData.contents).events[0];
      var returnMessage = "曜日と時限(半角:1〜7)を指定してね!\n次の授業が知りたいときは、「次」と入力してね!";
      if(event.source.userId == user_id){
        //返信するためのトークン取得
        var reply_token= event.replyToken;
        if (typeof reply_token === 'undefined') {
          return;
        }
        var message = event.message.text;
        for(let i=3; i<=7; i ++) {
          var dateColumn = i;
          var day = sheet.getRange(1, i).getValue();
          if(message.includes(day)){
            for(let j=2; j<=26; j += 4) {
              var classNumRow = j;
              var classNum = sheet.getRange(j, 1).getValue();
              if(message.includes(classNum) && sheet.getRange(classNumRow, dateColumn).getValue()){
                var classInfos = getClassInfo(classNumRow, dateColumn);
                var returnMessage = classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime + 
                  ")\n授業名:" + classInfos.className + 
                    "\nZoomID: " + classInfos.zoomID + 
                      "\nPass: " + classInfos.zoomPass;
                reply(reply_token, returnMessage);
              } else if(message.includes(classNum) && !sheet.getRange(classNumRow, dateColumn).getValue()) {
                var returnMessage = "授業はありません。"
                reply(reply_token, returnMessage);
              }
            }
          }
        }
    
        if(message.includes("次")){
          var classInfos = findNextClass();
          var returnMessage = classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime + 
            ")\n授業名:" + classInfos.className + 
              "\nZoomID: " + classInfos.zoomID + 
                "\nPass: " + classInfos.zoomPass;
          reply(reply_token, returnMessage);
        } else {reply(reply_token, returnMessage);}
      }
    }
    
    function reply(reply_token, returnMessage) {
      var reply_url = 'https://api.line.me/v2/bot/message/reply';
    
      // メッセージを返信 
      UrlFetchApp.fetch(reply_url, {
        'headers': {
          'Content-Type': 'application/json; charset=UTF-8',
          'Authorization': 'Bearer ' + access_token,
        },
        'method': 'post',
        'payload': JSON.stringify({
          'replyToken': reply_token,
          'messages': [{
            'type': 'text',
            'text': returnMessage,
          }],
        }),
      });
      return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
    }
    
    
    function push(text, zoom) {
      //メッセージを送信(push)する時に必要なurlでこれは、皆同じなので、修正する必要ありません。
      //この関数は全て基本コピペで大丈夫です。
      var url = "https://api.line.me/v2/bot/message/push";
      var headers = {
        "Content-Type" : "application/json; charset=UTF-8",
        'Authorization': 'Bearer ' + access_token,
      };
    
      //toのところにメッセージを送信したいユーザーのIDを指定します。(toは最初の方で自分のIDを指定したので、linebotから自分に送信されることになります。)
      //textの部分は、送信されるメッセージが入ります。createMessageという関数で定義したメッセージがここに入ります。
      var postData = {
        "to" : user_id,
        "messages" : [
          {
            'type':'text',
            'text':text,
          },
          {
            'type':'text',
            'text':zoom,
          }
        ]
      };
    
      var options = {
        "method" : "post",
        "headers" : headers,
        "payload" : JSON.stringify(postData)
      };
    
      return UrlFetchApp.fetch(url, options);
    }
    
    function pushClassInfo() {
      var classInfos = findNextClass();
      var today = new Date();
      var quarterAfter = new Date();
      var day = today.getDay();
      var array = ["日", "月", "火", "水", "木", "金", "土"];
      quarterAfter.setMinutes(quarterAfter.getMinutes() + 15);
      var hhmmToday = Utilities.formatDate( today, 'Asia/Tokyo', 'HH:mm');
      var hhmmQuarter = Utilities.formatDate( quarterAfter, 'Asia/Tokyo', 'HH:mm');
      console.log(classInfos);
      console.log(classInfos.startTime <= hhmmQuarter); //授業が始まるのは、今から15分後より前、つまりもうすぐ授業が始まる。
      if(classInfos.classDay == array[day] && classInfos.startTime <= hhmmQuarter ){ 
        var message = "もうすぐ次の授業です。\n" + classInfos.classDay + "曜" + classInfos.classNum + "限 (" + classInfos.startTime + "-" + classInfos.endTime + 
          ")\n授業名:" + classInfos.className + 
            "\nZoomID:" + classInfos.zoomID + 
              "\nPass:" + classInfos.zoomPass;
        console.log(message);
        push(message, classInfos.zoomPass);
      } else {console.log("not upcoming one ");}
    }
    
    function findNextClass() {
      var today = new Date();
      var hour = today.getHours();
      var minutes = today.getMinutes();
      console.log(today);
      for(let i=0; i <= 6; i++) {
        var day = (today.getDay() + i) % 7;
        var dateColumn = day + 3;
        var array = ['日','月','火','水','木', '金', '土'];
        console.log("曜日:" + array[day]);
    
        var searchHour = 0;
        if(day == today.getDay()){searchHour = hour;} else { searchHour = 6;}
        for(var j=0; j < 24-searchHour; j++) {
          console.log(searchHour + "時");
          for(let k=2; k <= 26; k+=4){
            var classNumRow = k;
            var startTimeRow = k + 1;  
            //始業時間が設定されている場合、始業時間を取得
            if(sheet.getRange(startTimeRow, 1).getValue()) {
              var startTime = sheet.getRange(startTimeRow, 1).getValue();
              var startHour = startTime.getHours();
              var startMinutes = startTime.getMinutes();
              console.log("start hour: " + startHour);
              //検索した時、今と検索時間の日付と時間が一致していても、今の分が始業の分を超えている場合は情報を取得しない          
              if(searchHour === startHour && today.getDay() === day && hour === searchHour && minutes > startMinutes){
                console.log("\nalready orver\n");
                //時間が一致し、授業が存在する場合、情報を取得
              } else if(searchHour === startHour && sheet.getRange(classNumRow, dateColumn).getValue()){
                var classInfos = getClassInfo(classNumRow, dateColumn);
                return classInfos;
              }
            }
          }
          searchHour += 1;
        }
      }  
    }
    
    function getClassInfo(rowNum, dateColumn){
      var className = sheet.getRange(rowNum, dateColumn).getValue();
      var classDay = sheet.getRange(1, dateColumn).getValue();
      var classNum = sheet.getRange(rowNum, 1).getValue();
      var startTime = Utilities.formatDate( sheet.getRange(rowNum + 1, 1).getValue(), 'Asia/Tokyo', 'HH:mm');
      var endTime = Utilities.formatDate( sheet.getRange(rowNum + 3, 1).getValue(), 'Asia/Tokyo', 'HH:mm');
      var zoomID = sheet.getRange(rowNum + 1, dateColumn).getValue();
      var zoomPass = sheet.getRange(rowNum + 2, dateColumn).getValue();
      var classInfos = {className: className, classDay: classDay, classNum: classNum, startTime: startTime, endTime: endTime, zoomID: zoomID, zoomPass: zoomPass};
      return classInfos;
    }
    
    function setTrigger(){
      var today = new Date();
      var year = today.getFullYear();
      var month = today.getMonth();
      var date = today.getDate();
      for(let i=3; i <= 27; i+=4) {
        if(sheet.getRange(i, 1).getValue()){
          var classStart = sheet.getRange(i, 1).getValue();
          var startMinutes = classStart.getMinutes();
          classStart.setFullYear(year);
          classStart.setMonth(month);
          classStart.setDate(date);
          classStart.setMinutes(startMinutes - 10);
          console.log(classStart);
          ScriptApp.newTrigger('pushClassInfo').timeBased().at(classStart).create();
        }
      }
    }
    
    function delTrigger() {
      var triggers = ScriptApp.getProjectTriggers();
      for(let i=0; i < triggers.length; i++) {
        if (triggers[i].getHandlerFunction() == "pushClassInfo") {
          ScriptApp.deleteTrigger(triggers[i]);
        }
      }
    }
    

    마지막으로



    어땠습니까?
    나는 이것을 만들었을 때, 문계에서도 이런 것을 만들 수 있다고 감동했습니다.
    문계 시선으로 가능한 한 알기 쉽게 해설을 넣을 생각이므로, 조금이라도 도움이 되면 기쁩니다.
    덧붙여 미경험문계 대학생이 쓰고 있으므로, 잘못등 있을지도 모릅니다만 양해 바랍니다.
    끝까지 일해 주셔서 감사합니다!

    좋은 웹페이지 즐겨찾기