2014年2月7日金曜日

[force.com] 変更セットとかパッケージが到着するのを監視して通知する方法

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
変更セットやパッケージがなかなかデプロイしたいインスタンスに到着しなくてイライラやきもきしたことはないでしょうか?

何度も⌘R(またはF5)を押して時間を無駄にしないでいい方法を見つけました。

Auto Refresh Plus(以後ARP)というChrome拡張を使うと、指定した秒数で自動的にページをリロードしてくれて、指定したキーワードがページ内に現れたら通知をしてくれます!!!

まずは、Chrome Web Storeから、ARPをインストールします。
https://chrome.google.com/webstore/detail/auto-refresh-plus/oilipfekkmncanaajkapbpancpelijih

設定画面で、キーワードをウォッチする機能、Page Monitorを有効にします。
気づきやすい様に通知時に音も鳴る様にしておきます。

準備はこれで完了です。

使い方


sandboxから、本番環境に変更セットを送ります。

本番環境で、「受信変更セット」のページを開きます。まだ来てないですね。ここでARPの出番です。

あまり負荷をかけない様に1分間隔くらいにして、Page Monitorのキーワードには変更セット名を入れ、スタートします。

もうこれで監視がスタートしたので、他の作業とか進めちゃいます。

(待ってる間に、このblogを書いています…)

(書き終わってしまいました…)

あ、通知が来ました。
これで時間を無駄にしなくてすみますね!

※同じやり方でキーワードを変えれば、パッケージがなかなか来ないとかでも監視ができます



2013年12月24日火曜日

リードの「取引の開始」をSalesforce1アプリにパブリッシャーアクションで追加する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Salesforce1に変わっても相変わらずリードの取引先変換が無い!!!とIdeaExchangeでも取り上げられています。

ちょっと前に「カレンダーをSalesforce1に追加する方法」を見たのでインスパイアされてパブリッシャーアクションを簡単に作ってみました。

Visualforceページを作る

こんな感じで、先ほどのカレンダーのやつまるパクリです。
{!id}でリードのIDを埋め込んで、isdtp=nvでヘッダなどを隠してます。

リードにアクションを追加

上のVisualforceページを指定します。

レイアウトに追加

リードのレイアウトに作成したアクションをドラッグ&ドロップして追加。

iPhoneのSalesforce1アプリから使ってみる

標準の画面を無理矢理埋め込んだだけなので画面サイズがアレですが…とりあえず使える様になりました!
video

※ネタが無かったのでForce.com Advent Calendar 2013不参加予定でしたが急遽プチネタができたので遡っての参加です

2013年9月8日日曜日

Salesforce Developer Conference Tokyo 2013 (Mini Hackレポート)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Salesforce.comの開発者向けイベント、Salesforce Developer Conference Tokyo 2013行ってきました。

去年のCloudforceでもあったMini Hack、今回は豪華賞品を揃えて全4問で再登場したの挑戦しました。なんと4問提出で、抽選で1名なんとDreamforceツアーご招待。

4問の課題は以下の内容:

とりあえず簡単そうなものから…と思って課題流し読みして、Aからやろうと思ったらTreaure Dataのアドオン追加がなぜかエラー…。Kからやることに。

課題K「Heroku Platform APIをつかってHerokuを操作しよう!」

要は、最近公開されたPlatform APIを試してみてね、という課題Platform APIのチュートリアル通りにコマンドラインからcurlでAPIの動作を確認すればOK。
一部、チュートリアルのコマンド例そのままだとContent-Type: application/jsonヘッダが足りなくてエラー出てたので報告しときました。
Heroku使った事あれば簡単すぎますね。

まだTreasure Dataのアドオンが追加できなかったので次はH。

課題H「Mobileアプリケーションを作ってみよう!」

こちらも数ヶ月前にリリースされたMobile Packを試してみてね、という課題。Mobile Packを使用して取引先の一覧を表示するモバイル用ページを作ればOK。
jQuery mobile, AngularJS, Backbone.js, Knockout, appery.io, Sencha, Xamarin, Codiqaと多数のフレームワークに対応してる様です(半分くらい知らない)。
とりあえず普段使っているAngularJSでやろうとサンプルコードを落としてきて動かしてみるが、app.jsとかを静的リソースに突っ込むのが面倒そうで、jQuery mobileに変更(@a_kurataniさんがjQuery mobileでやったら簡単だったと言ってたのでw)。
サンプルコードの取引先責任者の一覧表示するVisualforce Pageを覗いてみるとJSに直にSOQLが…。オブジェクト名と項目名だけ変えておしまいですね。

