Skip to main content

2 posts tagged with "Google Apps Script"

View All Tags

· 9 min read

今日(7/6 水)は勉強会で発表してきました。 資料は社名や人名が含まれてるところがあるので、調整後に後日公開するかも? 参加してくださった方には別途お送りする予定。

もくじ

話した内容はこんな感じ。
  1. Google App Engine概要(の概要)
  2. Scalaの紹介
  3. Google App Engine + Scalaで作ったTwitter bot
  4. ジオサービス
  5. apps script紹介

きっかけ

勉強会で話すきっかけになったのは職場で一緒に仕事をしている人に、 「勉強会で話してみない?」 と言われたこと。 いい機会だし、話してみるか…ということで話すことにしました。 この勉強会で聞いてくださったのは他社の方々。会社間の契約はあるし、数名は面識があるので、知らないわけじゃないけど、聞いてくださる方々は面識ないし、そもそも自社ではないのです。

初めは「20人くらいだし、話す内容はなんでもいいよ」と気楽に言われたので、気楽に考えてました。 「他の人は何を話すんだろ〜?」くらい気楽に。

少しずつ話が具体的になるに連れ、勉強会に近づくに連れ、すこ〜しずつ話が大きくなり、30人ほど出席するという反響ぶり!(人が増えたらビビるやん) 告知メールでは "講師" と書いてあるし、社内Ustreamするとか…広がりすぎですっ!(機器の都合でUst配信無くなったけど) 講師っていうか、情報共有しましょうよ〜みたいな感じにしか捉えてなかったのに、話す人俺だけ。

