GAS 基礎まとめ

GASに関する基礎をまとめます。

## GASのエディタを開く方法
まずはスプレッドシートを開きます。
`拡張機能 > AppScript`
![スクリーンショット 2021-12-05 11.02.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615043/9cc2454c-9c66-6f67-5413-25dc87c41e87.png)

をクリックするとエディタを開くことができます。

![スクリーンショット 2021-12-05 11.09.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615043/b5d4f94a-fe4b-771b-7900-52d0b326e9e8.png)


はい！開けましたね！

## スプレッドシートの編集
### シートの指定
シートを指定するために必要なものは2つあります。

* シートID(どのスプレッドシートか特定する)
* シート名

今回は`SHEET`という定数に編集するSHEET情報を保存する形で紹介します。
今後もシート情報は`SHEET`に保存されている前提で話を進めていきます。

``` GAS
// スプレッドシートと紐づいている場合は使用可能
const SHEET = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート名')

// シートIDとシート名を指定する
const SHEET = SpreadsheetApp.openById(シートID).getSheetByName('シート名')
```

### 値を修正
#### データを追加
``` GAS
// 末尾に追加
SHEET.appendRow([追加するデータ])
```
#### 中身を取得
``` GAS
// 全データを取得
SHEET.getDataRange().getValues()
```
#### 値を更新
``` GAS
// 全データを取得しvaluesにデータを格納
const values = SHEET.getDataRange().getValues()
// セルを指定して更新（今回はA1）
values[0][0] = "A1のセルを更新"
// 値を更新
SHEET.getDataRange().setValues(values)

```

#### 行を削除
``` GAS
// 全データを取得しvaluesにデータを格納
SHEET.deleteRow(2)
```

### 関数を実行するためのタブをスプシ内に作成
ヘルプの右側に新しいタブを表示させます。
下記画像では「新しいタブ」というタブを作成し、タブ内では「データを追加、データを削除」という名前で関数を実行できるようにしています。

![スクリーンショット 2021-12-05 13.51.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615043/efb27bbc-ad1f-77f6-a834-6bb0fbe99625.png)


``` GAS
// 全データを取得しvaluesにデータを格納
const ui = SpreadsheetApp.getUi()
const menu = ui.createMenu('GASの関数を実行するタブ')
menu.addItem('タブ内に表示される名前', '実行する関数名')
menu.addToUi()
```

### 新しいシートの作成
``` GAS
// 全データを取得しvaluesにデータを格納
const ss = SpreadsheetApp.getActiveSpreadsheet()
// 新しいシートの準備
const newSheet = SHEET.copyTo(ss)
newSheet.setName(date)
//新しいシートを追加
ss.setActiveSheet(newSheet)
```

## トリガーを指定して定期的に関数を実行する
Apps Scriptの画面左側のメニューバーより「トリガー」を選択し、
画面右下の「トリガーを追加」をクリックする

![スクリーンショット 2021-12-05 14.16.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615043/3be84ad5-c50d-7734-bb21-1ff4cca9d267.png)

イベントのソースを選択で"時間手動型">時間ベースのトリガーのタイプを選択で"日付ベースのタイマー"
を選択すると毎日関数を実行できます。
![スクリーンショット 2021-12-05 14.17.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615043/557f5461-55dc-10ba-9e3d-81193ce027a8.png)


## Googleカレンダーとの連携
当日の予定を取得してスプレッドシートに追加するスクリプトを作ります。

