
開始: Microsoft 365 OneDrive for Business: ファイルアップロード時
Start: Microsoft 365 OneDrive for Business: File Uploaded
このアイテムは、OneDrive の指定フォルダにファイルがアップロードされると、プロセスを開始します。
Basic Configs
- 工程名
- メモ
Configs for this Auto Step
- conf_OAuth2
- C1: OAuth2 設定 *
- conf_FolderUrl
- C2: 監視するフォルダの URL (空白の場合、ルートフォルダ)
- conf_urlData
- C3: ファイル URL を保存するデータ項目 *
- conf_timestampData
- C4: ファイルがアップロードされた日時を保存するデータ項目
Notes
- Microsoft 365 の OneDrive for Business で使用できる開始イベントです
- 個人用の OneDrive では使用できません
- ファイルやフォルダの URL は、OneDrive でファイルやフォルダの詳細ウィンドウ(右上の情報アイコン)から「その他の詳細」へ進み、「パス」の隣のアイコンから取得します

- 定期的に Questetra BPM Suite から OneDrive にポーリングが行われ、アップロードされているファイルがないか、チェックされます
- アップロードされているファイルがあれば、プロセスが開始されます
- 初回のチェック時には、プロセスは開始されません
- チェックのみ行われます。チェックの状況は、プロセスログより確認できます
- 短時間に多数のファイルがアップロードされると、全てのファイルについて、プロセスは開始されません
- 目安は、3 分 ~ 15 分間で 90 プロセスです
- フォルダ内に、多数 (2023 年 12 月現在 1000) のアイテム (ファイル / フォルダ) がある場合、チェックは中止されます
- アイテム数が増えすぎないように、コントロールしてください
Capture

