GoogleApps

2013年11月28日 (木)

続・ApexからGoogle Calendarを操作する

どもども。先週の記事「ApexからGoogle Calendarを操作する」の続きです。

といっても厳密には続いてないんですが。。。(^^;

 

★Google Data API Toolkitのお話

さて、先週の記事ではぶつぶつ文句を言いながらも、「Toolkitで一通りカレンダーいじれるんじゃないの?」という結論に達しました。

しかし、今週になってやっぱり使うのを止めました。(--

イベント作成時に使用するオブジェクトが何故かSalesforceのEventオブジェクトでなんかビミョーという話は前回さんざんしましたが、実際のところはタイトル、日時、場所、説明さえ設定できれば良かったのでそれで事足りるはずだったんです。

なのに、実際に試してみると何故か場所が設定されない。。。

あれ、なんでだ?自分のコードではちゃんとEvent#Locationに値を設定してるし。。。

。。。

。。。て、CalendarService#insertEventsで引数に渡したLocationがコピーされてねー

そらあかんわ。。。(--

 

□□□□

さて、どうしたものか?

直接修正するなら1行で直せる程度のものですが、それも気が進まない。

とりあえず元のリポジトリを探してみたところ。。。

https://code.google.com/p/apex-google-data/

うーん、もう3年近くメンテされた形跡が無い。。。

その間にAPIもXMLベースのV2からRESTベースのV3に変わっているわけで、これはもうこの先も放置なんだろうなぁ。。。(--

 

★V3 APIの使用を検討してみる

さてさて、ソースまるごとフォークして自分でメンテすることも考えましたが、それやろうとすると直したいところが多すぎる。(--

それに今は面倒なXMLを使わなくてもお手軽にRESTで実行できるV3 APIがあるんだよ!

ということでとりあえずV3のドキュメントを読んでみることにしました。

https://developers.google.com/google-apps/calendar/

うん、やっぱりReference見ただけでもV2よりもはるかに簡単に使えそう。それにDeprecation Policy見ると旧APIは2015年4月までは使えるけど、そっから先は知らん!と書いてるようにも思えるしこれはやっぱりどうでもV3を使うべきでしょう。

 

★Service Account認証

とりあえずApex用のV3ライブラリを探してみるけど、どうも無いっぽい。まぁ「Salesforce Google API」みたいなワードで検索すると一撃でSalesforce公式(?)っぽいToolkitのページが見つかるからその先に踏み込む人もあんまりいないんだろう。。。2015年4月以降をどうやって乗り切るつもりかは知らないけど。。。(--

V3 APIをざっと眺めるかぎり少なくともAPI本体のREST部分はものすごくシンプルなので自分で作るとしてもそんなにたいしたことはなさそう。

問題は認証部分。

V3 APIではClientLoginは廃止されたので今までのように気軽に個人のユーザーアカウントとパスワードでログインしてAPIをたたくことはできない。

そうはいってもサーバーアプリの場合ユーザーとは無関係の固定のアカウントでAPIを叩きたい場合も多い訳で、そういう場合はService Account認証というのを使うらしい。

https://developers.google.com/accounts/docs/OAuth2ServiceAccount

これは連携用のアプリケーションを登録して、そこで発行されたClientIDとPrivateKeyを使用して認証するという方法らしい。

下に詳細な実行手順が書かれているけど要するに

  • JSONで認証用の文字列(JWTというらしい)を組み立てて、
  • Base64でエンコードして、
  • 電子署名を追加して、
  • Http POSTで投げる

とすれば良いらしい。(どうでもいいんだけどこれもOAuth2の一種なの?一般的なOAuthとまったく類似点が無い気がするんだけど。。。)

ドキュメント読んでると3回位「悪いことは言わないから自分で実装したりせずに既存のライブラリ使っとけ!」と、言われるんだけどApex用のライブラリは無いんだよ。。。(--

ApexにもJSON、EncodingUtil、Crypto、と必要な道具立ては揃ってるっぽいから多分作れるんじゃないかな?

。。。とりあえず作ってみるか!

 

★で、作ってみた

けど無理でした。。。(--

認証文字列を作るところは良いんだけど最後の最後で署名が。。。(--

ここではSHA256withRSAで電子署名する必要があるんだけど、ApexのCrypto#signではSHA1withRSAでしか署名できないという罠。。。(--

マジでかー(--

ここさえ突破すれば終わりなのにこれはどうしようもねーよ。。。

どうしよう。。。

。。。しょうがないから、外に署名だけするサーバー建てるか。。。

 

★まさかのHeroku登場

作りました。

https://github.com/shunjikonishi/sign-server

ホントにPOSTされた文字列に電子署名して返すだけのアプリ。HerokuにpushしてConfigにBase64エンコードした秘密鍵を設定すれば使えます。

。。。(^^;;;

なんたるリソースの無駄遣い!数年前にはここまで単機能のサーバを気軽に作る日が来るとは思いもしなかったよ。

さすがにちょっとやりすぎなんじゃないの?という気がしなくもないけど、このアリサマはSalesforceがSHA256をサポートしていないのが原因なんでまぁいいか。(^^;

ということで、一応動くGoogle Calendar API V3のラッパーを作ることができました。

https://github.com/shunjikonishi/apex-google-api

次回はこいつの使い方を解説します。(^^v

 

□□□□

蛇足

実はSalesforceにもJWTを使った認証があるということを今回調べてて知りました。

SalesforceのAPIはIDとPassword(とSecurityToken)の認証で普通に使えるからこれ使う人いるのか?という疑問はまぁおいとくとしてもそこではSHA256での検証もやってるっぽい。

そこまでやってるなら後はそれをCryptoにもぶちこめば良いだけなんでとっととやって欲しい。。。(--

たったそれだけでGoogle V3 APIが自由に使えるかどうかが変わってくるんだからホント頼むよ。。。m(_ _)m

2013年7月 2日 (火)

Google Spreadsheetで特定のシートに直リンクする

こんにちは

昨日からGoogle Spreadsheet APIで作成したシートに直リンクするURLを生成したくて色々調べてました。

「API使うならそれくらい簡単にできるんじゃないの?」って思うでしょ?えぇ、僕もそう思いました。

しかし、これが。。。(--

一応最終的にはできたんですが、その方法が「マジですか?!」とかなり愕然とするものだったのでここにメモとして残しておきます。

 

★Google SpreadsheetのURL

実際にシートを作ってみながらブラウザのアドレスバーを確認するとすぐにわかりますが、GoogleSpreadsheetのURLは以下のような形式となっています。

 

https://docs.google.com/spreadsheet/ccc?key=xxxxxxxx#gid=1

 

アカウントが組織に属している場合は若干URLのパスが変わりますが、ここで重要なのは

  • URLパラメータの「key」がスプレッドシートを特定するキーとなっている
  • URLパラメータの「gid」がワークシートを特定するキーとなっている

という点です。ちなみにgidはおそらく単純にシートの作成順による連番です。途中でワークシートの削除や移動があった場合でもgidが振り直されることはなく単純なインクリメントで生成されます。

要するにAPIでこのkeyとgidが取得できれば、URLを組み立てることができるわけです。楽勝です。

 

★Google Spreadsheet APIを使う

今回アプリはPlay2で作成しているのでJavaのAPIを使用しました。Google Spreadsheet APIの使い方については良記事がたくさんあるので割愛しますが、スプレッドシート、ワークシートの情報はそれぞれ、

  • SpreadsheetEntry
  • WorksheetEntry

というクラスから取得できます。

これらのAPIリファレンスを眺めると目的とする情報はそれぞれ

  • SpreadsheetEntry#getSpreadsheetLink
  • WorksheetEntry#getId

というメソッドから取得できそうです。楽勝です。

 

★gidが取れないことに気がつく

さて、ここまで来たら後は試すだけですがまず、SpreadsheetEntry#getSpreadsheetLinkは完全に目的にマッチするものでした。keyだけでなくスキームから始まる完全なURLとして取得できます。楽勝楽勝(^^v

が、WorksheetEntry#getIdの方はgidではなく、こちらも「https://...」で始まるURIでした。そもそもgetIdメソッドはWorksheetEntryクラスのメソッドではなく、その基底クラスであるBaseEntryクラスのメソッドなのでSpreadsheetだけでなく他のGoogle Appsオブジェクトまで全部含めたIdentifierになっているわけです。同一のスプレッドシート内でのみユニークとなるgidとは意味合いが異なります。

それではgidはどうやって取得するのかと言うと。。。これはいろいろと試行錯誤したんですが、どうもそのためのメソッドは無いようでした。(--

最終的にはRESTのレスポンスXMLの中にそれっぽい値が入っていないことから、どうやら本当に無いらしいと結論しました。

 

★シート名でのリンクを試みる

APIでgidが取れないとなると、どうやって直リンクすれば良いのでしょうか?シートの削除や移動があるのでgidは単純な連番とはなりません。世の中にGoogleSpreadsheetの特定シートに直リンクしたい人は山ほどいるはずです。

。。。と、あおってはみたものの実際のところはここまでにさんざん検索をかけているのでシート名でリンクする( = URLパラメータに「sheet=xxxxx」を指定する)方法があるらしいことはわかってはいたんです。

が、これ途中でも試してたんですが何故かうまく動きません。検索結果にも「動かねー」という怨嗟の声が山ほどあるし、公式ドキュメントにもそれができるという記述が見つけられないので結局この方向もあきらめました。。。(--

 

★できないはずがないとあがく

手詰まりです。

絶対に必要と言う機能でもないし、もうあきらめようかとも思ったんですがこんな簡単なことができないということがどうしても信じられず検索を続けました。

そして。。。ついに、見つけた解答がこれです。

http://stackoverflow.com/questions/11290337/how-to-convert-google-spreadsheets-worksheet-string-id-to-integer-index-gid

一番最後にコード例が載っていますが、要約するとこうです。

 

  1. WorksheetEntry#getIdから最後の「/」以降の3桁を取得する
  2. その文字列を36進数として数値に変換する
  3. その数値と31578のXORを取るとgidが取得できる

 

。。。(--

。。。。。(--;;;

。。。できた。。。できたけどっ!

36進数って何だよ?!31578は一体どこから出てきた???

長くこの業界にいるけど、こんなの初めて見たよ!!!

動きはしたけどなんだか全然釈然としない。誰かこのアルゴリズムの根拠の分かる人がいたら教えてください。m(_ _)m

採用情報

株式会社フレクトでは、事業拡大のため、
Salesforce/Force.comのアプリケーション
開発
HerokuやAWSなどのクラウドプラッ
トフォーム上でのWebアプリケーション開発

エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみた
い方、是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、
セールスフォースパートナーです。
heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。
Powered by Six Apart