2023-02-09 (C) Questetra, Inc. (MIT License) 2 2 This item downloads the specified file on Box in the specified file format. この工程は、Box 上のファイルを指定形式でダウンロードします。 https://support.questetra.com/bpmn-icons/service-task-box-file-representation-download/ https://support.questetra.com/ja/bpmn-icons/service-task-box-file-representation-download/ iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAEBElEQVRYR82Xb2jbRRjHP/fL2jXJ 0qSd65x11aK0YgJWZUwEWZ0DfSNaHYKKmgykbP7pH/SVghvCkIlb6kREwfyGOougbgxB2Yt1oGwg aietdOJoV21ty2ob26xdm+TkLsufJr+2Sdtt3pv8uDx3z+ee+z53zwmucRMF+ff/9ijEtwB1IDwI 9QtIOkGOA50I0UHIezTfeRcH8Pd64GITyGaE8OQ1sVQwIgiONsxqBTZvWxjA3+UHDuTtONuNBjEC mLcfmY9gfgB/dxBBU14rXsxIyiCmr8XKzBog0GWCeG6xeQv6X2JiegPZY3IBVnLlOVtCG6a3ObN7 LoDacyFCBa2sUGMpGjI1kQbQao/0Lllw+YJoYTqrk9mRAdC9G8Eb+c6zLDvJHkzvbjVHGiDQpXLX nZw4tOMGyp02Hjn457J8WQ5WUTB9ZWkAdcIJ+XWm8XCwFkexwLWrZ+UB9OmZ0EIiAhbKH2lLAKzZ eaUAEhmRAAh0dYBQZ3yqKQDnaoPDp8PUVZXo/pM9EV75Ylh/77q/jO2bSlmz2mBgLErjoUHad95I Z/80re0Jmw+e3UD1dcU8uP+8RRTlSUK++ssA3X3ATdkA61y2nIE/9k7Rd2GWx+4uxWZkAP8bo9Ru YAho+XyIUruNNxsqiMzE8bxgEUV1gZneO5MAMtuTioACUM7e+W4Uj8Pg5W1rdV9cwvSsxPx+nNPn LvLStnI2VdsZi8TwOGyMTsY0nNth493j/9DSPmSto5BXLAigsmDLW7388MeUnuDVh9ay74n1+vvI zxM0vJfOkNGDtdiLDH7pn+beW+3a5kRPhK37rMJ/mScDIGcLBvfXsM61isrWs4xMxPSIpza7+ayx Un8rbTz94UBqZX8fqNFp+82vkzTc5dL9n54K88xHaZu5YZBnCPnq5hXhqdequecWO2rPH3j7PBvc qzjWVEXN9cV6HhVmJbwvf5rgcGMlT2526y1wldiYiUl9wKhtUHp4/8TYIiK0SMP6WgdfvbiRMqeN yKU4NkNQUiToH51lcDyq4aIxtMjcdoOpGYkSkrJpOz6qt6OxvowLkzEqms7mAsjMNLQ4iNSIrbc5 2bu9QqdSNC7pHrjEjo8H+GssyifPV3JfjQNHscFQOMqeoyPsfXw9vw/P8HBbv3b4bWsVG8uL8L5+ zgIg8yBSf2cdxdayXaleGSbk0+Xd/+gyUtexiPRlXkgrtd4s9YeRzptzr2NldU0LkiTmlS3JUnVA 0t3VK0qRhwj5VJk/p12lsjxdAeUPoDWhCpW4KtFTlVJhwpRhpOFf2sMkpQn9NGtGyOb8QZRj/TQL Lu9plr1c/TiV9QipHqUeEHckTOQZYBwpOkF0LLTiwragsHgvyfo/g3CBMFgjn40AAAAASUVORK5C YII= { configs.put('conf_OAuth2', 'Box'); // ファイル ID を保存した文字型データ項目(単一行)を準備し、設定 const fileIdDef = engine.createDataDefinition('ファイル ID', 1, 'q_FileId', 'STRING_TEXTFIELD'); engine.setData(fileIdDef, fileId); configs.putObject('conf_FileId', fileIdDef); configs.put('conf_Representation', representation); configs.put('conf_FileName', fileName); // ファイルの保存先データ項目を準備し、設定 const fileDef = engine.createDataDefinition('ファイル', 3, 'q_files', 'FILE'); configs.putObject('conf_Files', fileDef); engine.setData(fileDef, files); // ダウンロード URL を一時的に保存するデータ項目を準備し、設定 const urlTemplateDef = engine.createDataDefinition('URL Template', 2, 'q_url', 'STRING_TEXTFIELD'); configs.putObject('conf_urlTemplate', urlTemplateDef); engine.setData(urlTemplateDef, urlTemplate); return { urlTemplateDef, fileDef }; } /** * 異常系のテスト * @param func * @param errorMsg */ const assertError = (func, errorMsg) => { try { func(); fail(); } catch (e) { expect(e.toString()).toEqual(errorMsg); } } /** * ファイル ID の値が空でエラー */ test('File ID is blank', () => { prepareConfigs(null, '[pdf]', '', null, null); assertError(main, 'File ID is blank.'); }); /** * レプリゼンテーションの情報を取得する API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param request.headers * @param fileId * @param representation */ const assertGetRepInfoRequest = ({url, method, headers}, fileId, representation) => { expect(url).toEqual(`https://api.box.com/2.0/files/${encodeURIComponent(fileId)}?fields=representations`); expect(method).toEqual('GET'); expect(headers.get('X-REP-HINTS')).toEqual(representation); }; /** * レプリゼンテーションの情報を取得する API リクエストで失敗 */ test('Fail in API Request to get representation info', () => { const fileId = 'fileId-1'; const representation = '[pdf]'; prepareConfigs(fileId, representation, '', null, null); httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); assertError(main, 'Failed to get representations. status:400'); }); /** * 指定したレプリゼーションに対応しておらずエラーになる場合 */ test('Unavailable representation', () => { const fileId = 'fileId-1'; const representation = '[pdf]'; prepareConfigs(fileId, representation, '', null, null); const responseObj = { "representations": { "entries": [] } }; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(responseObj)); }); assertError(main, 'The [pdf] representation is unavailable for this file.'); }); const REP_INFO_TEMPLATE = { "representations": { "entries": [ { "properties": {}, "content": {} } ] } }; /** * PDF レプリゼーション情報のレスポンスオブジェクトを作成 * @param fileId * @return responseObj */ const createPDFRepresentationInfo = (fileId) => { const responseObj = JSON.parse(JSON.stringify(REP_INFO_TEMPLATE)); // ディープコピー const urlTemplate = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/pdf/representation/{+asset_path}`; responseObj.representations.entries[0].content['url_template'] = urlTemplate; return responseObj; } /** * テキストレプリゼーション情報のレスポンスオブジェクトを作成 * @param fileId * @return responseObj */ const createTextRepresentationInfo = (fileId) => { const responseObj = JSON.parse(JSON.stringify(REP_INFO_TEMPLATE)); // ディープコピー const urlTemplate = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/text/representation/{+asset_path}`; responseObj.representations.entries[0].content['url_template'] = urlTemplate; return responseObj; } /** * 画像レプリゼーション情報のレスポンスオブジェクトを作成 * @param fileId * @param paged * @return responseObj */ const createImageRepresentationInfo = (fileId, paged) => { const responseObj = JSON.parse(JSON.stringify(REP_INFO_TEMPLATE)); // ディープコピー const urlTemplate = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/image/representation/{+asset_path}`; responseObj.representations.entries[0].content['url_template'] = urlTemplate; responseObj.representations.entries[0].properties['paged'] = paged; return responseObj; } /** * レプリゼンテーションをダウンロードする API リクエストのテスト * @param {Object} request * @param request.url * @param request.method * @param downloadUrl */ const assertDownloadRepRequest = ({url, method}, downloadUrl) => { expect(url).toEqual(`${downloadUrl}?set_content_disposition_type=attachment`); expect(method).toEqual('GET'); }; /** * PDF レプリゼーションをダウンロードする API リクエストで失敗 */ test('Fail in API Request to download PDF representation', () => { const fileId = 'fileId-1'; const representation = '[pdf]'; const {urlTemplateDef} = prepareConfigs(fileId, representation, '', null, null); const repInfo = createPDFRepresentationInfo(fileId); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/pdf/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, downloadUrl); return httpClient.createHttpResponse(400, 'application/json', '{}'); }); assertError(proceed, 'Failed to download the representation [pdf]. status:400'); }); /** * ファイルのテスト * @param file * @param name * @param contentType * @param encoding * @param body */ const assertFile = (file, name, contentType, encoding, body) => { expect(file.getName()).toEqual(name); expect(file.getContentType()).toEqual(contentType); let text = ''; fileRepository.readFile(file, encoding, line => text += line + '\n'); expect(text).toEqual(body); }; /** * PDF レプリゼーションのダウンロードに成功 * ファイル名指定なし * 他のファイルの保存なし */ test('Succeed to download PDF representation', () => { const fileId = 'fileId-1'; const representation = '[pdf]'; const { fileDef, urlTemplateDef } = prepareConfigs(fileId, representation, '', null, null); // ファイル名指定なし、事前ファイルなし const originalFileName = '元の名前.pdf'; const repInfo = createPDFRepresentationInfo(fileId); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/pdf/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl); httpClient.setRequestHandler(request => { assertDownloadRepRequest(request, downloadUrl); const response = httpClient.createHttpResponse(200, 'application/pdf', 'This is the content of PDF'); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); return response; }); expect(proceed()).toEqual(undefined); const savedFiles = engine.findData(fileDef); expect(savedFiles.size()).toEqual(1); assertFile(savedFiles.get(0), originalFileName, 'application/pdf', 'UTF-8', 'This is the content of PDF\n'); expect(engine.findData(urlTemplateDef)).toEqual(null); }); /** * PDF レプリゼーションのダウンロードに成功 * ファイル名を指定 * 他のファイルの保存あり */ test('Succeed to download PDF representation - fileName specified', () => { const fileId = 'fileId-3'; const representation = '[pdf]'; const fileName = 'ダウンロードファイル.pdf'; // 事前ファイルを 1 つ追加 const files = new java.util.ArrayList(); files.add(new com.questetra.bpms.core.event.scripttask.NewQfile('事前ファイル.csv', 'text/csv; charset=UTF-8', 'あいうえお')); const { urlTemplateDef, fileDef } = prepareConfigs(fileId, representation, fileName, null, files); const originalFileName = '元の名前.pdf'; // 使用しないが、条件を同じにするためにレスポンスのヘッダにセット const repInfo = createPDFRepresentationInfo(fileId); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/pdf/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, downloadUrl); const response = httpClient.createHttpResponse(200, 'application/pdf', 'This is the content of PDF'); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); return response; }); expect(proceed()).toEqual(undefined); const savedFiles = engine.findData(fileDef); expect(savedFiles.size()).toEqual(2); assertFile(savedFiles.get(1), fileName, 'application/pdf', 'UTF-8', 'This is the content of PDF\n'); expect(engine.findData(urlTemplateDef)).toEqual(null); }); /** * テキストレプリゼーションのダウンロードに成功 * ファイル名指定なし * 他のファイルの保存なし */ test('Succeed to download TEXT representation', () => { const fileId = 'fileId-4'; const representation = '[extracted_text]'; const { urlTemplateDef, fileDef } = prepareConfigs(fileId, representation, '', null, null); // ファイル名指定なし、事前ファイルなし const originalFileName = '元の名前.text'; const repInfo = createTextRepresentationInfo(fileId); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/text/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, downloadUrl); const response = httpClient.createHttpResponse(200, 'text/plain; charset=UTF-8', '抽出されたテキスト'); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); return response; }); expect(proceed()).toEqual(undefined); const savedFiles = engine.findData(fileDef); expect(savedFiles.size()).toEqual(1); assertFile(savedFiles.get(0), originalFileName, 'text/plain', 'UTF-8', '抽出されたテキスト\n'); expect(engine.findData(urlTemplateDef)).toEqual(null); }); /** * JPEG レプリゼーション(ページ割なし)のダウンロードに成功 * 1 度は、作成中でダウンロードに失敗。 * ファイル名指定なし * 他のファイルの保存なし */ test('Succeed to download JPEG representation', () => { const fileId = 'fileId-5'; const representation = '[jpeg?dimensions=32x32]'; const { urlTemplateDef, fileDef } = prepareConfigs(fileId, representation, '', null, null); // ファイル名指定なし、事前ファイルなし const originalFileName = '元の名前.jpg'; const repInfo = createImageRepresentationInfo(fileId, 'false'); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/image/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, downloadUrl); return httpClient.createHttpResponse(202, 'application/json', '{}'); // 作成中でダウンロードできない場合のステータスは 202 }); expect(proceed()).toEqual(false); expect(engine.findData(fileDef)).toEqual(null); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, downloadUrl); const response = httpClient.createHttpResponse(200, 'image/jpeg', 'This is the content of JPEG'); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); return response; }); expect(proceed()).toEqual(undefined); const savedFiles = engine.findData(fileDef); expect(savedFiles.size()).toEqual(1); assertFile(savedFiles.get(0), originalFileName, 'image/jpeg', 'UTF-8', 'This is the content of JPEG\n'); expect(engine.findData(urlTemplateDef)).toEqual(null); }); /** * PNG レプリゼーション(ページ割あり)のダウンロードに失敗 */ test('Fail in API Request to download PNG representation', () => { const fileId = 'fileId-1'; const representation = '[png?dimensions=1024x1024]'; const { urlTemplateDef, fileDef } = prepareConfigs(fileId, representation, '', null, null); // ファイル名指定なし、事前ファイルなし const repInfo = createImageRepresentationInfo(fileId, 'true'); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/image/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl + "{+asset_path}"); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, `${downloadUrl}1.png`); return httpClient.createHttpResponse(404, 'application/json', '{}'); }); assertError(proceed, 'Failed to download the page 1 of the representation [png?dimensions=1024x1024]. status:404'); }); /** * PNG レプリゼーション(ページ割あり)のダウンロードに成功 * 1 度は、作成中でダウンロードに失敗。 * ファイル名指定なし * 他のファイルの保存なし */ test('Succeed to download PNG representation', () => { const fileId = 'fileId-6'; const representation = '[png?dimensions=1024x1024]'; const { urlTemplateDef, fileDef } = prepareConfigs(fileId, representation, '', null, null); // ファイル名指定なし、事前ファイルなし const originalFileName = '元の名前.png'; const repInfo = createImageRepresentationInfo(fileId, 'true'); const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/image/representation/`; httpClient.setRequestHandler((request) => { assertGetRepInfoRequest(request, fileId, representation); return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(repInfo)); }); expect(main()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl + "{+asset_path}"); // 作成中でダウンロードできない httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, `${downloadUrl}1.png`); return httpClient.createHttpResponse(202, 'application/json', '{}'); // 作成中でダウンロードできない場合のステータスは 202 }); expect(proceed()).toEqual(false); expect(engine.findData(urlTemplateDef)).toEqual(downloadUrl + "{+asset_path}"); let reqCount = 1; const pageNum = 3; httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, `${downloadUrl}${reqCount}.png`); if (reqCount <= pageNum) { const response = httpClient.createHttpResponse(200, 'image/png', `This is the content of PNG, page ${reqCount}`); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); reqCount++; return response; } return httpClient.createHttpResponse(404, 'application/json', '{}'); }); expect(proceed()).toEqual(undefined); const savedFiles = engine.findData(fileDef); expect(savedFiles.size()).toEqual(pageNum); for (let i = 0; i < pageNum; i++) { assertFile(savedFiles.get(i), `${i + 1}-${originalFileName}`, 'image/png', 'UTF-8', `This is the content of PNG, page ${i + 1}\n`); } expect(engine.findData(urlTemplateDef)).toEqual(null); }); /** * JPEG レプリゼーション(ページ割あり)のダウンロードに成功 * ページ割数は、HTTP リクエスト数の上限 * HTTP リクエスト数の関係で、proceed() のみのテスト * ファイル名を指定 * 他のファイルの保存あり */ test('proceed() Succeed to download Paged JPEG representation - fileName specified', () => { const fileId = 'fileId-7'; const representation = '[jpg?dimensions=2048x2048]'; const fileName = 'ダウンロードファイル.jpg'; const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/image/representation/`; // 事前ファイルを 2 つ追加 const files = new java.util.ArrayList(); files.add(new com.questetra.bpms.core.event.scripttask.NewQfile('事前ファイル1.csv', 'text/csv; charset=UTF-8', 'あいうえお')); files.add(new com.questetra.bpms.core.event.scripttask.NewQfile('事前ファイル2.csv', 'text/csv; charset=UTF-8', 'かきくけこ')); const { urlTemplateDef, fileDef } = prepareConfigs('', representation, fileName, downloadUrl + "{+asset_path}", files); const originalFileName = '元の名前.pdf'; // 使用しないが、条件を同じにするためにレスポンスのヘッダにセット const pageNum = httpClient.getRequestingLimit() - 1; // 上限のページ数でテスト let reqCount = 1; httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, `${downloadUrl}${reqCount}.jpg`); if (reqCount <= pageNum) { const response = httpClient.createHttpResponse(200, 'image/jpg', `This is the content of JPEG, page ${reqCount}`); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); reqCount++; return response; } return httpClient.createHttpResponse(404, 'application/json', '{}'); }); expect(proceed()).toEqual(undefined); const savedFiles = engine.findData(fileDef); expect(savedFiles.size()).toEqual(pageNum + 2); for (let i = 0; i < pageNum; i++) { assertFile(savedFiles.get(i + 2), `${i + 1}-${fileName}`, 'image/jpg', 'UTF-8', `This is the content of JPEG, page ${i + 1}\n`); } expect(engine.findData(urlTemplateDef)).toEqual(null); }); /** * ページ数が多く、リクエスト数の上限を超える */ test('proceed() sNumber of necessary HTTP requests exceeds the limit', () => { const fileId = 'fileId-1'; const representation = '[png?dimensions=1024x1024]'; const downloadUrl = `https://public.boxcloud.com/api/2.0/internal_files/${fileId}/path/to/the/image/representation/`; prepareConfigs('', representation, null, downloadUrl + "{+asset_path}", null); const originalFileName = '元の名前.png'; let reqCount = 1; const pageNum = httpClient.getRequestingLimit(); httpClient.setRequestHandler((request) => { assertDownloadRepRequest(request, `${downloadUrl}${reqCount}.png`); if (reqCount <= pageNum) { const response = httpClient.createHttpResponse(200, 'image/png', `This is the content of PNG, page ${reqCount}`); response.addHeader('Content-Disposition', `attachment;filename*=UTF-8''${encodeURI(originalFileName)}`); reqCount++; return response; } return httpClient.createHttpResponse(404, 'application/json', '{}'); }); assertError(proceed, 'Number of necessary HTTP requests exceeds the limit.'); }); ]]>