Google スプレッドシートを利用した出席アプリケーション

![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/3005b1ae-be5f-3dc3-25fd-f8fdada10abc.gif)
# 作成経緯
週1で某大学の非常勤講師をさせて頂いてたりするのですが、2020年前期は COVID 問題でオンライン開講ということに。オンライン授業にあたり単純なところで出席どう管理するの的な話題が。確かに出席の管理はオンラインで且つ手作業となると地味にめんどくさいので、こんな時代だし絶対何かしらの方法はあると思われるので検討。

手短なところで Google Classroom にそもそもそういう機能があるとか zoom のチャットを工夫すれば対応出来そうな可能性は全然あると思いつつ、GAS(Google Apps Script) が手軽というお話をしてもらう機会があり 「GAS 触ってみたい！オシャンティなサーバーレスアプリを作成してみたい！！」と今更ながらになったので、Classroom や zoom は深堀せずに着手^^;（GAS の技術的なお話は近々また別の投稿で書こうと思います。今回は「誰でも出来る、Google スプレッドシートの出席アプリ」的なお話で。）

# 更新履歴
- 2020/05/04 遅刻判定処理追加
- 2020/05/03 入力者のユニーク判定処理誤り修正  
修正に伴いフォーマットのエクセル内、各授業シートの項目名を修正
- 2020/05/03 日時バッチ関数  ```execDailyBatch``` 追加  
関数の追加に伴いフォーマットのエクセル ```基本設定``` シートの項目追加

# 要件
実際に利用とするとなると組織的な運用承認が必要となるが、その辺はクリアした体で要件をざっくり定義。

- 非エンジニアでもアプリケーションを構築可能に
- 非エンジニアでも扱えるデータ形式に
- データは各組織が保持しサービスは保持しない（但し Google ドライブ上になる）
- サーバーを用意しなくても使えるように

という感じで、実際の導入は指定ファイルダウンロードして Google スプレッドシートのスクリプトにコピペすれば誰でも自分専用アプリとして利用できるところを到達点に。


# 仕様
- 出席時に自分の学籍番号を入力
- 出席は1日1回のみしか受け付けない
- 出席の一意性は Google アカウントのセッション情報を利用して保持
- 授業の1日での一意性は授業パスワードで保持
- 授業パスワードはタイマー処理で深夜に自動で変わる
- 授業パスワードは授業開始時に担当教員がアナウンス

# 実際の挙動
冒頭の画面キャプチャのような操作をおこなえばスプレッドシートに以下のように反映される。
<img width="848" alt="etc.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/684db857-2459-b374-416b-1cca6350bb04.png">

# 導入方法
## 1. 必要ファイルのダウンロード
https://github.com/koronpo/attend-form の以下ボタンより「Dounload zip」を選択し解凍。
<img width="565" alt="attend-form_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/24cfa7d0-6c1d-86a4-c4ad-04144204db3c.png">

## 2. 新規スプレッドシート作成
Google ドライブで新規スプレッド作成。スプレッドシートの名前は任意で。
<img width="310" alt="attend-form_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/1e112c96-8b59-af0a-932c-b89ee04045a8.png">

## 3. 雛形のエクセルファイルをインポート
作成したスプレッドシートのメニューより **ファイル > インポート** を選択。
<img width="357" alt="attend-form_03_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/ac2f625b-fe9c-3467-f4ec-e3091dae5291.png">
<img width="743" alt="attend-form_03_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/c713d020-bcd6-d364-b1ed-e12f6e63a6c8.png">
この画面でダウンロードした xlsx_format フォルダ内の ```format.xlsx``` アップロードする。
インポートの種類は ```スプレッドシートを置換する``` を選択。
<img width="387" alt="attend-form_03_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/403327fa-d30f-41bd-10ac-8941d6b611ad.png">
インポートが終わればシートが幾つか生成されている状態となる。
<img width="431" alt="attend-form_03_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/c7643186-304f-26e9-e70a-6bff40863a6d.png">

## 4. スクリプトの設定
スプレッドシートのメニューより **ツール > スクリプトエディタ** を選択。
<img width="704" alt="attend-form_04_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/24067fdc-1246-c8bb-38a7-708f930bd859.png">
スクリプトエディタ画面に切り替わるのでとりあえず適当な名前で保存。
<img width="443" alt="attend-form_04_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/bd79a8e7-ec7f-0d05-52c2-cd8d96cb5dc7.png">
<img width="487" alt="attend-form_04_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/e5384222-4a28-1f48-55f3-35027ad29fa3.png">

## 5. 入力フォームに必要なファイルをコピーペーストで作成する
ダウンロードした src フォルダ内の以下を適当なテキストエディタで開いて内容をコピーペーストする。

1. css.html
2. index.html
3. js.html
4. main.js（main.tsでは無いので注意）

### 5-1. ダウンロードファイル css.html の反映
メニューより **ファイル > New > html** を選択し ```css``` というファイルを作成する。
<img width="462" alt="attend-form_05_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/963fa5e9-8363-e665-837f-3050fb28b9e6.png">
<img width="459" alt="attend-form_05_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/a32b5d18-e931-73e0-e3d2-54da2382df8f.png">
作成時に自動生成されるコードは全て削除し、ダウンロードした ```css.html``` の内容を全てコピペする。
<img width="457" alt="attend-form_05_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/ef0ec175-f562-8ca4-cb80-8330f70d3d59.png">
<img width="549" alt="attend-form_05_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/3e731df2-8e42-d41a-9a29-72d732baa28a.png">

