
Box: Download File as PDF/Text/Image
This item downloads the specified file on Box in the specified file format.
Configs: Common
- Step Name
- Note
Configs
- C1: OAuth2 Setting *
- C2: File ID to download *
- C3: File Format in which to download the file *
- C4: File Name (named with the file name on Box if blank)#{EL}
- C5: File type data item to add the downloaded file *
Notes
- The refresh token for Box has an expiration date. Use regularly to ensure that it does not exceed the expiration.
- This item uses Box file representation API. For supported file types, see the Box Developer Documentation.
- For some file formats like JPEG (2048×2048), PNG (1024×1024) and PNG (2048×2048), each page of the original file will be downloaded as a separate file. The downloaded files will have a page number attached at the beginning of their file names.
- A script error saying “The representation [xxx] is being created and not available yet. Please try again later.” may occur when downloading a file in the file format for the first time. In such case, re-execute this item some time later to successfully download the file.
Capture

See also
Script (click to open)
- An XML file that contains the code below is available to download
- box-file-representation-download.xml (C) Questetra, Inc. (MIT License)
- If you are using Professional, you can modify the contents of this file and use it as your own add-on
main();
function main(){
const oauth2 = configs.get('conf_OAuth2');
const fileId = decideFileId();
const representation = configs.get('conf_Representation');
const fileName = configs.get('conf_FileName');
const fileDef = configs.getObject("conf_Files");
const {urlTemplate, paged} = getRepresentationInfo(oauth2, fileId, representation);
if (paged !== 'true') { // ページ割されていない場合
const qfile = download(oauth2, urlTemplate, representation, fileName);
saveFile(fileDef, qfile);
return;
}
// ページ割されている場合
const qfiles = downloadPages(oauth2, urlTemplate, representation, fileName);
saveFiles(fileDef, qfiles);
}
/**
* ファイル ID を config から読み出す
* @return {String} fileId ファイル ID
*/
function decideFileId() {
const fileId = engine.findData(configs.getObject('conf_FileId'));
if (fileId === '' || fileId === null) {
throw 'File ID is blank.';
}
return fileId;
}
/**
* レプリゼンテーションの情報を取得する GET リクエストを送信
* @param {String} oauth2 OAuth2 設定
* @param {String} fileId ファイル ID
* @param {String} representation レプリゼンテーション
* @return {Object} representationInfo
* @return {String} representationInfo.urlTemplate ダウンロードの際の URL テンプレート
* @return {String|undefined} representationInfo.paged ページ割されているかどうか
*/
function getRepresentationInfo(oauth2, fileId, representation) {
const url = `https://api.box.com/2.0/files/${encodeURIComponent(fileId)}`;
const response = httpClient.begin()
.authSetting(oauth2)
.queryParam('fields', 'representations')
.header('X-REP-HINTS', representation)
.get(url);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw `Failed to get representations. status:${status}`;
}
const {entries} = JSON.parse(responseStr).representations;
if (entries.length === 0) {
throw `The ${representation} representation is unavailable for this file.`;
}
const urlTemplate = entries[0].content.url_template;
const paged = entries[0].properties.paged; // "true", "false" or undefined
return {urlTemplate, paged};
}
/**
* レプリゼンテーションをダウンロードする GET リクエストを送信
* ページ割されていない場合
* @param {String} oauth2 OAuth2 設定
* @param {String} urlTemplate URL テンプレート
* @param {String} representation レプリゼンテーション
* @param {String} fileName ファイル名
* @return {NewQfile} qfile ダウンロードしたファイル
*/
function download(oauth2, urlTemplate, representation, fileName) {
const url = urlTemplate.replace('{+asset_path}', '');
const response = httpClient.begin()
.authSetting(oauth2)
.queryParam('set_content_disposition_type', 'attachment')
.get(url);
const status = response.getStatusCode();
if (status === 202) { // レプリゼンテーション作成中でダウンロードできない
throw `The representation ${representation} is being created and not available yet. Please try again later.`;
}
if (status !== 200) { // その他のエラー
engine.log(response.getResponseAsString());
throw `Failed to download the representation ${representation}. status:${status}`;
}
const contentType = response.getContentType();
const content = response.getResponse();
const fileNameToSet = decideFileNameToSet(fileName, response);
const qfile = new com.questetra.bpms.core.event.scripttask.NewQfile(
fileNameToSet, contentType, content
);
return qfile;
}
/**
* レプリゼンテーションをダウンロードする GET リクエストを送信
* ページ割されている場合
* @param {String} oauth2 OAuth2 設定
* @param {String} urlTemplate URL テンプレート
* @param {String} representation レプリゼンテーション
* @param {String} fileName ファイル名
* @return {Array<NewQfile>} qfiles ダウンロードしたファイルを格納した配列
*/
function downloadPages(oauth2, urlTemplate, representation, fileName) {
const extension = representation.substring(1,4); // jpg or png
const qfiles = [];
let pageNum = 1;
const httpLimit = httpClient.getRequestingLimit();
while (true) {
if (pageNum + 1 > httpLimit) { // レプリゼンテーション情報の取得で 1 回リクエスト済み
throw 'Number of necessary HTTP requests exceeds the limit.';
}
const url = urlTemplate.replace('{+asset_path}', `${pageNum}.${extension}`);
const response = httpClient.begin()
.authSetting(oauth2)
.queryParam('set_content_disposition_type', 'attachment')
.get(url);
const status = response.getStatusCode();
if (pageNum === 1 && status === 202) { // レプリゼンテーション作成中でダウンロードできない
throw `The representation ${representation} is being created and not available yet. Please try again later.`;
}
if (pageNum > 1 && status === 404) { // ページを最後までダウンロードした。ループから抜ける
break;
}
if (status !== 200) { // その他のエラー
engine.log(response.getResponseAsString());
throw `Failed to download the page ${pageNum} of the representation ${representation}. status:${status}`;
}
const contentType = response.getContentType();
const content = response.getResponse();
let fileNameToSet = decideFileNameToSet(fileName, response);
fileNameToSet = `${pageNum}-${fileNameToSet}`; // ファイル名にページ番号を追加
const qfile = new com.questetra.bpms.core.event.scripttask.NewQfile(
fileNameToSet, contentType, content
);
qfiles.push(qfile);
pageNum++;
}
return qfiles;
}
/**
* 保存時のファイル名を決定する
* @param {String} fileName 新しく名前をつける場合のファイル名
* @param {HttpResponseWrapper} response ファイルダウンロードのレスポンス
* @return {String} fileNameToSet 設定するファイル名
*/
function decideFileNameToSet(fileName, response) {
if (fileName !== '' && fileName !== null) {
return fileName;
}
// ファイル名をレスポンスの Content-Disposition ヘッダから取得する
const contentDisposition = response.getHeaderValues('Content-Disposition')[0];
const matched = contentDisposition.match(/filename\*=UTF-8''(.+)/);
const fileNameToSet = decodeURI(matched[1]);
return fileNameToSet;
}
/**
* 1 つのファイルを追加保存する
* @param {ProcessDataDefinitionView} fileDef 保存先データ項目
* @param {NewQfile} qfile 追加保存するファイル
*/
function saveFile(fileDef, qfile) {
let files = engine.findData(fileDef);
if (files === null) {
files = new java.util.ArrayList();
}
files.add(qfile);
engine.setData(fileDef, files);
}
/**
* 複数のファイルを追加保存する
* @param {ProcessDataDefinitionView} fileDef 保存先データ項目
* @param {Array<NewQfile>} qfiles 追加保存するファイルを格納した配列
*/
function saveFiles(fileDef, qfiles) {
let files = engine.findData(fileDef);
if (files === null) {
files = new java.util.ArrayList();
}
qfiles.forEach(qfile => {
files.add(qfile);
});
engine.setData(fileDef, files);
}