Salesforceのカスタムオブジェクトに画像付きデータを送信する
概要
このサンプルでは、Webhook送信を利用し、SPALOアシスタントで「送信」したタイミングで、セールスフォースのカスタムオブジェクトに画像付きの送信データを書き込む方法を説明します。
用意するもの
- 報告書:写真台帳
- SPALOボット:写真台帳
- カスタムオブジェクト:写真台帳
- Webhookアプリ:NodeJs
- 公開サーバ:Google Cloud Functions
- SPALO-APIs:Webhook送信
SPALOボットの準備
SPALOメーカーで「写真台帳」ボットを作成します。ボットとの会話で入力する情報は以下の5項目です。
作業日、現場名、作業者、写真、備考
ボットが作成できたら、SPALO アシスタントで「送信」し、送信結果が SPALO メーカーの履歴画面に表示されることを事前に確認します。
SFDC側の設定
データを登録するためのカスタムオブジェクト、カスタムオブジェクトに接続するための接続アプリケーション、接続アプリケーションを実行するユーザーのセキュリティトークンを用意します。
カスタムオブジェクトの作成
SPALOアシスタントで「送信」すると、ボットに登録されたWehook通知先に写真台帳の中身となるデータが通知されます。通知されたデータを登録するためのカスタムオブジェクトを作ります。
写真の項目のデータ型は「URL」とします。
接続アプリケーションの作成
Webhook受信アプリから、カスタムオブジェクトに接続するための「接続アプリケーション」を作成します。接続アプリケーションを作成したら、設定画面でキーワード「アプリケーションマネージャ」で検索すると、様々なアプリケーションと一緒に作成したアプリケーションが表示されるようになります。そこで該当するアプリケーションの「参照」を選択すると、以下のような画面が表示されます。表示されたら、consumerKey、consumerSecret を、メモしておきます。
セキュリティトークンの取得
個人の「設定」> 「私のセキュリティトークンのリセット」と選択し、リセットを行います。リセットすると、セキュリティトークンがメールが送られてくるので、メモしておきます。
Webhook受信アプリの作成
Webhook通知を受け取り、Salesforceのカスタムオブジェクトに書き込むアプリケーションを作成します。Node.jsを使ってコーディングし、Google Cloud Functionsにデプロイします。
データ取得
Webhook通知された情報を req で受け取り、データの中身を取得します。Webhook通知される送信オブジェクトのデータ構造の詳細は、こちら をご覧ください。
exports.sfdcWebhook = async (req, res) => {
// data setting.
const historyId = req.body.historyId;
const date = req.body.data['作業日'];
const dm = date.match(/(\d+)年(\d+)月(\d+)日/);
const working_date = dm[1] + '-' + dm[2] + '-' + dm[3];
const worker = req.body.data['作業者'];
const site_name = req.body.data['現場名'];
const remarks = req.body.data['備考'];
画像ファイル取得
SPALO APIを利用して送信した画像ファイルをダウンロードします。
SPALO ログイン
const spalo_login_url = 'https://maker.spalo.jp/api/v2/user/login';
const params = {
workspaceCode: 'xxxx',
email: 'yyyy',
password: 'zzzz',
};
const res1 = await axios.post(spalo_login_url, params);
画像ダウンロードAPI
画像ダウンロードAPIの詳細はこちらを参照して下さい。
const spalo_download_url = 'https://maker.spalo.jp/api/v2/history/download/image/';
const config = {
headers: {
Authorization: 'Bearer ' + res1.data.accessToken, //SPALOログインの戻り値を設定
ContentType: 'application/octet-stream',
},
responseType: 'arraybuffer',
}
const res2 = await axios.get(spalo_download_url + req.body.historyId, config);
const contentMeta = res2.headers['content-disposition'].split('=');
// ファイル名取得
const fileName = contentMeta[1];
// CloudFunction利用可能一時ディレクトリ
const outputDir = '/tmp/';
// 一時ファイル出力
fs.writeFileSync(outputDir + fileName, res2.data, 'binary');
接続オブジェクトの作成
アプリからSFDCのカスタムオブジェクトに接続するための接続オブジェクトを作ります。このサンプルでは、jsforceモジュールで接続します。
// Create Connection.
const conn = new jsforce.Connection({
oauth2: {
loginUrl: login_url,
clientId: consumer_key,
clientSecret: consumer_secret,
},
});
画像をSalesforceへアップロード
カスタムオブジェクトへ登録する前に画像ファイルをSalesforceのストレージへアップロードします。
exports.uploadImage = async (conn, file) => {
try {
const formdata = new FormData();
formdata.append("fileData", file);
const config = {
headers: {
Authorization: 'Bearer ' + conn.accessToken,
ContentType: 'multipart/form-data',
...formdata.getHeaders(),
},
}
const url = conn.instanceUrl + '/services/data/v49.0/connect/files/users/me';
const res = await axios.post(url, formdata, config);
// 登録したファイルID
return res.data.id;
} catch (err) {
console.dir(err);
}
}
ファイルのプレビューURLを作成
カスタムオブジェクトの写真の項目(URL型)に設定するプレビューURLを作成します。
// ドメイン抽出
const domain = conn.instanceUrl.substring(8, conn.instanceUrl.indexOf('.my'));
const fileViewUrl = 'https://' + domain + '.lightning.force.com/lightning/r/ContentDocument/' + fileId + '/view';
インサートデータの作成
カスタムオブジェクトのフィールド情報に合わせて送信データをセットします。
// custom object
const sobject_name = 'photo_ledger_demo__c';
// data setting.
const historyId = req.body.historyId;
const date = req.body.data['作業日'];
const dm = date.match(/(\d+)年(\d+)月(\d+)日/);
const working_date = dm[1] + '-' + dm[2] + '-' + dm[3];
const worker = req.body.data['作業者'];
const site_name = req.body.data['現場名'];
const remarks = req.body.data['備考'];
// postdata
const insert_data = {
history_id__c: historyId,
working_date__c: working_date,
site_name__c: site_name,
worker__c: worker,
photo__c: fileViewUrl,
remarks__c: remarks,
};
インサート処理
接続オブジェクトでログインし、成功したらインサート処理を行います。 ログイン、インサート、それぞれのタイミングで成否をログに残すようにしておきます。
// POST
conn.login(client_username, client_password, function (error, response) {
if (error) {
console.log(error);
return res.status(401).end();
}
// Insert
conn.sobject(sobject_name).create(insert_data, function (error, response) {
if (error) {
console.log(error);
return res.status(400).end();
}
console.log(response);
return res.status(200).send(response).end();
});
});
ローカルテスト
以前紹介したこちらの記事を参考にして下さい。
デプロイ
cloud functionsにデプロイして、WebhookURLを発行します。
gcloud functions deploy exampleSfdcWebhookSendImage --runtime=nodejs10 --trigger-http --allow-unauthenticated
デプロイが完了すると、以下のようなログが表示されます。httpsTriggerにあるURLが発行されたWebhookURLです。
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
buildId: 7498e6ca-c24c-466b-a961-e812525856c9
entryPoint: exampleSfdcWebhookSendImage
environmentVariables:
TZ: Asia/Tokyo
httpsTrigger:
url: xxxxx
ingressSettings: ALLOW_ALL
labels:
deployment-tool: cli-gcloud
name: projects/haro-164414/locations/us-central1/functions/exampleSfdcWebhookSendImage
runtime: nodejs10
erviceAccountEmail: xxxxx
sourceUploadUrl: xxxxx
status: ACTIVE
timeout: 60s
updateTime: '2020-11-16T05:22:53.321Z'
versionId: '24'
SPALOメーカーの設定
発行されたURLをSPALOメーカーに登録します。登録するとWebhookIDが発行されるので、そのIDをSPALOボットに紐付けます。
エンドポイント保護
WebhookURLの登録時に発行されたSecretKeyを使い、 不正なアクセスからエンドポイントを保護します。保護の仕方は こちら をご覧ください。
完成
エンドポイント保護対策を入れたら、再度、デプロイします。
SPALO アシスタントで「写真台帳」ボットを開き、ボットと会話を進めます。
会話が終わったら「送信」します。送信した内容は、SPALOメーカーの履歴画面に表示されると同時に、カスタムオブジェクトにも表示されます。
ダウンロード
この記事で紹介したサンプルは以下からダウンロードできます。