Google ドライブ: ファイルダウンロード
この工程は、Google ドライブ内の指定ファイルをダウンロードします。一度に複数のダウンロードが可能です。複数ダウンロードする場合、データ項目では 1 行につき 1 つずつファイル ID を書くようにしてください。
Basic Configs
- 工程名
- メモ
Configs for this Auto Step
- conf_Auth
- C1: サービスアカウント設定 *
- conf_FileIds
- C2: ダウンロードするファイルの ID(1 行に 1 つ) *
- conf_FileData
- C3: ダウンロードファイルを追加保存するデータ項目 *
Notes
- ダウンロードするファイルは、事前に[C1: サービスアカウント設定]のサービスアカウントと共有しておく必要があります
- [C1: サービスアカウント設定]を設定するには:
- Google Cloud コンソールでサービスアカウントを準備します
- サービスアカウントキーを作成またはアップロードします
- Google Cloud コンソール上でサービスアカウントキーを作成すると、必要な情報を含む JSON ファイルをダウンロードできます
- サービスアカウントキーを作成またはアップロードします
- Questetra BPM Suite で OAuth2 JWT ベアラーフローの設定を作成し、C1 に設定します
- スコープ
https://www.googleapis.com/auth/drive.readonly
が必要です - 以降の項目は、下表のとおり設定してください
- スコープ
- Google Cloud コンソールでサービスアカウントを準備します
Questetra BPM Suite の設定項目 | 対応する Google Cloud サービスアカウントキーの情報 | JSON ファイルの項目名 | 設定必須かどうか |
---|---|---|---|
クライアント ID | OAuth2 クライアント ID | client_id | 任意 |
秘密鍵 ID | キー ID | private_key_id | 必須 |
秘密鍵 | 秘密鍵 | private_key | 必須 |
カスタム秘密情報 1 | メールアドレス | client_email | 必須 |
Capture
See Also
Script (click to open)
- 次のスクリプトが記述されている XML ファイルをダウンロードできます
- google-drive-file-download.xml (C) Questetra, Inc. (MIT License)
- Professional のワークフロー基盤では、ファイル内容を改変しオリジナルのアドオン自動工程として活用できます
const REQUEST_NUM_PER_FILE = 4; // ファイル 1 つにつき 4 回リクエストを行う
function main() {
////// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
const auth = configs.getObject('conf_Auth');
const fileIds = retrieveFileIds();
const fileDef = configs.getObject('conf_FileData');
let files = engine.findData( fileDef );
if (files === null) {
files = new java.util.ArrayList();
}
////// == 演算 / Calculating ==
if (fileIds.length * REQUEST_NUM_PER_FILE > httpClient.getRequestingLimit()) {
throw new Error('Number of File IDs exceeds the limit.');
}
fileIds.forEach(fileId => {
const {name, contentType} = getFileMetadata(auth, fileId);
const content = getFile(auth, fileId);
const qfile = new com.questetra.bpms.core.event.scripttask.NewQfile(
name, contentType, content
);
files.add(qfile);
});
////// == ワークフローデータへの代入 / Data Updating ==
engine.setData(fileDef, files);
}
/**
* config からファイル ID を読み出す
* ファイル ID が設定されていない場合はエラー
* @returns {Array<String>} ファイル ID の配列
*/
const retrieveFileIds = () => {
let fileIdsStr = configs.get('conf_FileIds');
const fileIdsDef = configs.getObject('conf_FileIds');
if (fileIdsDef !== null) {
fileIdsStr = engine.findData(fileIdsDef);
}
if (fileIdsStr === null) {
throw new Error('No File IDs.');
}
const fileIds = fileIdsStr.split('\n').filter(key => key.length !== 0);
if (fileIds.length === 0) {
throw new Error('No File IDs.');
}
return fileIds;
};
const URL_TOKEN_REQUEST = 'https://oauth2.googleapis.com/token';
const SCOPE = 'https://www.googleapis.com/auth/drive.readonly';
/**
* @param auth HTTP 認証設定
* @returns {any} アクセストークンを含むオブジェクト
*/
const getAccessToken = (auth) => {
const privateKeyId = auth.getPrivateKeyId();
const privateKey = auth.getPrivateKey();
const serviceAccount = auth.getCustomSecret1();
const scope = auth.getScope();
if (!scope.split(' ').includes(SCOPE)) {
throw new Error(`Scope ${SCOPE} must be included in the scope.`);
}
if (privateKeyId === '') {
throw new Error('Private Key ID is required.');
}
if (privateKey === '') {
throw new Error('Private Key is required.');
}
if (serviceAccount === '') {
throw new Error('Service Account must be set to Custom Secret 1.');
}
const header = {
"alg": "RS256",
"typ": "at+jwt",
"kid": privateKeyId
};
const now = Math.floor(Date.now() / 1000);
const payload = {
"iss": serviceAccount,
"aud": URL_TOKEN_REQUEST,
"sub": '',
"iat": now,
"exp": now + 3600,
/**
* https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth
* "without OAuth" の話だが、OAuth でも 1 hour になるようだ。
* 1 hour より長ければエラー。短ければ、1 hour のトークンが返ってくる。
*/
scope
};
const keyB = rsa.readKeyFromPkcs8(privateKey);
const assertion = jwt.build(header, payload, keyB);
const response = httpClient.begin()
.formParam("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
.formParam('assertion', assertion)
.post(URL_TOKEN_REQUEST);
const responseText = response.getResponseAsString();
if (response.getStatusCode() !== 200) {
engine.log(responseText);
throw new Error(`Failed to get Access token. status: ${response.getStatusCode()}`);
}
const result = JSON.parse(response.getResponseAsString());
if (result.access_token === undefined) {
engine.log(responseText);
throw new Error(`Failed to get Access token. access token not found.`);
}
return result;
};
/**
* ファイルメタデータ取得
* @param auth HTTP 認証設定
* @param fileId ファイルID
*/
const getFileMetadata = (auth, fileId) => {
const URL = `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}`;
const response = httpClient.begin()
.oauth2JwtBearer(auth, () => getAccessToken(auth))
.queryParam("supportsAllDrives", "true")
.get(URL);
const status = response.getStatusCode();
const respTxt = response.getResponseAsString();
if (status !== 200) {
engine.log(respTxt);
throw new Error(`Failed to get metadata of file. status: ${status}`);
}
const respJson = JSON.parse(respTxt);
return {
name: respJson.name,
contentType: respJson.mimeType
};
};
/**
* ファイル取得
* @param auth HTTP 認証設定
* @param fileId ファイルID
*/
const getFile = (auth, fileId) => {
const URL = `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}`;
const response = httpClient.begin()
.oauth2JwtBearer(auth, () => getAccessToken(auth))
.queryParam("supportsAllDrives", "true")
.queryParam("alt", "media")
.get(URL);
const status = response.getStatusCode();
const respTxt = response.getResponseAsString();
if (status !== 200) {
engine.log(respTxt);
throw new Error(`Failed to download file. status: ${status}`);
}
return response.getResponse();
};