kintone JS SDKを使ってアプリ&レコードコピー

kintone JS SDKを使って、指定したアプリとそのレコードを一括でコピーするコードを書いてみました。

コード

constkintone=require('@kintone/kintone-js-sdk');constfs=require('fs');constreduce=require('awaity/reduce').default;constauth=newkintone.Auth();auth.setBasicAuth({//Basic認証情報(必要な場合のみ)username:'\*\*\*\*',
  password:'\*\*\*\*'});auth.setPasswordAuth({//kintoneログインユーザー情報(「kintoneのシステム管理権限」、「コピー元アプリのアプリ・レコード・フィールドの閲覧権限」を持ったユーザー)username:'\*\*\*\*',
  password:'\*\*\*\*'});constconnection=newkintone.Connection({
  domain:'\*\*\*\*.cybozu.com',//kintoneのドメインauth:auth
});constoriginAppId=\*\*\*\*;//コピーするアプリのIDconstappApi=newkintone.App({connection});constrecordApi=newkintone.Record({connection});constfileApi=newkintone.File({connection});constcopyFile=asyncfile=\>{awaitfileApi.download({
    fileKey:file.fileKey,
    outPutFilePath:file.name});constfileUploadResponse=awaitfileApi.upload({filePath:file.name});fs.unlink(file.name, ()=\>{});returnfileUploadResponse.fileKey;
};constformatProperties=properties=\>(Object.fromEntries(Object.entries(properties).filter(([fieldCode])=\>(!['レコード番号','$id','$revision','作成者','更新者','作成日時','更新日時','カテゴリー','作業者','ステータス'].includes(fieldCode)
  )))
);constformatRecords=asyncrecords=\>await(Promise.all(records.map(asyncrecord=\>await(reduce(Object.entries(record).filter(([fieldCode])=\>(!['レコード番号','$id','$revision','作成者','更新者','作成日時','更新日時'].includes(fieldCode)
    )),async(record, [fieldCode, field])=\>{
      record[fieldCode]=field;if(field.type==='FILE'){
        record[fieldCode].value=awaitPromise.all(field.value.map(asyncfile=\>await({...file,
          fileKey:awaitcopyFile(file)
        })));
      }elseif(field.type==='SUBTABLE'){
        record[fieldCode].value=awaitPromise.all(field.value.map(asyncrow=\>await({...row,
          value:awaitreduce(Object.entries(row.value),async(rowValue, [fieldCode, field])=\>{
            rowValue[fieldCode]=field;if(field.type==='FILE'){
              rowValue[fieldCode].value=awaitPromise.all(field.value.map(asyncfile=\>await({...file,
                fileKey:awaitcopyFile(file)
              })));
            }returnrowValue;
          }, {})
        })));
      }returnrecord;
    }, {})
  )))
);

(async()=\>{constoriginApp=awaitPromise.all([appApi.getApp({id:originAppId}).then(app=\>({app})),appApi.getGeneralSettings({app:originAppId}).then(generalSettings=\>({generalSettings})),appApi.getFormFields({app:originAppId}).then(formFields=\>({formFields})),appApi.getFormLayout({app:originAppId}).then(formLayout=\>({formLayout})),appApi.getViews({app:originAppId}).then(views=\>({views})),recordApi.getAllRecordsByCursor({
      app:originAppId,
      query:'order by $id asc'}).then(records=\>({records}))
  ]).then(responses=\>{returnresponses.reduce((originApp,response)=\>{return{...originApp,
        [Object.keys(response)[0]]:Object.values(response)[0]
      };
    }, {});
  });constcopyAppName=`${originApp.app.name}\_copy\_${new Date()}`;//コピー先アプリ名constcopyAppId=awaitappApi.addPreviewApp({name:copyAppName}).then(response=\>response.app);awaitappApi.updateGeneralSettings({
    app:copyAppId,
    description:originApp.generalSettings.description,
    icon:originApp.generalSettings.icon,
    theme:originApp.generalSettings.theme});awaitappApi.addFormFields({
    app:copyAppId,
    fields:formatProperties(originApp.formFields.properties)
  });awaitappApi.updateFormLayout({
    app:copyAppId,
    layout:originApp.formLayout.layout});if(!originApp.views.views){awaitappApi.updateViews({
      app:copyAppId,
      views:originApp.views.views});
  }awaitappApi.deployAppSettings({apps:[{app:copyAppId}]});awaitnewPromise(resolve=\>{consttimer=setInterval(async()=\>{conststatus=awaitappApi.getAppDeployStatus({apps:[copyAppId]}).then(response=\>response.apps[0].status);if(status==='SUCCESS'){clearInterval(timer);resolve();
      }
    },1000);
  });awaitrecordApi.addAllRecords({
    app:copyAppId,
    records:awaitformatRecords(originApp.records.records)
  });console.log(`「${originApp.app.name}(appId:${originAppId})」を「${copyAppName}(appId:${copyAppId})」へコピーしました。`);
})();

・Node.js v12以上で動作します。(Object.fromEntries()を利用しているため。)
・「@kintone/kintone-js-sdk」及び「awaity」はnpm等でインストールして下さい。
・add、update処理に関してはエラーを避けるために直列処理としております。(参考)
・kintone REST API及びkintone JS SDKで対応していないアプリ設定値はコピーできません。
過去記事でPHP版も紹介しています。PHP版では、kintone REST APIで対応しているアプリ設定値は全てコピーできます。