1. 概要
申込があった場合、下記処理を行う事で申込管理をしやすくする。
- スプレッドシートへ記載
- 名簿や集計用
- Lineへ通知
- 状況確認用
本記事では「API連携」による通知について解説します。
2. LINE Messaging APIの準備
2-1. 「LINE Developers」にアクセス
- 「ログイン」をクリック
2-2 LINEアカウントでログイン
2-3. 「LINE Developers Account」を作成
2-4. 「Provider」を作成
2-5. 「Channel」を作成
2-6. 「User ID」を取得
2-7. 「Access Token」を取得
3. ウェブアプリ(HTML)の準備
3-1. New Deploymentを選択
3-2. Web appを選択
3-3. 内容を記載
3-4. Deployment完了
3-5. 申込フォーム画面のHTMLファイルを作成
3-6. 申込完了画面のHTMLを作成
4. サンプルコード
4-1. ファイル構成(GitHubで管理 )
- notification/line/app_form_to_spreadsheet_and_line.gs
- メインコード
- notification/html/entry_form.html
- 申込フォーム画面
- notification/html/thanks.html
- 申込完了画面
- notification/slack/gas_properties.gsheet
- 「WebHook URL」を含め、コード内に書かない方が良いデータ(ID、PASSWORD、KEY等)をプロパティとして保存
4-2. スプレッドシートIDの取得
4-3. GAS Editorの開け方
※「+新規」をクリック
4-4. コード & 解説
※複数のプログラムよりプロパティファイルを共有する為、敢えてスタンドアロン型(*6-2)を採用する
// プロパティ情報が記載されているスプレッドシートのID
const bookId = '1j2z-S●●●●●●●●●●●●●●●●●●●●●●●●●●●●cQk';
// 申込フォーム
const doGet = () => {
const html = HtmlService.createTemplateFromFile('entry_form');
html.app_url = getValueOfProperty('H32');
return html.evaluate().addMetaTag('viewport', 'width=device-width, initial-scale=1, user-scalable=no').setTitle('申込フォーム');
}
// 申込フォーム完了
// ・スプレッドシートへ記録
// ・Lineへ通知
// ・完了画面に申込内容を表示
const doPost = (e) => {
const eventMap = getEventInfo(e);
recordToSpreadSheet(eventMap);
sendEvent(eventMap);
// 完了画面に申込内容を表示
const html = HtmlService.createTemplateFromFile('thanks');
html.joinTime = eventMap.get('joinTime');;
html.name = eventMap.get('name');
html.tel = eventMap.get('tel');
html.notes = eventMap.get('notes');
return html.evaluate().addMetaTag('viewport', 'width=device-width, initial-scale=1, user-scalable=no').setTitle('申込完了');
}
// スプレッドシートへ記録
const recordToSpreadSheet = (eventMap) => {
const sheet = getTargetSheet(getValueOfProperty('G32'));
const event = [eventMap.get('now'), eventMap.get('joinTime'), eventMap.get('name'), eventMap.get('tel'), eventMap.get('notes')];
sheet.appendRow(event);
}
// 申込内容を取得
const getEventInfo = (e) => {
let eventMap = new Map();
eventMap.set('joinTime', e.parameter.joinTime + '時');
eventMap.set('name', e.parameter.name);
eventMap.set('tel', e.parameter.tel);
eventMap.set('notes', e.parameter.notes);
eventMap.set('now', Utilities.formatDate(new Date(), 'JST', 'YYYY-MM-dd HH:mm:ss'));
return eventMap;
}
// Lineへ通知
const sendEvent = (eventMap) => {
const joinTime = eventMap.get('joinTime');
const name = eventMap.get('name');
const tel = eventMap.get('tel');
const notes = eventMap.get('notes');
const now = eventMap.get('now');
const eventInfo = `【申込日時】${now}\n【参加時間】${joinTime}\n【名前】${name}\n【連絡先】${tel}\n【備考】${notes}`;
sendToLine(eventInfo);
}
// 申込用スプレッドシート
const getTargetSheet = (sheetName) => {
const spreadsheetId = getValueOfProperty('D32');
const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
return spreadsheet.getSheetByName(sheetName);
}
// 指定のスプレッドシートに記載されているプロパティの値を取得
const getValueOfProperty = (cell) => {
const sheet = SpreadsheetApp.openById(bookId).getSheetByName('Properties');
return sheet.getRange(cell).getValue();
}
// メッセージをLineへ通知
const sendToLine = (msg) => {
// Message Push API Url
const targetUrl = getValueOfProperty('C32');
// アクセストークン
const accessToken = getValueOfProperty('E32');
// BotユーザーID
const to = getValueOfProperty('F32');
const headers = {
'Content-type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + accessToken,
};
const param = {
'to': to,
'messages': [
{
'type': 'text',
'text': msg,
},
],
};
const payload = JSON.stringify(param);
const options = {
'method': 'post',
'headers': headers,
'payload': payload,
};
UrlFetchApp.fetch(targetUrl, options);
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
<title>卓球レッスン申込</title>
</head>
<body>
<div class="container">
<div class="container-fluid">
<form action="<?= app_url ?>" method="POST" name="entryForm">
<div class="card text-white bg-primary mb-3">
<div class="card-header">申込フォーム</div>
<div class="card-body">
<h5 class="card-title">卓球レッスン申込</h5>
<p class="card-text">9月20日(月)、2時間コース、1000円</p>
</div>
</div>
<div class="card text-dark bg-light mb-3">
<div class="card-body">
<h5 class="card-title">参加時間を選択して下さい。</h5>
<div class="form-check">
<input class="form-check-input" type="radio" name="joinTime" id="joinTime1" value="10">
<label class="form-check-label" for="joinTime1">
10時
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="joinTime" id="joinTime2" value="14" checked>
<label class="form-check-label" for="joinTime2">
14時
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="joinTime" id="joinTime3" value="18">
<label class="form-check-label" for="joinTime3">
18時
</label>
</div>
</div>
</div>
<div class="card text-dark bg-light mb-3">
<div class="card-body">
<h5 class="card-title">お名前を教えて下さい。</h5>
<div class="form-floating mb-3">
<input type="text" class="form-control" name="name" id="name" placeholder="田中">
<label for="floatingInput">お名前</label>
</div>
</div>
</div>
<div class="card text-dark bg-light mb-3">
<div class="card-body">
<h5 class="card-title">ご連絡先を教えて下さい。</h5>
<div class="form-floating mb-3">
<input type="text" class="form-control" name="tel" id="tel" placeholder="090-1234-5678">
<label for="floatingInput">ご連絡先</label>
</div>
</div>
</div>
<div class="card text-dark bg-light mb-3">
<div class="card-body">
<h5 class="card-title">ご質問などあれば記載して下さい。</h5>
<div class="mb-3">
<textarea class="form-control" name="notes" id="notes" rows="3"></textarea>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
<title>申込完了</title>
</head>
<body>
<div class="container">
<div class="container-fluid">
<div class="card text-white bg-primary mb-3">
<div class="card-header">申込完了</div>
<div class="card-body">
<h5 class="card-title"><?= name ?>さん、ご申込ありがとうございます!</h5>
<p class="card-text"><?= name ?>さんの申込内容</p>
</div>
</div>
<ul class="list-group">
<li class="list-group-item">【参加時間】<?= joinTime ?></li>
<li class="list-group-item">【ご連絡先】<?= tel ?></li>
<li class="list-group-item">【ご質問】<?= notes ?></li>
</ul>
</div>
</div>
</body>
</html>
5. 実行結果例
【申込フォーム画面】
【申込完了画面】
【スプレッドシート】
【Line】
6. 参考
6-1. GAS(Google Apps Script)とは
- https://workspace.google.co.jp/intl/ja/products/apps-script/
- https://developers.google.com/apps-script?hl=ja
6-2. 2種類の方式
- コンテナバインド型(スプレッドシートやフォームに紐づくタイプ)
- スタンドアロン型(独立タイプ)
6-3. Web APIとは
6-4. 「UrlFetchApp.fetch()」について
投稿者プロフィール
-
開発好きなシステムエンジニアです。
卓球にハマってます。