### 5-2. ダウンロードファイル index.html の反映
上記　5-1 の CSS と同様の手順で、メニューより **ファイル > New > html** を選択し ```index``` というファイルを作成、ダウンロードした ```index.html``` の内容を全てコピペする。

### 5-3. ダウンロードファイル js.html の反映
上記　5-1 の CSS と同様の手順で、メニューより **ファイル > New > html** を選択し ```js``` というファイルを作成、ダウンロードした ```js.html``` の内容を全てコピペする。

### 5-4. ダウンロードファイル main.js の反映
main.js（main.tsでは無いので注意）はスクリプトエディタ起動時に作成されている　```コード.gs``` に ```main.js``` の内容を全てコピペする。
<img width="638" alt="attend-form_05_5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/1f6ebceb-609a-1e90-de52-9b65b2610b9f.png">

### 6. アプリケーションの公開

### 6-1. アプリケーションの公開
メニューより **公開 > ウェブアプリケーションとして導入** を選択。
<img width="546" alt="attend-form_06_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/b9abce3b-e8c0-6249-6ba7-be7f18de261f.png">

### 6-2. 公開設定
公開設定は以下で
<img width="469" alt="attend-form_06_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/b3618cc9-801c-f1dc-1a2f-beb9de503733.png">

- Project version:
- Execute the app as: ```Me``` を選択
- Who has access to the app: ```全ユーザー``` を選択  
（```Anyone, even anonymous``` を選択すると回答者の Google アカウントは不要になるが、回答者の一意性は保てなくなる。）

公開すると WEB アプリの URL が表示されるのでコピーしてその URL にアクセス。
<img width="465" alt="attend-form_06_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/0285d2a5-761e-02f2-c98b-32ac933f4797.png">

### 6-3. スクリプトからのアクセス権限付与
初回のみスクリプトからのアクセス確認が行われるので ```REVIEW PERMISSIONS``` を選択。
<img width="533" alt="attend-form_06_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/252d15ac-28ec-d35c-0d49-c2d214c4a1ff.png">
権限許可を行うアカウントを選択。
<img width="467" alt="attend-form_06_5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/e83c116b-d8ea-1a85-2723-6d8b989a429a.png">
Google が作成したアプリでない警告が出るので左下の ```詳細``` をクリック。
<img width="669" alt="attend-form_06_6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/9b621b35-9d99-4777-a9c8-91790304d89f.png">
左下の ```XXXに移動``` を選択。
<img width="679" alt="attend-form_06_7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/139161cf-9be9-8fa5-e1ed-8b2f7065f76d.png">
アクセスの許可を行う。
<img width="701" alt="attend-form_06_8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/071591fd-be5c-8444-78bf-897d71ca7cfb.png">
以上でアプリ画面が表示されるようになる。
<img width="583" alt="attend-form_06_9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/98a3f767-fbd6-78de-e514-4b499d7eec56.png">

## 7. 日次自動データ更新設定
日次処理にて自動で授業パスワードの書き換え設定を行います。
メニューより **ファイル > 編集 > 現在のプロジェクトのトリガー** を選択。
<img width="272" alt="attend-form_07_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/9d921342-31b6-15dd-5bcb-06fadb8dc958.png">
トリガー一覧の画面に遷移したら右下の「トリガーを追加」ボタンを押し、表示された画面で以下のように設定する。
<img width="743" alt="attend-form_07_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/fd16c27c-aab6-f3b3-a0a3-229c862b7a5d.png">


これで毎日深夜に授業パスワードが更新されるようになる。

# 使い方
このアプリケーションはスプレッドシート内のシートのデータを利用しながら動作します。

## 基本設定シート
このシートの名称は変更不可。

- 授業として扱わないシート名（追加する場合は行末に追加してく）項目 >  
授業出席回答シートとして利用しないシート名を記入する。
- 格言の利用（利用する場合は する と入力）項目 >  
出席回答後に「格言」を表示するかを制御。
- パスワード日時変更（実行する場合は する と入力）項目 >  
「する」を入力していた場合は、日時バッチ処理にて授業パスワードが自動更新される
- パスワード文字列数 >  
タイマー処理時に授業パスワードを更新する処理が生成するパスワード文字列数を指定。
- 遅刻許容時間（分） >  
指定分以上遅れた場合に遅刻表示を行う。

## 名言シート
このシートの名称は変更不可。
基本設定シートにて「格言の利用（利用する場合は する と入力）」項目を「する」に設定した場合、回答後ここの名言がランダムで表示される。特に数の制限は無し。

## 授業名称1、授業名称2 シート
出席回答のフォーマットとなるシート。シート名が画面上にて授業名の選択プルダウンエリアに表示される。このシートを複製して授業を増やしていく。

- 開始時間、終了時間、授業パスワード項目 >  
該当する内容をそれぞれ入力。
- 授業参加生徒項目 >  
授業に参加する生徒の学籍番号と氏名を入力 >  
- 出席項目
出席回答時に自動で入力される。

# 気になる点
負荷テスト的なことはやってないので、数百人が同時にアクセスしたらどうなるのかが気になる。

# まとめ
サーバーレスでエクセルでのデータ取り扱いが出来るので上記の気になる点を除けば、若干導入ハードルが高いものの変なツールよりは扱いやすいのではと。Google App Script のプロジェクト内に zip ファイルポンとあげてスクリプト展開とか出来ればまだましなのだがやはりそんな都合良くはいかない。エンジニア向けには Clasp というコマンドベースでのファイル管理が出来るので、それを利用すればまだかなりマシになるので、その辺のお話はまた別の記事で。