@mino0123さんのツイートを見て、アドオン追加が復活してるっぽかったのでAを再開。

課題A「Treasure Dataアドオンを使ってみよう!」

Treasure DataのHerokuアドオンを試してみてね、という課題
とりあえず課題シートの指示通りにデモアプリをgithubからcloneして、コマンドラインからアドオン追加、プラグイン追加、デプロイをしてみます。
デモアプリをブラウザで開いても、Hello World!が出るだけで動きが分からないのでソースを追ってみると、アクセスの都度裏でTDにログを送る様です。
「サンプルアプリを修正して画面の表示を変更してください」って画面の修正だけで本当にいいのか気になりながら、変更するところはタイトルくらいしか無かったのでHello World! をHoge Hoge! みたいに書き換えて聞いてみたらこれでOKw(TD関係ないじゃん)
ちなみにRubyを全然書いたことがないので初めて.erbファイルをさわった(デモアプリはsinatra)。

3問でMBA狙いにしようかと思ったけど時間あったから4問目も挑戦。

課題C「オフラインHack - SmartStore」

Mobile SDKを使ってオフライン対応のアプリを作れ、という課題と勝手に解釈。
SmartSyncがBackbone.js使われてるとか基調講演で聞いたので、ちょっと難易度高いかなーと思って思い込んで避けてたやつ。
Mobile SDKは前に落として試してたけど、念のため最新版をgit pull。
iOS版のサンプルアプリをXcodeからとりあえず動かしてみて、問題を良く読んでみると…「提出方法:サンプルの動作が画面で確認できたら、お声掛けください」
始める前に、終わってた。
@yonet77さんがサンプルコードでビルドエラーが…て困ってたのでちょっと見てみたら、最近iOS7対応したときに見覚えのある定数が。github上のmasterがすでにiOS7対応されてて、β版Xcodeじゃないとヘッダ足りなくて動かないので、β版Xcode5持ってない場合は古いリビジョン取り直さないとダメという罠

4問解いておいて、Dreamforceにするか、MBAにするかギリギリまで迷ったけど、@yonet77さんがDreamforceに1人目で申し込んだので、このままだと確定で面白くないなーということで同じくDreamforceに申し込んだら、なんと抽選当たってしまいました!

Developer Conference参加自体も直前で決めたのに、なんか申し訳ない…

最後に、傾向と対策

  • なんか難しそうだけど課題の意図はとりあえず手を動かしてさわってみてね、という所だと思うのでチュートリアルレベル。とにかくやってみる
  • git, herokuは使えて当たり前? 環境は整えておく
  • ノートパソコンの電源アダプタは持ってくる(電池切れた…て人がちらほら)

課題カードが無くなるの早かった割には、参加者少なかったんじゃないかな…
あと提出方法、応募方法が分かりにくかったという声も…
SDUG(Salesforce Developer User Group)に参加してると最新情報に強くなれますよー、とちょっと宣伝で締めにします。



2012年12月4日火曜日

[force.com] CSV添付のメールをスケジューリングして送る

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

とある案件で毎日CSVをメールに添付して送る要件があり、実装できるまでの顛末のメモです。 問題は、添付するCSVの文字コードがShift_JIS、改行コードがCRLFじゃないといけないこと…

1. まずはControllerとVisualforceでSJISのCSVを吐き出してみる

public class CSVController {
    public String getCRLF(){return '\r\n';}
    public List<Account> accounts{get;set;}
    public CSVController() {
       accounts = [select id, name from Account];
    }
 }

{!a.id},{!a.name}{!CRLF}

こんな感じで、/apex/CSVPage でSJISのCSVがダウンロードできた。簡単すぎる。

2. メール添付して送ってみる

スケジュールApexでスケジューリングする予定なのでScheduableインタフェースを実装して、こんな感じで。

global class CSVMail implements Schedulable {
    global void execute(SchedulableContext sc) {
        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        msg.setSubject('テスト');
        msg.setPlainTextBody('テスト');
        msg.setToAddresses(new String[]{'pomu0325@gmail.com'});
       
        Messaging.EmailFileAttachment att = new Messaging.EmailFileAttachment();
        att.setFileName('テスト.csv');
       
        // 添付CSVをVisualforceページから読み込む
        PageReference page = new PageReference('/apex/CSVPage');
        att.setBody(page.getContent());
        msg.setFileAttachments(new Messaging.EmailFileAttachment[]{att});

        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
    }
}

開発者コンソールで、new CSVMail().execute(null); とかすればメール送信成功! あとはスケジュール設定するだけと思って「Apexをスケジュール」しても、エラーで送られないんですね…