Script (click to open)
- 次のスクリプトが記述されている XML ファイルをダウンロードできます
- onedrive-file-uploaded.xml (C) Questetra, Inc. (MIT License)
- コードの参考用にご利用ください
- アドオンとしてワークフローアプリにインポートすることはできません
// OAuth2 config sample at [OAuth 2.0 Setting]
// - Authorization Endpoint URL: https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/authorize
// - Token Endpoint URL: https://login.microsoftonline.com/{your-tenant-id}/oauth2/v2.0/token
// - Scope: https://graph.microsoft.com/Files.ReadWrite.All offline_access
// - Consumer Key: (Get by Microsoft Azure Active Directory)
// - Consumer Secret: (Get by Microsoft Azure Active Directory)
const DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX";
const GRAPH_URI = 'https://graph.microsoft.com/v1.0/';
const LIMIT = 1000; // API の制限は明記されていない。1000 件以上のファイル/フォルダがある場合はエラーにする
/**
* configs から必要な情報を取り出す
* @returns {Object} setting 設定
* @returns {string} setting.folderInfo 検索対象のフォルダの情報 {driveId, folderId}
* @returns {AuthSettingWrapper} setting.oauth2 OAuth2 設定
*/
const prepare = () => {
const oauth2 = configs.getObject('conf_OAuth2');
let folderUrl = configs.get('conf_FolderUrl');
const folderInfo = getFolderInfoByUrl(oauth2, folderUrl);
return {
oauth2,
folderInfo
};
};
/**
* フォルダの URL からフォルダ情報(ドライブのパスとフォルダ ID)を取得し、
* オブジェクトで返す(URL が空の場合はドライブのパスを me/drive、フォルダ ID を root にする)
* @param {AuthSettingWrapper} oauth2 OAuth2 認証設定
* @param {String} folderUrl フォルダのURL
* @return {Object} folderInfo フォルダ情報
* @return {String} folderInfo.drivePath ドライブのパス
* @return {String} folderInfo.folderId フォルダ ID
*/
const getFolderInfoByUrl = (oauth2, folderUrl) => {
if (folderUrl === '' || folderUrl === null) {
return {
drivePath: 'me/drive',
folderId: 'root'
};
}
const driveItem = getObjBySharingUrl(oauth2, folderUrl);
if (driveItem.folder === undefined) {
throw 'The specified URL is not a folder.';
}
return {
drivePath: `drives/${driveItem.parentReference.driveId}`,
folderId: driveItem.id
};
};
/**
* OneDriveのドライブアイテム(ファイル、フォルダ)のメタデータを取得し、JSONオブジェクトを返す
* APIの仕様: https://docs.microsoft.com/ja-jp/onedrive/developer/rest-api/api/shares_get?view=odsp-graph-online
* @param {AuthSettingWrapper} oauth2 OAuth2 認証設定
* @param {String} sharingUrl ドライブアイテムの共有 URL
* @return {Object} responseObj ドライブアイテムのメタデータのJSONオブジェクト
*/
const getObjBySharingUrl = (oauth2, sharingUrl) => {
const encodedSharingUrl = encodeSharingUrl(sharingUrl);
const response = httpClient.begin() // HttpRequestWrapper
.authSetting(oauth2) // Request HEADER (OAuth2 Token)
.queryParam('select', 'id,parentReference/driveId,folder')
.get(`${GRAPH_URI}shares/${encodedSharingUrl}/driveItem`); // HttpResponseWrapper
const httpStatus = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (httpStatus >= 300) {
const accessLog = `---GET request--- ${httpStatus}\n${responseStr}\n`;
engine.log(accessLog);
throw `Failed to get drive item. status: ${httpStatus}`;
}
return JSON.parse(response.getResponseAsString());
};
/**
* 共有URLをunpadded base64url 形式にエンコードする
* @param {String} sharingUrl 共有URL
* @return {String} encodedSharingUrl エンコードされた共有URL
*/
const encodeSharingUrl = (sharingUrl) => {
let encodedSharingUrl = base64.encodeToUrlSafeString(sharingUrl);
while (encodedSharingUrl.slice(-1) === '=') {
encodedSharingUrl = encodedSharingUrl.slice(0, -1);
}
return `u!${encodedSharingUrl}`;
};
/**
* ファイルの検索
* @param {number} limit ファイル数の上限
* @param {timestamp} timestampLowerLimit timestamp の下限
* @returns {Array} files ファイル一覧
* @returns {string} files[].id ファイル ID
* @returns {timestamp} files[].timestamp ファイルアップロード時刻
*/
const list = (limit, timestampLowerLimit) => {
const {
oauth2,
folderInfo
} = prepare();
const driveItems = getChildren(oauth2, folderInfo);
let files = driveItems
.filter(driveItem => driveItem.file !== undefined && !engine.isProcessStarted(driveItem.id)) // ファイルのみに絞り込み、かつ未開始のファイル
.map(formatFile) // 必要な情報のみ抜き出し、整形
.filter(file => !file.timestamp.before(timestampLowerLimit)) // timestampLowerLimit 以降のデータのみに絞り込み
.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()); // 新しい順に並べ替え
// 先頭から limit で切る
files = files.slice(0, limit);
logFiles(files);
return files;
};
/**
* 指定フォルダ内のドライブアイテムの一覧を取得する
* フォルダ内のドライブアイテム (ファイル+フォルダ) 数が 1000 を超える場合、エラー
* @param {AuthSettingWrapper} oauth2 OAuth2 設定
* @param {Object} folderInfo 検索対象のフォルダ情報 {drivePath, folderId}
* @returns {Array} driveItems ドライブアイテム一覧
* @returns {string} driveItems[].id ドライブアイテム ID
* @returns {timestamp} driveItems[].createdDateTime ドライブアイテム作成日時
* @returns {Object} driveItems[].file ドライブアイテムのファイル情報(ファイルかどうかを判定するために使用)
* @returns {string} driveItems[].webUrl ドライブアイテムの URL
*/
const getChildren = (oauth2, folderInfo) => {
const url = `${GRAPH_URI}${folderInfo.drivePath}/items/${folderInfo.folderId}/children`;
const response = httpClient.begin()
.authSetting(oauth2)
.queryParam('$top', `${LIMIT}`)
.queryParam('$select', 'id,createdDateTime,file,webUrl')
.get(url);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw `Failed to get children of the folder. status: ${status}`;
}
const json = JSON.parse(responseStr);
// 次のページを取得するリンクがある場合は、フォルダにまだファイル/フォルダがあるとみなして、エラーにする
const nextLink = json['@odata.nextLink'];
if (nextLink !== undefined) {
throw `More than ${LIMIT} items are in the specified folder.`;
}
return json.value;
}
/**
* OneDrive のファイルデータから、必要な部分のみ抜き出す
* @param file ファイルデータ
* @returns {Object} file ファイル
* @returns {string} file.id ファイル ID
* @returns {timestamp} file.timestamp ファイルアップロード時刻
*/
const formatFile = (file) => {
const {
id,
createdDateTime,
webUrl
} = file;
return {
id,
timestamp: dateFormatter.parse(DATETIME_FORMAT, createdDateTime),
url: webUrl
};
};
/**
* ファイルのログ出力
* @param {Array} files ファイル一覧
*/
const logFiles = (files) => {
if (files.length === 0) {
engine.log('no files');
return;
}
const replacer = (key, value) => value instanceof java.sql.Timestamp ? dateFormatter.format(DATETIME_FORMAT, value) : value;
files.forEach(file => engine.log(JSON.stringify(file, replacer)));
};
