Google ドライブ: ファイルコピー

Google ドライブ: ファイルコピー

Google Drive: Copy File

この工程は、Google ドライブ上の指定ファイルをコピーします。保存先のフォルダや新しいファイル名を任意で設定でき、作成さ れたファイルの ID や表示用 URL を保存できます。

Basic Configs
工程名
メモ
Auto Step icon
Configs for this Auto Step
conf_Auth
C1: サービスアカウント設定 *
conf_SourceFileId
C2: コピー元ファイルの ID *
conf_DestinationFolderId
C3: 保存先フォルダの ID(空欄の場合、コピー元と同じ場所に作成されます)
conf_NewFileName
C4: 新しいファイル名(空欄の場合、自動的に設定されます)#{EL}
conf_NewFileIdItem
C5: 作成されたファイル ID を保存するデータ項目
conf_NewFileUrlItem
C6: 作成されたファイルの表示用 URL を保存するデータ項目

Notes

  • ダウンロードするファイルは、事前に[C1: サービスアカウント設定]のサービスアカウントと共有しておく必要があります
  • [C1: サービスアカウント設定]を設定するには:
    1. Google Cloud コンソールでサービスアカウントを準備します
    2. Questetra BPM Suite で OAuth2 JWT ベアラーフローの設定を作成し、C1 に設定します
      • スコープ https://www.googleapis.com/auth/drive が必要です
      • 以降の項目は、下表のとおり設定してください
Questetra BPM Suite の設定項目対応する Google Cloud
サービスアカウントキーの情報
JSON ファイルの項目名設定必須かどうか
クライアント IDOAuth2 クライアント IDclient_id任意
秘密鍵 IDキー IDprivate_key_id必須
秘密鍵秘密鍵private_key必須
カスタム秘密情報 1メールアドレスclient_email必須

Errors

  • "code": 403, "message": "Google Drive API has not been used in project 123456789012 before or it is disabled."
    • 『Google Drive API』を有効化する必要があります。
  • "code": 404, "message": "File not found:"
    • ファイルが存在しない可能性があります。
    • 『Google サービスアカウント』がファイルへの閲覧権限を持っていない可能性があります。

Capture

See Also

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

const COPY_FIELDS = 'id,name,parents,webViewLink';

function main() {
    const auth = configs.getObject('conf_Auth');
    const sourceFileId = getSourceFileId();
    const destinationFolderId = getDestinationFolderId();
    const newFileName = getNewFileName();
    const newFileIdDataDef = configs.getObject('conf_NewFileIdItem');
    const newFileUrlDataDef = configs.getObject('conf_NewFileUrlItem');

    const copiedFile = copyFile(auth, sourceFileId, destinationFolderId, newFileName);

    engine.log(`Succeeded to copy. Source ID: ${sourceFileId}, New ID: ${copiedFile.id}`);

    if (newFileIdDataDef !== null) {
        engine.setData(newFileIdDataDef, copiedFile.id);
    }
    if (newFileUrlDataDef !== null) {
        const webViewUrl = copiedFile.webViewLink ?? `https://drive.google.com/file/d/${copiedFile.id}/view`;
        engine.setData(newFileUrlDataDef, webViewUrl);
    }
}

/**
 * コピー元のファイル ID を取得する
 * @return {String} コピー元ファイル ID
 */
function getSourceFileId() {
    let fileId = configs.get('conf_SourceFileId');
    const fileIdDef = configs.getObject('conf_SourceFileId');
    if (fileIdDef !== null) {
        fileId = engine.findData(fileIdDef);
    }
    if (fileId === null) {
        throw "Source File ID isn't set.";
    }
    const trimmed = fileId.trim();
    if (trimmed === '') {
        throw "Source File ID isn't set.";
    }
    return trimmed;
}

/**
 * 保存先フォルダ ID を取得する(未指定の場合は空文字を返す)
 * @return {String} 保存先フォルダ ID または空文字
 */
function getDestinationFolderId() {
    let folderId = configs.get('conf_DestinationFolderId');
    const folderIdDef = configs.getObject('conf_DestinationFolderId');
    if (folderIdDef !== null) {
        folderId = engine.findData(folderIdDef);
    }
    if (folderId === null) {
        return '';
    }
    return folderId.trim();
}

/**
 * 新しいファイル名を取得する(未指定の場合は空文字を返す)
 * @return {String} 新しいファイル名または空文字
 */
function getNewFileName() {
    const newName = configs.get('conf_NewFileName');
    if (newName === null) {
        return '';
    }
    return newName.trim();
}

/**
 * ファイルをコピーする
 * @param {HttpAuthSettingWrapper} auth 認証設定
 * @param {String} sourceFileId コピー元のファイル ID
 * @param {String} destinationFolderId 保存先フォルダ ID
 * @param {String} newFileName 新しいファイル名
 * @return {Object} コピー後のファイル情報
 */
function copyFile(auth, sourceFileId, destinationFolderId, newFileName) {
    const url = `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(sourceFileId)}/copy`;
    const body = {};
    if (destinationFolderId !== '') {
        body.parents = [destinationFolderId];
    }
    if (newFileName !== '') {
        body.name = newFileName;
    }

    const response = httpClient.begin()
        .oauth2JwtBearer(auth, () => getAccessToken(auth))
        .queryParam('fields', COPY_FIELDS)
        .queryParam('supportsAllDrives', 'true')
        .body(JSON.stringify(body), 'application/json; charset=UTF-8')
        .post(url);

    const status = response.getStatusCode();
    const responseBody = response.getResponseAsString();
    if (status >= 300) {
        engine.log(responseBody);
        throw `Failed to copy. Source ID: ${sourceFileId}, status: ${status}`;
    }

    let json;
    try {
        json = JSON.parse(responseBody);
    } catch (error) {
        throw `Failed to parse response. Source ID: ${sourceFileId}`;
    }

    if (json.id === undefined) {
        throw `Failed to retrieve new file information. Source ID: ${sourceFileId}`;
    }

    return json;
}

const URL_TOKEN_REQUEST = 'https://oauth2.googleapis.com/token';
const SCOPE = 'https://www.googleapis.com/auth/drive';

/**
 * @param {HttpAuthSettingWrapper} auth HTTP 認証設定
 * @returns {{access_token: string}} アクセストークンを含むオブジェクト
 */
function 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,
        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(responseText);
    if (result.access_token === undefined) {
        engine.log(responseText);
        throw new Error('Failed to get Access token. access token not found.');
    }
    return result;
}

Questetra Supportをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む