【Google Apps Script】その6　スプレッドシートを誰がいつ開いたか記録する

この記事は[Google Apps Scriptを実例交えて基礎からざっくり学ぶ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/gas_beginner)　6日目の記事です。

本アドベントカレンダーは@rt_pの個人プロジェクトですが、筆者は[Ateam Brides Inc. Advent Calendar 2017](https://qiita.com/advent-calendar/2017/a-t-brides)にも参加しています。そちらでも出張版記事を書いているので、覗いていただけると嬉しいです。

# はじめに

今回は、スプレッドシートを誰がいつ開いたか自動的に記録する仕組みを入れていきます。

# 単純なアクセスログ機能実装

スプレッドシートを新規作成し、シート名（シート1）を変更し「アクセスログ」というシートを作ります。

その後スクリプトエディタを開き、以下コードに置き換えて、まずは実行します。
スクリプトエディタの開き方や*承認が必要です*メッセージが出た際の対処法が分からない場合は
[アドベントカレンダー1日目のHello, world!記事](https://qiita.com/rf_p/items/0535ec495df8f9d2b894)をご参照ください。

```javascript:login_user.gs
function onOpen(e) {
  var sheet = SpreadsheetApp.getActive().getSheetByName('アクセスログ');
  var now   = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
  var email = Session.getActiveUser().getEmail();
  sheet.appendRow([now, email]);
}
```

スプレッドシート画面でF5を押すと画面更新になり、「スプレッドシートを開いた」判定となり`onOpen(e)`イベントが発火してアクセスログに記録がされるはずです。

![login.PNG](https://qiita-image-store.s3.amazonaws.com/0/199678/a5010d7a-a22b-3359-b9e2-7ea3bad8743b.png)

スプレッドシートを開いた時に自動実行される設定は、`onOpen(e)`という関数を作ることで実現できます。

> onOpen(e)

https://developers.google.com/apps-script/reference/script/spreadsheet-trigger-builder#onOpen()

また、実行ユーザーのメールアドレスは`Session.getActiveUser().getEmail()`で取得できます。

> getActiveUser() 

https://developers.google.com/apps-script/reference/base/session#getActiveUser()

F5でスプレッドシートを開き直しても記録が付かない場合、以下ご確認ください。

- シート名は合っていますか？
- スプレッドシート操作処理やログインユーザーの権限を許可していない可能性があります。スクリプトエディタで`onOpen()`の実行をしてみてください。*許可を実行*が出た場合は許可をすれば動くはずです。

![execute.png](https://qiita-image-store.s3.amazonaws.com/0/199678/10069fc4-c9a0-0aee-518a-69df01214e80.png)

# ユーザーごとの最終閲覧日時、閲覧回数を記録する

[昨日の記事](https://qiita.com/rf_p/items/f423ed2b23b789b2ebe9)を参考にすると、ユーザーごとの最終閲覧日時や閲覧回数を記録するシステムもサクッとできます。

「閲覧記録」というシートを作り、1行目に下記内容をコピペしてください。

||A|B|C|
|:-:|:-:|:-:|:-:|
|1|メールアドレス|最終閲覧|閲覧回数|

スクリプトエディタを開いて以下ソースを貼り付け実行します。

```javascript:open_count.gs
function onOpen(e) {
  var sheet = SpreadsheetApp.getActive().getSheetByName('閲覧記録');
  insertOrUpdate(sheet, Session.getActiveUser().getEmail());
}

// 行の存在に応じて追加もしくは更新を行う
function insertOrUpdate(sheet, email) {
  var row = findRow(sheet, email);
  var now = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
  if (row) { // 行が見つかったら更新
    var loginCount = sheet.getRange(row, 3).getValue();
    sheet.getRange(row, 1, 1, 3).setValues([[email, now, loginCount + 1]]);
  } else { // 行が見つからなかったら新しくデータを挿入
    sheet.appendRow([email, now, 1]);
  }
}

// 行番号を返す
function findRow(sheet, email) {
  var values = sheet.getDataRange().getValues();

  for (var i = values.length - 1; i > 0; i--) {
    var dataEmail = values[i][0]
    if (dataEmail == email) {
      return i + 1; // 配列のキーは0から始まり、行数は1から始まるのでズレを直す
    }
  }
  return false;
}
```

[昨日の記事](https://qiita.com/rf_p/items/f423ed2b23b789b2ebe9)のソースを流用しているので降順に調べていたりしますが、今回は特別な意図はないです。

うまく動けば、以下のように動作します。

![loginCount.PNG](https://qiita-image-store.s3.amazonaws.com/0/199678/07dd255d-9e48-1093-f3e0-f950d745a612.png)


もし
```TypeError: null のメソッド「getDataRange」を呼び出せません。```
というエラーが出た場合、シートオブジェクトの取得に失敗している可能性があります。
「閲覧記録」というシート名になっているかご確認ください。

<img width="291" alt="シート名" src="https://qiita-image-store.s3.amazonaws.com/0/199678/67fba63b-9311-b2ab-6412-89de82b368ff.png">


本日は以上です。

# おわりに

今回の方法は閲覧者に編集権限があると簡単に改竄できてしまうので、そこまでの意味は無いかもしれないです。
ですがあらゆる応用の利く知識だと思うので、是非試してみてください。

本アドベントカレンダーは、1日目～9日目あたりは基礎編でGASに関する基本的な操作を紹介していきます。
10日目以降は応用編ということで、実際に作ったアプリケーションとそれに関する技術の紹介になります。お楽しみに！

# 明日

[【Google Apps Script】その7　ビットコインの最終取引価格を取得する](https://qiita.com/rf_p/items/e903593033b76566daf0)
となります。
実際にスプレッドシートとデータをやり取りする方法をご紹介します。

前の記事
[【Google Apps Script】その5　該当する日付の行が存在したら上書き、存在しなかったら挿入する](https://qiita.com/rf_p/items/f423ed2b23b789b2ebe9)
次の記事
[【Google Apps Script】その7　ビットコインの最終取引価格を取得する](https://qiita.com/rf_p/items/e903593033b76566daf0)