Google Apps Scriptを用いて、kintoneの指定したアプリ、フィールドに格納したい

何を実現したいのかを書きましょう

Google Apps Scriptを用いて、Googleドライブに格納してあるPDFファイルを、kintoneのファイルフィールドに格納したいです。

発生した問題やエラーメッセージを具体的に書きましょう

エラーメッセージなどは特に表示されず、またkintoneの格納対象としているフィールドの設定やAPIキーの設定に問題な無く、また手動で格納は出来ていますが、スクリプトを実行しても格納がされないのが現状です。

スクリプト内で指定しているkintoneのドメインやAPP_ID、その他kintoneと紐づける為の指定した値も見直しましたが、他に留意するべき点はありますか?

実行したコードをコピー&ペーストしましょう

// ④: 格納したPDFファイルを、kintoneの指定したアプリの指定したフィールドに格納する。
function uploadPDFtoKintone(pdfFileId, recordId, fileName, kintoneAppId, kintoneFieldCode) {
  var kintoneApiToken = 'APITOKEN_SAMPLE'; // kintoneのAPIトークンは置き換えています

  var file = DriveApp.getFileById(pdfFileId);
  var apiUrl = 'https://sample.cybozu.com/k/v1/file.json'; //URLは置き換えています

  // ファイルのBlobを取得
  var blob = file.getBlob();

  // マルチパート形式のデータを構築
  var payload = Utilities.newBlob('--BOUNDARY\r\n' +
    'Content-Disposition: form-data; name="file"; filename="' + fileName + '"\r\n' +
    'Content-Type: application/pdf\r\n\r\n' +
    blob.getBytes() +
    '\r\n--BOUNDARY--');

  var headers = {
    'X-Cybozu-API-Token': kintoneApiToken,
    'X-Requested-With': 'XMLHttpRequest',
  };

  var options = {
    'method': 'POST',
    'headers': headers,
    'contentType': 'multipart/form-data; boundary=BOUNDARY',
    'payload': payload,
    'muteHttpExceptions': true,
  };

  // アプリIDとフィールドコードをURLに追加
  apiUrl += '?app=' + kintoneAppId + '&record=' + recordId + '&field=' + kintoneFieldCode;

  var response = UrlFetchApp.fetch(apiUrl, options);

  // レスポンスのログを出力
  Logger.log(response.getContentText());

  // レスポンスが成功したかどうかを確認
  if (response.getResponseCode() === 200) {
    Logger.log('File uploaded successfully.');
    
    // ファイルがアップロードされたか確認
    var uploadedFileInfo = JSON.parse(response.getContentText());
    if (uploadedFileInfo.fileKey) {
      Logger.log('File Key: ' + uploadedFileInfo.fileKey);
    } else {
      Logger.log('File key not found in the response.');
    }
  } else {
    Logger.log('File upload failed. Response code: ' + response.getResponseCode());
  }
}

追加の情報ですが、APIリクエストの中身を見る限り、エラーは無くresponse.getResponseCode() === 200を指しています。

kintone側で何かアクセス制限等があるのでしょうか?

こんにちは。

API で添付ファイルフィールドにファイルをアップロードする場合、
以下の流れで API を実行する必要があります。

  1. ファイルアップロード API でファイルを kintone にアップロードする
    1. のレスポンスから fileKey を取得する
  2. レコードを操作する API の POST や PUT を実行して、
    添付ファイルフィールドに 2. の fileKey を紐づける

記載していただいている処理では、1. の処理部分で添付ファイルフィールドへの
ファイルの紐付けまで実行しようとしているように見えるので、
上手く動作していないのかなと思います。
(ファイルアップロードAPI は、アプリIDなどのパラメーターは指定できないです)

API で添付ファイルフィールドにファイルを設定する処理の流れは、
以下のページで紹介されているので、確認してもらえればと思います。

3 Likes

@ko_ji
ご回答を頂いてから、お返事が滞ってしまい大変申し訳ございません。。。

結論から言うと、共有いただいた手順を参考に、GASを使ってtextファイルをkintoneアプリの特定の添付ファイルフィールドにアップロードすることができました。
ありがとうございます!!

一方で、PDFファイルをアップロードすることもできましたが
kintoneへアップロードしたファイルをダウンロードして展開すると
「ファイルを読み込めませんでした」というエラーが出てしまいます。
破損しているのか、Base64へのエンコードがうまくいっていないのか原因が特定できずです。。。
誠に勝手ながらも、本件に関してもご助言いただけると大変ありがたいです :bowing_woman:

// PDFファイルを変換してアップロードする関数
function upload() {

  var fileBlob = DriveApp.getFileById('<ファイルID>').getBlob();
  var fileData = Utilities.base64Encode(fileBlob.getBytes());

  var headers = {
    'Content-Type': 'multipart/form-data; boundary=myboundary',
    'X-Cybozu-API-Token' : '<APIトークン>'
  }

  var body =
    '--myboundary\r\n' +
    'Content-Disposition: form-data; name="file"; filename="PDFファイル.pdf"\r\n' +
    'Content-Type: application/pdf\r\n\r\n' +
    fileData +
    '\r\n--myboundary--';

  var options = {
    'method': 'post',
    'headers': headers,
    'payload': body,
  };

  var response = getUploadFileKey(
    Library.kintoneDomain,
    Library.venderInvoiceManagementAppId,
    options
  );

  var uploadfileKey = JSON.parse(response).fileKey;
  Logger.log(uploadfileKey);
  associateFileWithRecord(uploadfileKey);
}

// ファイルキーを取得する関数
function getUploadFileKey(kintoneDomain,appId,options){

  const kintoneUrl = `https://${kintoneDomain}.cybozu.com/k/v1/file.json?app=${appId}`;
  const response = UrlFetchApp.fetch(kintoneUrl,options);

  return response.getContentText();
}

// レスポンスから取得したfileKeyをフィールドコードに紐づける処理
function associateFileWithRecord(uploadfileKey) {
  var appId = Library.venderInvoiceManagementAppId;
  var recordId = '1';
  var apiToken = '<APIトークン>';

  var recordData = {
    app: appId,
    id: recordId,
    record: {
      '<フィールドコード>': {
        value: [{ fileKey: uploadfileKey }]
      }
    }
  };

  // REST APIのURL
  const kintoneUrl = `https://${Library.kintoneDomain}.cybozu.com/k/v1/record.json?app=${appId}`;

  // リクエストヘッダー
  var headers = {
    'X-Cybozu-API-Token': apiToken,
    'Content-Type': 'application/json'
  };

  // レコードの更新リクエストを送信
  var response = UrlFetchApp.fetch(kintoneUrl, {
    method: 'put',
    headers: headers,
    payload: JSON.stringify(recordData)
  });

  // レスポンスを確認(成功したかどうかなど)
  var responseBody = response.getContentText();
  Logger.log(responseBody);
}

@ud.project

過去の投稿を見てみると、同様な現象について質問/回答されているページが
見つかったので、以下のページが参考になるかと思います!

2 Likes

ありがとうございます!!
確認いたします!!

(ちなみに予想だと、Base64へのエンコードが正常に行われていないか
kintoneが正常にPDFへデコードできていないかのどちらかだと思っています)

@ko_ji

共有していただいたページを参考に(ほぼコピペですが ^_^;)
正常にkintoneにアップロードできました!
本当にありがとうございます!!

requestBodyの作成過程が違っていたみたいです。
元はbase64にエンコードしたものを繋げてrequestbodyにしていましたが
共有していただいたページでは、blobにエンコードしてそれらを繋げていただけでした。

2 Likes

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。