Google Calender API v3をChrome Extensionから使ってイベント登録する。

2015/10/27追記

現バージョンのRight Click to Calendarはこの記事で使用している方法で認証を実装していません。(chrome.identity APIを使用しています。)
詳細は次の記事を参照してください。 | Right-Click to CalendarのOAuth2認証系をchrome.identity APIで修正。 – return $lock;


GoogleカレンダーAPIバージョン3登場 – 今までのAPIは非推奨 | マイナビニュース
Google Calender API v1とv2が2014年の11月くらいに使えなくなることと、新しいAPIの勉強も兼ねて去年の10月末にカレンダー用の拡張を更新しました。
Chrome ウェブストア – Right-Click to Calendar
その時は時間がなかったのと、使ってるライブラリの仕様を理解しないで作ったので、何度も再認証が必要になるという意味が分からないことになってました。

今回は使用したライブラリの使い方も兼ねてイベント登録の方法を書きたいと思います。
ライブラリは以下を使用しました。
borismus/oauth2-extensions · GitHub

長いので続きで書きます。

あと、これとは別にカレンダー用のスクリプトを書いたのですが、自分が大学の時にいた研究室の共用カレンダーに謎の文字列を爆撃してて死にそうになりました。
カレンダーのIDを自動で取得+自動で投稿する際は気をつけないと大変なことになるので気をつけてください。

Client IDを取得する

Google APIs ConsoleにアクセスしてClient IDを取得します。
手順は以下のサイトがまとまっていてわかりやすかったです。
天使やカイザーと呼ばれて » OAuth2.0によるGoogle+ APIのアクセス方法

oauth2.jsを使ってカレンダーに登録する

oauth2.jsを使用してGoogle Calender API v3を叩いてみます。
まずmanifest.jsonをいじっておきます。

//manifest.jsonに以下を追加
   "content_scripts":[{
        "matches":["http://www.google.com/robots.txt*"],
        "js":["oauth2/oauth2_inject.js"],
        "run_at":"document_start"
    }],
   "permissions": [ "tabs", "contextMenus",
        "http://www.google.com/*",
        "https://www.google.com/*",
        "https://www.googleapis.com/*",
        "https://accounts.google.com/o/oauth2/token"
    ],
    "web_accessible_resources": [
        "oauth2/oauth2.html"
    ]

スクリプト本体。

var google = new OAuth2('google', { //今回はGoogleのAPIにアクセスするためgoogleを指定
	client_id: 'Client ID',
	client_secret: 'Client secret',
	api_scope: 'https://www.googleapis.com/auth/calendar' //スコープはGoogleカレンダー
});

google.authorize(function() {

	var body = JSON.stringify({
		"description": "詳細説明",
		"summary": "タイトル",
		"transparency": "opaque",
		"status": "confirmed",
		"start" : {"dateTime":st}, //開始時間
		//RFC3339形式で記述。日本時間なら2014-02-16T16:00:00+09:00
		//終日設定の場合、YYYY-MM-DDのみで指定し、実際の終了日に+1する。
		"end": {"dateTime":st} //終了時間
	});

	var xhr = new XMLHttpRequest();
	xhr.onreadystatechange =  function() { //レスポンスによって処理を振り分ける
		if(xhr.readyState == 4) {
			if(xhr.status == 200) {
				alert("成功しました");

            		}
			else{
				var data  =  JSON.parse(xhr.responseText);
				alert("(Error)" + data.error.code + " : " + data.error.message);
			}
		}
	}

	xhr.open('POST',
		"https://www.googleapis.com/calendar/v3/calendars/"+ カレンダーのID +"/events",
		true);
	xhr.setRequestHeader('Content-Type', 'application/json');
	xhr.setRequestHeader('Authorization', 'Bearer ' + google.getAccessToken()); //アクセストークンの取得
	xhr.send(body);
});

AccessTokenが取得できたらイベントが登録されます。statusとかパラメータの詳細は以下を参照してください。
Google Calendar API – Google Apps Platform — Google Developers

oauth2.jsを修正する

OAuth2.0ではexpires_inの値の時間(秒)しかAccessTokenが生存しません。
トークンの生存時間を経過した場合、一番最初にAccessTokenと一緒に取得したRefreshTokenを使用して再度AccessTokenを取得します。(RefreshTokenが存在しないなら再度認証が必要になります)
GoogleのAPIは最初に取得したRefreshTokenをずっと使い続けるため、2度目のAccessToken取得問い合わせの時にはRefreshTokenが返ってこないようです。
(※私が確認した範囲ではそうだったのですが、仕様的にこう決まってるのかはわからないです。ドキュメントを見ても、レスポンスにrefreshTokenが含まれているように見えませんが、よくわかりません。)
oauth2.jsはRefreshTokenで再度AccessTokenを取得した際に、RefreshTokenの値がレスポンス内に含まれている前提でコードを書いているため、このままだとRefreshTokenの値がundefinedで上書きされて再度認証が必要になってしまいます。
再度AccessTokenを取得した際に、受け取ったレスポンスでrefreshTokenの値が空なら、値を上書きしないようにコードを修正する必要があります。
気づいた人がいつかpullRequestするんじゃないかな…。
Google APIのRefreshTokenの扱いは以下のサイトがわかりやすかったです。
天使やカイザーと呼ばれて » Google OAuth2 Web Server Profileでのリフレッシュトークン

とりあえず私が書いた修正は以下です。

OAuth2.prototype.authorize = function(callback) {
  var that = this;
  OAuth2.loadAdapter(that.adapterName, function() {
    //中略
      if (data.refreshToken) {
        that.refreshAccessToken(data.refreshToken, function(at, exp, re) {
          var newData = that.get();
          newData.accessTokenDate = new Date().valueOf();
          newData.accessToken = at;
          newData.expiresIn = exp;
		  //リフレッシュトークンが空でない場合のみ場合更新。ここを修正したよ。
		  if(re) {
          	     newData.refreshToken = re;
		  }
          that.setSource(newData);
     }
     //中略
};

OAuth2.prototype.clearAccessToken = function() {
  this.clear('accessToken');
  this.clear('refreshToken');//refreshTokenが有効期限切れだった場合、refreshTokenが上書きできないと詰むので救済措置
};

カレンダーの一覧を取得する

おまけ。APIの使用例。

google.authorize(function(){
	var xhr = new XMLHttpRequest();
	
	xhr.onreadystatechange =  function() {
		if(xhr.readyState == 4) {
			if(xhr.status == 200) {
				var data = JSON.parse(xhr.responseText);
				//console.log(data);
				var list = data.items;
				for (var i = 0; i < list.length; i++){
					console.log(list[i].summary + " " + list[i].id);
				}

			}
			else {
				var data  =  JSON.parse(xhr.responseText);
				//console.log(data);
				alert("リストの取得に失敗しました。" + data.error.code + " : " + data.error.message);
			}
		}
	}

	xhr.open('GET',
		"https://www.googleapis.com/calendar/v3/users/me/calendarList?minAccessRole=owner",
	true);
	xhr.setRequestHeader('Content-Type', 'application/json');
	xhr.setRequestHeader('Authorization', 'Bearer ' + google.getAccessToken());
	xhr.send(null);
});

これで右クリックした時の文字列をそのままカレンダーに送れば、同じ拡張が作れます。
詳しくはGithubを参照してください。

コメントを残す

お手数ですが半角数字で計算結果を入力してください。 *