今回のアップデート(2016/05/08 の定期メンテナンスにおけるkintone API、User API更新情報)で難解なのがこのkintone.proxy.upload()です。kintone JavaScript APIとして外部APIをコールできるkintone.proxy()のファイルアップロード版なのですが、試行錯誤の結果、「transfer.sh」というファイル共有サービスで利用可能なことが分かったのでご紹介したいと思います。
transfer.sh
transfer.sh(http://transfer.sh)は、コマンド・シェルでアップロードできて、10GBまでのファイルが14日間ストアされるファイル共有サービスです。公式サイトを見ると売り文句の通り、cURLコマンドやシェルの実行例が記載されています。
次のようなコマンドでローカルファイル(logo.jpg)をアップロード出来ます。メソッドとしてはPUTで実行されています。
$ curl --upload-file ./logo.jpg https://transfer.sh/logo.jpg # リクエスト https://transfer.sh/66nb8/logo.jpg # レスポンス
レスポンスとして、共有されたファイルのURLが発行されます。
kintone.proxy.upload() による添付ファイルの共有
kintone.proxy.upload()を使えば、このcURLコマンド相当の処理をkintone JavaScript APIで実装し、kintoneに添付されたファイルをオープンに共有することが簡単にできるというわけです。早速設定していきましょう。
アプリ
まず、次のようなフィールドを持ったアプリを準備しましょう。
フィールド名 | フィールドコード(フィールドタイプ) | 利用目的 |
---|---|---|
タイトル | Title(文字列1行) | タイトル |
ファイル | File(ファイル) | 管理しているファイル ※今回transfer.shで共有できるファイルは最上段の1個です。 |
(スペースフィールド) | space(スペース) | ボタン設置用スペースフィールド |
共有URL | FileShareUrl(リンク:Web) | transfer.shで共有されたファイルリンク |
共有終了日 | EndDay(日付) | ファイル共有が終了する日 |
JavaScriptのコーディング例
/* * fileShare.js * * Dependencies: * jQuery( https://js.cybozu.com/jquery/1.11.3/jquery.min.js ) * SweetAlert( https://js.cybozu.com/sweetalert/v1.1.0/sweetalert.min.js / https://js.cybozu.com/sweetalert/v1.1.0/sweetalert.css) * spin.js( https://js.cybozu.com/spinjs/2.3.2/spin.min.js ) * Moment.js( https://js.cybozu.com/momentjs/2.10.6/moment-with-locales.min.js ) */ jQuery.noConflict(); (function($) { "use strict"; // kintoneの添付ファイルをBlobで取得する function getBlob(fileKey, fileName, callback) { var apiurl = '/k/v1/file.json?fileKey=' + fileKey; var xhr = new XMLHttpRequest(); xhr.open('GET', apiurl, true); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); //これが無いとIE,FFがNG xhr.responseType = "blob"; var blob = xhr.responseType; xhr.onload = function() { var blob = xhr.response; callback(blob); }; xhr.send(); } // transfer.shにファイルをアップロードする function uploadToService(fileName, blob) { var url = 'https://transfer.sh/' + encodeURIComponent(fileName); return kintone.proxy.upload( url, 'PUT', {}, { 'format': 'RAW', 'value': blob } ); } // transfer.shの公開URLと共有終了日をkintoneのレコードにREST APIでセットする関数 function updateRecord(url) { url = url.replace('\n', ''); return kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', { app: kintone.app.getId(), id: kintone.app.record.getId(), record: { "FileShareUrl": { "value": url // 共有URL }, "EndDay": { "value": moment().add(13, 'day').format('YYYY-MM-DD') // 共有終了日 } } }); } kintone.events.on(['app.record.detail.show'], function(event) { var record = event.record; var attachments = record['File'].value; // スペース要素 var el = kintone.app.record.getSpaceElement('space'); // 親要素のサイズを調整 $(el).parent().width('200px'); $(el).parent().height('100px'); $(el).css({ 'margin-left': '10px' }); // 正味のコンテナ要素 var $container = $('<div>').prop({ 'id': 'container' }).appendTo(el); // ボタン等追加 $container.append( $('<button>').prop({ id: 'joyzo-button' }).css({ 'margin-top': '30px' }).addClass('kintoneplugin-button-normal').text('transfer.shで共有'), $('<div>').text('※最上段の添付ファイルのみが共有されます').css({ 'font-size': '8pt', 'margin': '3px' }) ); // ボタンクリックイベント $('#joyzo-button').bind('click', function() { showSpinner(); //console.log(attachments); // 添付ファイル(Blob)の取得 -> transfer.shへのアップロード -> レコード更新 new kintone.Promise(function(resolve, reject) { getBlob(attachments[0].fileKey, attachments[0].name, function(blob) { // 添付ファイルの取得 resolve(blob); }); }).then(function(blob) { //console.log(blob); return uploadToService(attachments[0].name, blob); // transfer.sh へのアップロード }).then(function(resp) { //console.log(resp); var url = resp[0]; return updateRecord(url); // レコード更新 }).then(function() { hideSpinner(); swal({ title: 'ファイルアップロード完了', text: '', type: 'success' }, function() { location.reload(true); }); }).catch(function(e) { hideSpinner(); //console.log(e); var errmsg = 'ファイルアップロード失敗。'; if (e.message !== undefined) { errmsg += e.message; } swal({ title: 'ファイルアップロード失敗', text: errmsg, type: 'error' }, function() { return; }); }); }); function showSpinner() { // 要素作成等初期化処理 if ($('.kintone-spinner').length == 0) { // スピナー設置用要素と背景要素の作成 var spin_div = $('<div id ="kintone-spin" class="kintone-spinner"></div>'); var spin_bg_div = $('<div id ="kintone-spin-bg" class="kintone-spinner"></div>'); // スピナー用要素をbodyにappend $(document.body).append(spin_div, spin_bg_div); // スピナー動作に伴うスタイル設定 $(spin_div).css({ 'position': 'fixed', 'top': '50%', 'left': '50%', 'z-index': '510', 'background-color': '#fff', 'padding': '26px', '-moz-border-radius': '4px', '-webkit-border-radius': '4px', 'border-radius': '4px' }); $(spin_bg_div).css({ 'position': 'absolute', 'top': '0px', 'z-index': '500', 'width': '150%', 'height': '150%', 'background-color': '#000', 'opacity': '0.5', 'filter': 'alpha(opacity=50)', '-ms-filter': "alpha(opacity=50)" }); // スピナーに対するオプション設定 var opts = { 'color': '#000' }; // スピナーを作動 new Spinner(opts).spin(document.getElementById('kintone-spin')); } // スピナー始動(表示) $('.kintone-spinner').show(); }; // スピナーを停止させる関数 function hideSpinner() { // スピナー停止(非表示) $('.kintone-spinner').hide(); }; return event; }); })(jQuery);
コードの内容は、「transfer.shで共有」ボタンのクリックで、
①添付ファイルフィールドの1つ目の添付ファイルをXMLHttpRequestを用いてBlob形式で取得(getBlob関数)
②kintone.proxy.upload()でtransfer.shにリクエスト(uploadToService関数)
③kintone.proxy.upload()のリクエストが成功し、transfer.shでファイルが公開できたら、アクセスURLと共有終了日をレコード更新でセットする(updateRecord関数)
という感じの内容です。
アプリの動作とファイル共有
①レコード新規登録・編集画面でファイルをレコードに添付し、保存後に②「transfer.sh」ボタンをクリック
③リクエスト(アップロード)が成功すると、(ダイアログ表示後リロードされて)共有URLがセットされれる
④共有URLにアクセスすると、ファイルが共有され、ダウンロード出来る状態になっていることが確認できる。第3者に共有したい場合にもこの共有URLを伝えることで、アクセスできる
kintone.proxy.upload()の考察
今回この記事でわかることをひとつまとめておくと、『cURLコマンドにおける「–upload-file」オプションでのリクエストとkintone.proxy.upload()/PUTに等価性がある』ということです。
まとめ
kintoneに添付されたファイルをパブリックな場に共有したい際に便利なtransfer.shへの連携を例にkintone.proxy.upload()のリクエスト例をお届けしました。冒頭に「試行錯誤した結果」と書かせて頂きましたが、実はこの記事は色々調べてみた結果から辿ってまとめたものです。この経緯を詳しく知りたい方は長編版をまとめていますので、こちらを御覧ください。