さらに、追い打ちをかけるかの如く、社内から3人ほど聞きにくると…Σ(゚Д゚) 社長来るし、Google API Expert来るし、賢い海藻猫来るし、もう大変。 Expertいる前でApp Engineの話をするってどうなのよ!? …と思っていたけど、実際、当日になったら、あまり顔を合わせないといえども自社の人だし、心強くも感じられるものでしたε-(´∀`*)ホッ

資料作成

今回はPreziを使って発表したんだけど、資料作成には結構時間かかりました。 まずはiPad2に思っていることを描き出し、それをマインドマップにまとめ、最終的にPreziに落としこむという手順。 iPad2に書いた時点で40ページ超えてて、それをマインドマップに書いたら結構広がった。 さらにPreziにしたらパスの数は130くらいに行きそうな勢いだったので、急遽方法を変え、Scalaの説明はソースコードのみで行いました。 これでも、パスの数は129…って、130くらいになりそうなのを抑えてもまだまだ多かったか...orz

発表

発表自体は、個人的には最低ラインは確保できたかな…と思ってる。 最低ラインですみません…なんだけど、自分としてはなんとか最低ラインまで持って行けて一安心…的な感じ。

事前に2回ほど通しで話してみたけど、ちょっとこれでは質がいいとは言えないな…と思っていたし、自分でも納得出来ていなかった。 今日は自分なりに気になっていたことを気を付けていたこともあって、気になっていた部分はだいぶ減ったと思ってる。 時間配分は前半少し取り過ぎた。聞いてくれる方がいるからには、伝えるところは伝えておきたいな…と思って、追加でちょっと話をした部分が追加の時間だろう。 そんなわけで、後半はちょっと急ぎ気味に進め、ほぼ1時間。 時間的にはよかったけど、時間的にも精神的にも、もう少し落ち着いて話をしたいところだ。 それでも、事前に話した時よりは落ち着いて話せたと思っている。

内容は目次に書いた項目を1時間くらいで話す予定だったため、どうしても説明が薄くなりがち。 今回のターゲットはApp EngineもScalaもほとんど知らない人だろうという想定だったから、あまり深いところは話さず、それらを組み合わせたbotの話や、ジオサービスの話を取り入れ、少しは楽しんでもらえたら…と思っていたんだけど、どうだったんだろう?

内容の薄さと話をカバーすべく、Preziを使ってよかったのかも?これについては少しは楽しめてもらえたと思う。 最後に話したapps scriptは興味がないのか、馴染みがないのか、懇親会でも話が出なかったなぁ。 App Engineよりも、Scalaよりも、Apps Scriptが一番お手軽なんだけど、そんな話をしなかったからか(^^;

まとめ

内容はともかく、練習していた時よりも本番の方が安定して話せたということがよかった。練習の方がよかったら悔やまれる。

仮に、発表がうまくいかなかったとしても、やらないよりやった方がいい経験になるし、自分が楽しまないと見ている人も楽しくないだろうし…ということで、ネガティブなことは考えず、一緒に楽しむことを考えていたのが一番大きいかも。

そんなわけで、自分本位に考えていたところもあり、お聞き苦しいところも多々あったと思いますが、ありがとうございました!

解放

6月はほぼ資料作成ばかりやってたから、やっと解放された感じ(笑) インラインのフレームを交換したいし、スラックラインを注文したいし、サイト構成などなど、色々と考えねば…。 少しずつ色々と進める予定。

· 6 min read

先日、Google Apps ScriptからGoogle App Engineのサービスを利用する際に管理者の判断を行いたかったのでそれについて調べていた。 自分ではある程度解決したと思っている。

発端

そんなとき、こんなmentionが飛んできた。

来月辺り、@vvakameにふやかされる可能性があるので、今のうちに親切に恩を売っておく目的でこれ書いてる。

今のところこうなのかな?と思っている

以下の確認はスクリプトエディタから実行したので、トリガーなどからの実行は未確認です。 テスト中なので一部は "???" 表記にしてます。

まずはOAuthによる認証について。

  • ???.appspot.comではOAuthによる認証が出来た
  • ???.mydomain.xyzではOAuthによる認証が出来なかった

続いて、OAuthが通った場合のユーザ情報について。

  • AppEngine側ではOAuthServiceFactoryからユーザ情報が取得できた
  • AppEngine側ではUserServiceFactoryからユーザ情報が取得できなかった
  • UserServiceFactoryからUser情報が取得できなかったので、管理者かどうか判断できない

所感

mydomain.xyzで認証が通らないのはそのドメインの信頼性を確保できないからということなのだろうか? だとしたら、証明書を登録することによってmydomain.xyzでもOAuthによる認証が通るのかな?と思いつつ、試してない。時間があったらやってみたいところだけど、優先度が下がってる。 mydomain.xyzのToken(key, secret)使ってても、appspot.comでの認証が通ってる。mydomain.xyzはDNSでgoogleの方を向いているから結局は同じということなのだろうか?これはなんとなくありのような、無しのような、微妙な感覚。

ソースコード(apps script)

以下がapps scriptのソースコード。
function initApps_() {
ScriptProperties.setProperty("http", "https://");
ScriptProperties.setProperty("appid", "?????");
ScriptProperties.setProperty("d", "appspot.com");
ScriptProperties.setProperty("consumerKey", "?????.appspot.com");
ScriptProperties.setProperty("consumerSecret", "appssecret");
}

function initMydomain_() {
ScriptProperties.setProperty("http", "https://");
ScriptProperties.setProperty("appid", "?????");
ScriptProperties.setProperty("d", "mydomain.xyz");
ScriptProperties.setProperty("consumerKey", "?????.mydomain.xyz");
ScriptProperties.setProperty("sonsumerSecret", "mydomainsecret");
}

function initOAuthUrl_() {
var http = ScriptProperties.getProperty("http");
var appid = ScriptProperties.getProperty("appid");
var domain = ScriptProperties.getProperty("d");

var ah = http + appid + "." + domain + "/_ah/";
ScriptProperties.setProperty("accessTokenUrl", ah + "OAuthGetAccessToken");
ScriptProperties.setProperty("requestTokenUrl", ah + "OAuthGetRequestToken");
ScriptProperties.setProperty("authUrl", ah + "OAuthAuthorizeToken");
}

// appspotへOAuth --> oauth: ken@mydomain.xyz / user: unknown
function oAuthAppspot() {
initApps_();
var url = "http://?????.appspot.com/oauth/auth";
oAuthTest_(url);
}

// mydomainへOAuth --> Unknown(OAuthRequestExceptionが発生している)
function oAuthmydomain.xyz() {
initMydomain_();
var url = "http://?????.mydomain.xyz/oauth/auth";
oAuthTest_(url);
}

// appspotへOAuth(mydomainのtoken) --> oauth: ken@mydomain.xyz / user: unknown
function oAuthAppspotMyKey() {
initMydomain_();
var url = "http://?????.appspot.com/oauth/auth";
oAuthTest_(url);
}

// mydomainへOAuth(appspotのtoken) --> Unknown(OAuthRequestExceptionが発生している)
function oAuthmydomain.xyzAppspotKey() {
initApps_();
var url = "http://?????.mydomain.xyz/oauth/auth";
oAuthTest_(url);
}

function oAuthTest_(url) {
url += "?" + Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd HH:mm:ss");
Logger.log(url);
try {
var response = UrlFetchApp.fetch(url, option_());
Browser.msgBox(response.getContentText());
} catch(e) {
var msg = "";
for (var i in e) {
msg += e[i] + "n";
}
Browser.msgBox(msg);
}
}

function option_() {
initOAuthUrl_();
var oAuthServiceName = "apps";
var accessTokenUrl = ScriptProperties.getProperty("accessTokenUrl");
var requestTokenUrl = ScriptProperties.getProperty("requestTokenUrl");
var authUrl = ScriptProperties.getProperty("authUrl");
var key = ScriptProperties.getProperty("consumerKey");
var secret = ScriptProperties.getProperty("consumerSecret");

var oAuthConfig = UrlFetchApp.addOAuthService(oAuthServiceName);
oAuthConfig.setAccessTokenUrl(accessTokenUrl);
oAuthConfig.setRequestTokenUrl(requestTokenUrl);
oAuthConfig.setAuthorizationUrl(authUrl);
oAuthConfig.setConsumerKey(key);
oAuthConfig.setConsumerSecret(secret);

var options = {
"oAuthServiceName" : oAuthServiceName,
"oAuthUseToken" : "always"
};

return options;
}

oAuthTest_メソッドでURLに時刻を付けてるのは、キャッシュを返されるような動作があったので、それを回避するため。

スクリプトでひとつ疑問。 ScriptPropertiesで "domain" をキーに指定した場合、getPropertyするとnullになる。これはうちだけ?

ソースコード(App Engine)

以下がApp Engineのソースコード。 言語はJavaじゃなくて、Scala使ってるし、オレオレフレームワーク使ってる。
class OauthController(request:Request, response:Response) extends Controller(request, response) {

def auth = {
try {
val oauth = OAuthServiceFactory.getOAuthService();
val oauthUser = oauth.getCurrentUser match {
case user if user != null => user.getNickname;
case _ => "unknown"
}
val user = UserServiceFactory.getUserService.getCurrentUser match {
case user if user != null => user.getNickname
case _ => "unknown"
}
val msg = "oauth: %s / user: %s".format(oauthUser, user)
response.getWriter.write(msg)
} catch {
case e:OAuthRequestException =>
response.getWriter.write(e.getMessage)
}
}
}

まとめ

今のところ、管理者かどうか判断は出来ていないけど、ユーザは判断できているので、それで凌ごうと思っている。必ずしも開発者(管理者)がアプリの管理者とは限らないので、これはこれでいいや…と思ってる。 お仕事じゃないので、うるさく言う人いないし(笑)