``` GAS

const SHEET = SpreadsheetApp.getActiveSheet()
// 取得したいgmailアドレスをJson形式で入力
const calendarTitleMap = {
  "xxx@gmail.com" : "xxxがわかる任意の名前,
  "xxx@gmail.com" : "xxxがわかる任意の名前"
}
// 自分がアクセスできるカレンダーの一覧を取得（自分以外のカレンダーを含む）
const calendars = CalendarApp.getAllCalendars()
let dt = new Date()
dt.setDate(dt.getDate())
for(i in calendars){
  let calendar = calendars[i]
  let calendarName = calendarTitleMap[calendar.getId()]
  let events = calendar.getEventsForDay(dt)

  // calendarTitleMapで入力したメールアドレスのカレンダーではない or 予定がない時は次のカレンダーのループへ
  if(calendarName == undefined || events.length == 0){
    continue
  }

  for(e in events){
   SHEET.appendRow([events[e].getTitle(),Utilities.formatDate(events[e].getStartTime(), 'JST', 'HH:mm'), Utilities.formatDate(events[e].getEndTime(), 'JST', 'HH:mm')])
  }
}

```

## Gmailと連携
スプレッドシートに入力されている内容をGmailで送信します。
今回はスプレッドシートに下記3つの情報が入っていることを想定しています。

* A列に受信者の名前
* B列に挨拶文
* C列に受信者のメールアドレス

``` GAS

const SHEET = SpreadsheetApp.getActiveSheet()
const data = SHEET.getDataRange().getValues()
const subject = 'メールのタイトル'

for(i in data){
  const recipientName = data[i][0] //メールを送る人の名前(スプシA列に記入しておく)
  const recipientGreet = data[i][1] //挨拶(スプシB列に記入しておく)
  const recipientMail = data[i][2] //メールを送る人のメアド(スプシC列に記入しておく)
  const body = `${recipientName}様\n${recipientGreet}`
  const options = {name: '送信者の名前'}
  GmailApp.sendEmail(recipientMail, subject,body,options)
}

```

## LINEとの連携
今回は、メッセージを送信するプログラムと、相手からのメッセージが来たら返信するプログラムを作っていきます。

### Developersアカウントの登録
LINE Developoersから登録
https://developers.line.biz/ja/

### プロバイダの作成
今回はGAS-Firstという名前で作成しました。

### チャネルの作成
今回はMessaging APIを利用します

### 応答設定
`Messaging API設定　> 応答メッセージ`より設定
* 応答モード：Bot
* あいさうtメッセージ：オフ
* 詳細設定：オフ
* Webhook：オン

### チャネルアクセストークンの発行
`Messaging API設定　> チャネルアクセストークン`より発行

### LINE.gsを実装
`ファイルを追加 > スクリプト > "LINE"と入力`
するとLINE.gsが作成されます。

``` GAS

const REPLY = "https://api.line.me/v2/bot/message/reply"
const SHEET_LOG = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LINEログ')
const ACCESS_TOKEN = "取得したアクセストークン"

//固定のメッセージを送信する 
function pushMessage(){
  const push = 'https://api.line.me/v2/bot/message/broadcast';
  pushNotify()
  function pushNotify(){
    const message = '送信したいメッセージ'

    UrlFetchApp.fetch(push, {
      method: 'post',
      headers:{
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + ACCESS_TOKEN,
      },

      payload: JSON.stringify({
        messages:[
          {
            type: 'text',
            text: message
          },
        ]
      }),

    })

  }
}

// メッセージが来たら返答する
function doPost(e){
  const data = JSON.parse(e.postData.contents).events[0]
  const replyToken = data.replyToken
  const lineUserId = data.source.userId
  const postMsg = data.message.text
  const date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss')
  SHEET_LOG.appendRow([lineUserId, postMsg, date])

  const postData = {
    "replyToken" : replyToken,
    "messages" : [{
      "type" : "text",
      "text" : `${postMsg}と入力しました`
    }]
  }

  const headers = {
    'Content-Type': 'application/json; charset=UTF-8',
    'Authorization': 'Bearer ' + ACCESS_TOKEN,
  }
  const options = {
    "method" : "POST",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  }
  UrlFetchApp.fetch(REPLY,options)
}

```
完成したらデプロイ
新しいデプロイ >  種類の選択　> Webアプリ
アクセスできるユーザー > 全員へ変更> デプロイ

