Box: ファイルを PDF/テキスト/画像でダウンロード

Box: Download File as PDF/Text/Image

この工程は、Box 上のファイルを指定形式でダウンロードします。

Auto Step icon
Basic Configs
工程名
メモ
Configs for this Auto Step
conf_OAuth2
C1: OAuth2 設定 *
conf_FileId
C2: ダウンロードするファイルの ID *
conf_Representation
C3: ダウンロードするファイル形式 *
conf_FileName
C4: ファイル名 (空白の場合、Box でのファイル名を使用します)#{EL}
conf_Files
C5: ダウンロードファイルを追加保存するデータ項目 *
conf_urlTemplate
C6: ダウンロードに必要な一時データを保存するデータ項目 *

Notes

  • Box のリフレッシュトークンには、期限があります。期限を超えないよう、定期的に利用する必要があります。
  • このアイテムは、Box ファイルのレプリゼンテーション API を使用しています。サポートされているファイルの種類については、Box 開発者向けドキュメントを参照してください。
  • JPEG (2048×2048)、PNG (1024×1024)、PNG (2048×2048) のようにページ毎にファイルがダウンロードされる形式の場合、ダウンロードファイルのファイル名の先頭にページ番号が付与されます。

Capture

See also

Script (click to open)
  • 次のスクリプトが記述されている XML ファイルをダウンロードできます
    • box-file-representation-download.xml (C) Questetra, Inc. (MIT License)
    • Professional のワークフロー基盤では、ファイル内容を改変しオリジナルのアドオン自動工程として活用できます

const PATH_VARIABLE = "{+asset_path}";

function main() {
    const oauth2 = configs.get('conf_OAuth2');
    const fileId = decideFileId();
    const representation = configs.get('conf_Representation');
    const urlDef = configs.getObject("conf_urlTemplate");

    const {urlTemplate, paged} = getRepresentationInfo(oauth2, fileId, representation);
    let url;
    if (paged !== 'true') { // ページ分割されていない場合
        url = urlTemplate.replace(PATH_VARIABLE, '');
    } else {
        url = urlTemplate;
    }
    engine.setData(urlDef, url);
    return false;
}

function proceed() {
    const oauth2 = configs.get('conf_OAuth2');
    const representation = configs.get('conf_Representation');
    const fileName = configs.get('conf_FileName');
    const urlDef = configs.getObject("conf_urlTemplate");
    const fileDef = configs.getObject("conf_Files");

    const url = engine.findData(urlDef);
    let qfiles;
    if (url.includes(PATH_VARIABLE)) {
        // ページ割されている場合
        qfiles = downloadPages(oauth2, url, representation, fileName);
    } else {
        // ページ割されていない場合
        qfiles = download(oauth2, url, representation, fileName);
    }
    if (qfiles === false) {
        return false;
    }
    saveFiles(fileDef, qfiles);
    engine.setData(urlDef, null);
}

/**
 * ファイル 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} url URL
 * @param {String} representation レプリゼンテーション
 * @param {String} fileName ファイル名
 * @return {Array<NewQfile>} qfiles ダウンロードしたファイルを格納した配列
 */
function download(oauth2, url, representation, fileName) {
    const response = httpClient.begin()
        .authSetting(oauth2)
        .queryParam('set_content_disposition_type', 'attachment')
        .get(url);
    const status = response.getStatusCode();
    if (status === 202) { // レプリゼンテーション作成中でダウンロードできない
        return false;
    }
    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 = [];
    const httpLimit = httpClient.getRequestingLimit();
    for (let pageNum = 1; ; pageNum++) {
        if (pageNum > httpLimit) {
            throw 'Number of necessary HTTP requests exceeds the limit.';
        }
        const url = urlTemplate.replace('{+asset_path}', `${pageNum}.${extension}`);
        engine.log(`url: ${url}`);
        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.`;
            return false;
        }
        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);
    }
    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''(.+)/);
    return decodeURI(matched[1]);
}

/**
 * 複数のファイルを追加保存する
 * @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);
}
    
%d人のブロガーが「いいね」をつけました。