PageReferenceのリファレンス見てみると、「This method can't be used in: … Scheduled Apex …」って使えないじゃん…どうしよう。

3. 外部のサーバで文字コードだけ変換する

Apexで文字コード変換するのが簡単にはいかなさそうなので…外部サーバで文字コード変換する為だけのapiの様なものを置いて、コールアウトで使ってみる作戦。

ScalaのUnfilteredてフレームワークで、こんな感じでデプロイしてみた。
※自分は某G社のクラウドに置きましたがherokuに置くとかいいですね!

  object UtilPlan {
    def intent = Intent {
      case r @ POST(Path("/utils/nkf")) & QueryParams(p) =>
        val encoding = p("encoding").headOption getOrElse "MS932"
        val payload = new String(Body.bytes(r), "utf-8")
        
        Ok ~> ResponseBytes(payload.getBytes(encoding))
    }
  }

これを使って、Apex Classはこんな感じに。 実行前に「セキュリティのコントロール>リモートサイトの設定」で外部サーバのURLの追加も忘れずに。

global class CSVMail implements Schedulable {
    global void execute(SchedulableContext sc) {
        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        msg.setSubject('テスト');
        msg.setPlainTextBody('テスト');
        msg.setToAddresses(new String[]{'pomu0325@gmail.com'});
       
        Messaging.EmailFileAttachment att = new Messaging.EmailFileAttachment();
        att.setFileName('テスト.csv');
       
        /*
        // 添付CSVをVisualforceページから読み込む
        PageReference page = new PageReference('/apex/CSVPage');
        att.setBody(page.getContent());
        */
        // 添付CSVを文字列で生成して外部サーバで文字コード変換
        String csv = CSVMail.csv([select id, name from Account]);
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://ひみつ/utils/nkf');
        req.setMethod('POST');
        req.setBody(csv);

        Http h = new Http();
        HttpResponse res = h.send(req);
        att.setBody(res.getBodyAsBlob());
       
        msg.setFileAttachments(new Messaging.EmailFileAttachment[]{att});
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
    }
   
    private static String csv(List<Account> accounts) {
        String csv = '';
        for (Account a : accounts) {
            csv += a.id + ',' + a.name + '\r\n';
        }
        return csv;
    }
}

これもまた、開発者コンソール等からの実行だとOKだけど、スケジュールするとコールアウトがダメ… と思ったけど@future(callout=true)を付ければ非同期実行でコールアウト呼べることが判明したので@futureなメソッドにメール送信の処理を移動して完成!

global class CSVMail implements Schedulable {
    global void execute(SchedulableContext sc) {
        CSVMail.sendCSV();
    }
   
    @future(callout=true)
    private static void sendCSV() {

        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        msg.setSubject('テスト');
        msg.setPlainTextBody('テスト');
        msg.setToAddresses(new String[]{'pomu0325@gmail.com'});
       
        Messaging.EmailFileAttachment att = new Messaging.EmailFileAttachment();
        att.setFileName('テスト.csv');
       
        /*
        // 添付CSVをVisualforceページから読み込む
        PageReference page = new PageReference('/apex/CSVPage');
        att.setBody(page.getContent());
        */
        // 添付CSVを文字列で生成して外部サーバで文字コード変換
        String csv = CSVMail.csv([select id, name from Account]);
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://ひみつ/utils/nkf');
        req.setMethod('POST');
        req.setBody(csv);

        Http h = new Http();
        HttpResponse res = h.send(req);
        att.setBody(res.getBodyAsBlob());
       
        msg.setFileAttachments(new Messaging.EmailFileAttachment[]{att});
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
    }
   
    private static String csv(List<Account> accounts) {
        String csv = '';
        for (Account a : accounts) {
            csv += a.id + ',' + a.name + '\r\n';
        }
        return csv;
    }
}

2011年12月18日日曜日