表示された新しいデプロイをLINE DevelopersのWebhook設定に登録


## slackとの連携
GASからslackのワークスペースにbotを使ってメッセージを送信する機能を作っていきます。

### Incoming Webhookをslackに追加する

slackにログインして、
`設定と管理 > アプリを管理する`
次の画面で「Webhook」と入力し`Incoming Webhook`をslackに追加するをクリック。

次に、メッセージを送信したいチャンネルを選択し`Incoming Webhookインテグレーションの追加`をクリックします

次の画面で表示されているWebhook URLをソースコードを記述する際に使用するのでコピーしておきましょう。

### slcak.gsの実装
LINE.gsと同様の手順でslack.gsを作成します。

``` GAS

function slack(){
  const url = 'コピーしたURL'
  const username = 'botの名前'
  const icon = ':a'//アイコンを任意で設定
  const jsonData = {
    'username' : username,
    'icon_emoji' : icon,
    'text' : '送信するテキストを任意で設定'
  }

  const payload = JSON.stringify(jsonData)
  const options = {
    'method' : 'post',
    'contentType' : 'application/json',
    'payload' : payload
  }
  UrlFetchApp.fetch(url, options)
}

```

## Webアプリの作成
### webApp.gsファイルの作成
LINE.gsと同様にwebApp.gsファイルを作成します。

``` GAS

function doGet() {
  const user = Session.getActiveUser()
  let html = HtmlService.createTemplateFromFile('index')
  html.email = user.getEmail()

  const SHEET = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('webAppシート')
  const numColumn = SHEET.getLastColumn()
  const numRow = SHEET.getLastRow() - 1
  const dataRange = SHEET.getRange(2, 1, numRow, numColumn)
  html.data = dataRange.getValues()
  html.flag = 0

  return html.evaluate()
}


```

### index.htmlを作成
`ファイルを追加 > HTML > "index"を入力`してindex.htmlを作成します。
<body>の中身を下記に変更

``` GAS
<?
for(i in data){
  //Webを閲覧しているユーザーのメールアドレスとスプシのメアドが一緒なら出力
  if(email == data[i][2]){
    output._ = data[i][0] + '様 / ' + data[i][1]
    flag = 1
  }
}

if(0 == flag) output._ = 'ユーザーが登録されていません。'

?>
```
### デプロイ
デプロイした際に表示されるURLでアクセスすることにより出力を確認することができる。

## WebAPIの出力
最後にGASで作成したAPIを別プロジェクトから叩けるようにしていきます。
### WebAPI.gsの実装
APIを提供するためのファイルを作成します。
LINE.gsと同様にWebAPI.gsを作成しましょう。
スプレッドシートの値は先程のWebアプリと同様のものを使用します。

``` GAS
function doGet() {
  let result = {}

  const SHEET = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('webAppシート')
  const numColumn = SHEET.getLastColumn()
  const numRow = SHEET.getLastRow() - 1
  const dataRange = SHEET.getRange(2, 1, numRow, numColumn)
  const ssData = dataRange.getValues()

  result['data'] = ssData
  return ContentService.createTextOutput(JSON.stringify(result))
}
```

こちらでAPIの提供準備はOKです！
デプロイしてリンクをコピーしておきます。

### VScodeなどでhtmlファイルを実装
テキストエディタはなんでもいいですが、任意のhtmlファイルを作成し、ブラウザでプレビューできるようにします。
作成したhtmlファイルからAPIを叩きにいきます。

```JavaScript

<body>
  <script>
    const request = new XMLHttpRequest();
    request.open('GET', 'デプロイした際のURL');
    request.responseType = 'json';
    request.onload = function(){
      let data = this.response;
      document.write(data['data']);
    };
    request.send();
  </script>
</body>

```

はい！これでGASで作成したAPIを任意のファイルから叩くことができました！