開始: Microsoft 365 OneDrive for Business: ファイルアップロード時

開始: Microsoft 365 OneDrive for Business: ファイルアップロード時

Start: Microsoft 365 OneDrive for Business: File Uploaded

このアイテムは、OneDrive の指定フォルダにファイルがアップロードされると、プロセスを開始します。

Basic Configs
工程名
メモ
Auto Step icon
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)));
};

上部へスクロール

Questetra Supportをもっと見る

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

続きを読む