Titanium Salesforce module(SalesForce Toolkit for Appcelerator)の使い方 (2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
前回のサンプルアプリをちょっと時間が経ってから動かしてみると、

[ERROR] In the error handler looking for a 401, and have a 401

[ERROR] Handleing the 401 error...

とかエラーが出てしまい動きません…

force.comからOAuth2で取得したaccess tokenには有効期限があるのでrefresh tokenを使って再度取得する必要があるのですが…そこが動作していないようです。
force.comのOAuthについて詳しくはこちらで

エラーのコールバックも呼んでくれないので有効期限切れたかどうかも検出できず…

なんとかhackできないかと、こんな感じでモジュールの中身をダンプしてみます。

var FDC = require('com.salesforce');
for (var i in FDC.ForceOAuth) {
 Ti.API.debug(i + ':' + FDC.ForceOAuth[i]);
}

最終的にREST APIの呼び出しはここに来るようです。
[DEBUG] makeRestCall:function (path, callback, error, method, payload, retry) {var restUrl=Ti.Network.decodeURIComponent(fa.instanceUrl)+'/services/data'+path;var xhr=Ti.Network.createHTTPClient();xhr.onload=function(){Ti.API.info("REST Response: "+this.responseText);var data="";if(this.responseText){data=this.responseText;}

callback(data);};xhr.onerror=function(e){Ti.API.error("XHR, error handler..."+"\nDbDotCom.REST.OAuth.refreshToken: "+fa.refreshToken+"\nretry: "+retry+"\n e: "+e.error+"\nXHR status: "+this.status);if(!fa.refreshToken||retry){error(e.error);}else{Ti.API.error("In the error handler looking for a 401, and have a "+xhr.status);if(xhr.status===401){Ti.API.error("Handleing the 401 error...");exports.refreshAccessToken(function(oauthResponse){Ti.API.error("Refresh response... "+oauthResponse);fa.makeRestCall(path,callback,error,method,payload,true);},error);}else{Ti.API.error("Not a 401 error, re-throwing...");error(e);}}};if(fa.usePostBin===true){restUrl="http://www.postbin.org/135onm5";}

xhr.open(method||"GET",restUrl,true)

Ti.API.info("Rest url: "+restUrl);xhr.setRequestHeader("Authorization","OAuth "+Ti.Network.decodeURIComponent(fa.accessToken));xhr.setRequestHeader("Content-Type","application/json");xhr.send(payload);}

出てるログから、exports.refreshAccessToken()の呼び出しの中でエラーが起きてコールバックまで戻って来ないようです。

よく考えたら、OAuth2のrefresh tokenによるaccess token再取得時にはclient secretが必要なはずなのに、モジュールのパラメータなどでどこにもセットしていないのでrefreshできるわけないですね… 未実装なんでしょうか?
※追記:secret要らない仕様に変わってました
ダンプしたソースを参考に、こんな感じでhackしてみました。
※モジュール内で定義されてるobjectのプロパティは動的に書き換えられない?&スコープ的にアクセスできない変数があったので結構無理矢理

使い方は、requireした後にこのファイルをincludeしてパッチを当て、ForceOAuthの代わりにForceOAuth2を使うようにします。ForceOAuth2.openのパラメータにはclient idとclient secretを渡す様にします。

var FDC = require('com.salesforce');
Ti.include('fdc-patch.js');
FDC.ForceOAuth2.open('CLIENT_ID');

パッチしたポイントは2つ。refreshAccessTokenをclient secretを使用して動作する様にしたのと、REST APIのパスの固定部分に /data が含まれていたのを /apexrest が呼べる様に /services までとしたこと。

Winter '12でリリースされたApex RESTを使って公開したAPIのURLは、$instance_url/services/apexrest/... となるので、FDC.ForceOAuth2.makeRestCall('/apexrest/myapi', callback) の様な感じで使える様になります。

marketplaceのモジュールのページには、"This toolkit is maintained by the community and sponsored by salesforce.com. Salesforce.com does not officially support this product."とか書いてあるんですが、パッチとか提供したい場合どこに連絡すればいいんでしょうか… githubとかにソース上がってればforkするのに…

この記事はForce.com Advent Calendar 2011に参加しています。

2011年12月8日木曜日

Titanium Salesforce module(SalesForce Toolkit for Appcelerator)の使い方

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
最近、Titanium Mobileでforce.comのREST APIを使用したiPhoneアプリを作ってます。

Titanium Mobileについての基本的な知識やTitanium Studioの使い方はある程度知ってる前提で書いているので、Titaniumについて知りたい方は「Titanium Mobileで作る! iPhone/Androidアプリ」などを参考にどうぞ。

Titaniumにはmarketplaceがあり、ソフトウェア部品としてのモジュールや、アプリのテンプレートなどをダウンロードできます(有償のもアリ)。
うまいこと目的に合ったモジュールを見つけて利用すれば開発スピードは向上する…はず…

Salesforce用のモジュールも用意されているので、今回の開発にはこれを利用しました。が、ドキュメントが大して無かったりで取っ掛かり苦労したのでメモとして残しておきます。
今回は、モジュールを使うまでの準備と、サンプルコードの実行まで。

2011年9月20日火曜日

foursquare global hackathon @ Tokyo

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
NYC, SF, Paris, Tokyoで同時開催のfoursquare global hackathon、東京会場のオーガナイザ兼参加者として9/17-18の2日間約42時間ぶっつづけで楽しんできました。

東京会場では参加者15名、応募作品9と他会場と比べて少ない数字でしたが、みんなでワイワイおやつ食べたり深夜居残り組はみんなで銭湯行ったり、いい雰囲気でした。
NYC,SF,Parisの中継映像をスクリーンに映して、音声無しながらもParisがエッフェル塔切り抜いたのカメラの前に貼って遊んでたのに東京タワーで対抗?してみたりw
Togetterまとめ

いきなりですが東京会場内での作品の投票結果発表!
日本時間9/23の正午まで、http://fshackathon.appspot.com/で一般投票が行われているので気に入った作品にぜひ投票をお願いします(何作品でも投票できます)!

1位(会場得票数4): photosquare
作者:中継カメラ設置等いろいろ手伝ってくれた@koogawaさん
内容:近くのvenueに投稿されてる写真をスライドショー表示してくれるiPhone/iPad用アプリ。アプリ審査があるのでまだダウンロードできませんが、http://twitvideo.jp/06TpCから映像見ることができます。
投票する

2位(会場得票数3):The Journalist
作者:今回素晴らしい会場を提供してくださったGaiaXの@aomushi510さんと、直前に@aomushi510さんに誘われて急遽参加のTomoyuki Hisadaさんのチーム
内容:4sqのチェックイン履歴を使用して、自分の行った場所の記事を投稿できる、ソーシャルニュース的なサービス。新聞的なデザインや、細かいところの動きがよくできていて完成度高くてびっくり!
http://journalist.azu.sh/で見れる…はずが残念ながら今エラー出てます…
投票する

同着2位(会場得票数3):4sqlist(仮)
作者:pomu0325(すいません自分です。)
内容:サブベニュー(駅のホームとか、モール内の店舗とか)をグループ化して探しやすくするiPhone/iPad用WEBアプリ。時間が無くて最低限の機能しか作り込めませんでした… 同じアイデアで作り始めた@ikawamotoさんとは違い、手動でサブベニューの情報を編集するアプローチです。http://4sqlist.appspot.com/
投票する

以下、順不動での掲載です。

チーム名:curly
作者:@takochuuさん、@sunny_510さんのチーム
内容:venue毎に、そこにチェックインした人のつぶやきが見えたりランキングが見れたりするサービス。デザインもよくまとまってましたが、公開はまだ…かな?
投票する

Packed Venues
作者:大阪から来てくれた@ikawamotoさん
内容:住所が同じベニューをまとめて表示するiPhoneアプリ。動かしているところの動画はこちら。住所表記のブレが解決できれば自動でまとめられるアプローチの方がいいですね!
投票する

Squarecount
作者:meetup主催等いつも手伝ってくれてる@jayjpn
内容:4sqへのチェックイン回数を表示するだけw。エンジニアじゃないのに締め切りぎりぎりまで頑張ってました。http://squarecount.appspot.com/index.html
投票する

4sq Scouter
作者:自分と同じく携帯用4sq「じゃぽすく」を作っている@jpfoursquareさん
内容:スカウターと言ったらおなじみ、例のアレ風に「強さ」を数値化して表示してくれます。数値には、「複雑な足し算」が使用されているとのことですw http://scouter.jpfoursquare.com/から試せます。
投票する

fourSquare PopUp Utility
作者:The Journalistもチームメンバーで作っているTomoyuki Hisadaさん
内容:4sqのユーザやvenueの情報をマウスオーバーで表示してくれるjsライブラリ。ページ内のfoursquareへのリンクを自動で変換してくれるみたいです。twitter anywhereの4sq版、と言えば分かる人には分かる。使い方等
投票する

Complete Japanese fried chicken delis in MusashiKoyama
作者:@Suger1008 さん
内容:むさこ(武蔵小山)の唐揚げ屋さんを制覇! むさこ愛にあふれるスマートフォン用アプリをTitanium Mobileで作られていました。公開はまだですが解説等はこちら
投票する

応募があったのは以上9作品ですが、他にも時間が足りなかったり、既に作っているものを4sq対応したりと各自ガリガリがんばっていました。

最後に、深夜含め2日連続と無理な条件にも関わらずすてきな会場を提供してくださった、ガイアックスさん、本当にありがとうございました!!!
ハッカソンなどのイベントでよく会場提供をしているそうなので、またお邪魔させていただきます!