rubyでgoogleカレンダーのイベントを取得するメモ

rubyでgoogleカレンダーのイベントを取得を試してみていたのでメモ

# 参照サイト

 * [rubyにてgoogleカレンダーの情報を取得する - Qiita](http://qiita.com/iron-breaker/items/2440c4ab41a482b1b096)
  * google-api-client gemではgoogle-apiコマンドの提供を止めているようだった
 * [GoogleアナリティクスAPIの承認を初回のみにする - さかなチキンぱん。](http://blog.naberon.jp/post/2013/08/27/google-analytics-api2/)
 * [Heroku上からService Account認証でGoogle APIにアクセスする - すぎゃーんメモ](http://d.hatena.ne.jp/sugyan/20130112/1357996092)

# アプリケーションの種類

google apiを利用するために登録するアプリケーションの種類としては以下の3つとなる。

 * ウェブアプリケーション
  * 今回さわってみてない
 * サービスアカウント
  * 秘密鍵で管理アカウントとは別アカウントとして認証、定期実行スクリプト向きかな
 * インストールされているアプリケーション
  * ブラウザでOauth認証、ユーザ操作のクライアント向きかな

# 事前準備

## 共通の事前準備

1. [https://cloud.google.com/console](https://cloud.google.com/console)にアクセスする
1. プロジェクトを作成する
1. プロジェクトの設定をする
 * 「APIと認証」の「API」でCalendar APIを有効にする
1. カレンダーIDの確認
 * イベントを取得したいカレンダーのIDをメモしておく(カレンダーの設定から確認可能)

## サービスアカウントの事前準備

1. プロジェクトの設定をする
 1. 「APIと認証」の「認証情報」で新しいクライアントIDを作成する
 1.  新しいクライアントIDの作成ではアプリケーションの種類でサービスアカウントを選択する
 1.  新しい公開キー/秘密キーのペアが作成されるので表示される秘密キーのパスワードをメモする
 1.  キーペア作成と同時に秘密キーをダウンロードがされるので保管する
1. カレンダーの設定をする
 1. [googleカレンダー](https://www.google.com/calendar) にアクセスする
 2. イベントを取得したいカレンダーの共有設定において、作成したサービスアカウントのメールアドレスでユーザを追加する

## インストールされているアプリケーションの事前準備

1. プロジェクトの設定をする
 * 「APIと認証」の「認証情報」で新しいクライアントIDを作成する
 * 新しいクライアントIDの作成ではアプリケーションの種類でインストールされているアプリケーションを選択する
 * 新しいクライアントIDの作成ではインストールされているアプリケーションの種類でその他を選択する
1. 作成したネイティブアプリケーションから情報を取得しておく
 * JSONをダウンロードでJSONファイルをダウンロードしておく

# サービスアカウントで取得

## スクリプト

* Gemfile

```rb
# A sample Gemfile
source "https://rubygems.org"

# gem "rails"
gem 'google-api-client'
```
* サンプルスクリプト

```rb
# coding: utf-8
require 'google/api_client'

client = Google::APIClient.new(:application_name => '')

# 認証
key = Google::APIClient::KeyUtils.load_from_pkcs12('[秘密キーのパス]', '[秘密キーのパスワード]')
client.authorization = Signet::OAuth2::Client.new(
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience => 'https://accounts.google.com/o/oauth2/token',
  :scope => 'https://www.googleapis.com/auth/calendar.readonly',
  :issuer => '[サービスアカウントのEmail address]',
  :signing_key => key)
client.authorization.fetch_access_token!

# イベント取得
cal = client.discovered_api('calendar', 'v3')

time_min = Time.utc(2014, 3, 1, 0).iso8601
time_max = Time.utc(2014, 3, 31, 0).iso8601
params = {'calendarId' => '[カレンダーID]',
          'orderBy' => 'startTime',
          'timeMax' => time_max,
          'timeMin' => time_min,
          'singleEvents' => 'True'}

result = client.execute(:api_method => cal.events.list,
                        :parameters => params)


# イベント格納
events = []
result.data.items.each do |item|
  events << item
end

# 出力
events.each do |event|
  printf("%s,%s\n",event.start.date,event.summary)
end
```

# インストールされているアプリケーションで取得

## スクリプト

* Gemfile

```rb
# A sample Gemfile
source "https://rubygems.org"

# gem "rails"
gem 'google-api-client'
```
* サンプルスクリプト

```rb
# coding: utf-8
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
require 'google/api_client/auth/file_storage'

client = Google::APIClient.new(:application_name => '')

# 認証
authfile = Google::APIClient::FileStorage.new('.authfile')
unless authfile.authorization.nil?
  client.authorization = authfile.authorization
else
  client_secrets = Google::APIClient::ClientSecrets.load("[ダウンロードしておいたjsonファイルのパス]")

  flow = Google::APIClient::InstalledAppFlow.new(
    :client_id => client_secrets.client_id,
    :client_secret => client_secrets.client_secret,
    :scope => ['https://www.googleapis.com/auth/calendar.readonly']
  )
  client.authorization = flow.authorize(authfile)
end

# イベント取得
cal = client.discovered_api('calendar', 'v3')

time_min = Time.utc(2014, 3, 1, 0).iso8601
time_max = Time.utc(2014, 3, 31, 0).iso8601
params = {'calendarId' => '[カレンダーID]',
          'orderBy' => 'startTime',
          'timeMax' => time_max,
          'timeMin' => time_min,
          'singleEvents' => 'True'}

result = client.execute(:api_method => cal.events.list,
                        :parameters => params)


# イベント格納
events = []
result.data.items.each do |item|
  events << item
end

# 出力
events.each do |event|
  printf("%s,%s\n",event.start.date,event.summary)
end
```

# 終日と時間指定のイベントについて

## 終日と時間指定のイベントの開始と終了の取得

取り方が違うので面倒くさい

 * 終日のイベントの開始日と終了日の取得(時間指定のイベントの場合はnil)

```rb
event.start.date # => Stringクラス
event.end.date   # => Stringクラス
```

 * 時間指定のイベントの開始日時と終了日時の取得(nil)

```rb
event.start.date_time # => Timeクラス
event.end.date_time   # => Timeクラス
```

## 終日と時間指定のイベントの検索について

終日イベントの開始/終了時刻はUTC扱い、
時間指定イベントの開始/終了時刻はローカル時刻で検索にひっかかるらしくややこしい。

* 例えば2014年5月23日終日イベントは以下の検索期間にひっかかる
 * 開始 2014/05/23 00:00:00 UTC (2014/05/23 9:00:00 +9:00)
 * 終了 2014/05/24 00:00:00 UTC (2014/05/23 9:00:00 +9:00)

* 時間指定だと指定したローカル時間内の検索でひっかかる