Microsoft Lists: リストアイテム取得

Microsoft Lists: リストアイテム取得

Microsoft Lists: Get List Item

この工程は、Microsoft Lists のリストアイテム(1件)の内容を取得します。

Basic Configs
工程名
メモ
Auto Step icon
Configs for this Auto Step
conf_OAuth2
C1: OAuth2 設定 *
conf_SiteUrl
C2: SharePoint サイトの URL *
conf_ListTitle
C3: リストの名前 *
conf_ListItemId
C4: リストアイテム ID *
conf_ColumnName1
C-K1: 列 1 の Lists フィールド名
conf_ColumnValue1
C-V1: 列 1 の値を保存するデータ項目
conf_ColumnName2
C-K2: 列 2 の Lists フィールド名
conf_ColumnValue2
C-V2: 列 2 の値を保存するデータ項目
conf_ColumnName3
C-K3: 列 3 の Lists フィールド名
conf_ColumnValue3
C-V3: 列 3 の値を保存するデータ項目
conf_ColumnName4
C-K4: 列 4 の Lists フィールド名
conf_ColumnValue4
C-V4: 列 4 の値を保存するデータ項目
conf_ColumnName5
C-K5: 列 5 の Lists フィールド名
conf_ColumnValue5
C-V5: 列 5 の値を保存するデータ項目
conf_ColumnName6
C-K6: 列 6 の Lists フィールド名
conf_ColumnValue6
C-V6: 列 6 の値を保存するデータ項目
conf_ColumnName7
C-K7: 列 7 の Lists フィールド名
conf_ColumnValue7
C-V7: 列 7 の値を保存するデータ項目

Notes

  • SharePoint サイトの URL は、リスト URL の /Lists より前の部分です
    • マイリスト内のリストの場合、https://{サブドメイン}-my.sharepoint.com/personal/{ユーザ識別子}_{サブドメイン}_onmicrosoft_com のような形式です
    • SharePoint サイト内のリストの場合、https://{サブドメイン}.sharepoint.com/sites/{サイト識別子} のような形式です
  • フィールド名を取得する方法はいくつかあります
    • リストのスキーマ付き CSV をエクスポートすると、各列のスキーマ内の Name プロパティの値がフィールド名です
    • WebUI でリストを表示し、列の値で並び替えを行うと、URL に sortField={フィールド名} の形式でフィールド名が含まれます
  • Questetra BPM Suite の各データ型について、保存をサポートしている Microsoft Lists の列タイプは、下表の通りです:
Questetra BPM Suite のデータ型保存をサポートする Microsoft Lists の列タイプ
文字(複数行)1 行テキスト、複数行テキスト、数、Yse/No、日付と時刻、選択肢、通貨
文字(単一行)1 行テキスト、数、Yes/No、日付と時刻、選択肢(複数選択を許可していない場合)、通貨
数値数、通貨
選択(ラジオボタン、セレクトボックス、検索セレクトボックス)Yes/ No、選択肢(複数選択を許可していない場合)
※ 列の値は、一致する選択肢 ID をもつ選択肢として保存されます
選択(チェックボックス)選択肢(複数選択を許可している場合)
※ 列の値は、一致する選択肢 ID をもつ選択肢として保存されます
日付、日時日付と時刻
※ Microsoft Lists で表示される日付と時刻は、SharePoint サイトのタイムゾーン設定(Microsoft 365 アカウントのタイムゾーン設定とは異なります)に応じたものです
※ SharePoint サイトのタイムゾーン設定と、Questetra BPM Suite のタイムゾーン設定が異なる場合、表示される日付、日時にずれが生じます

Capture

See Also

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

// 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/Sites.ReadWrite.All offline_access
// - Consumer Key: (Get by Microsoft Azure Active Directory)
// - Consumer Secret: (Get by Microsoft Azure Active Directory)

const GRAPH_URI = 'https://graph.microsoft.com/v1.0/';

const COLUMN_NUM = 7; // 扱える列の数

const main = () => {
    //// == 工程コンフィグの参照 / Config Retrieving ==
    const oauth2 = configs.getObject('conf_OAuth2');
    const siteUrl = retrieveSiteUrl();
    const listTitle = configs.get('conf_ListTitle');
    const listItemId = retrieveListItemId();
    const {columnNames, columnDefs} = retrieveColumnNamesAndDataDefs();

    //// == 演算 / Calculating ==
    const siteId = getSiteIdByUrl(oauth2, siteUrl);
    checkColumns(oauth2, siteId, listTitle, columnNames, columnDefs);
    const listItem = getListItem(oauth2, siteId, listTitle, listItemId, columnNames);

    //// == ワークフローデータへの代入 / Data Updating ==
    saveData(listItem, columnNames, columnDefs);
};

/**
 * 工程コンフィグからサイトの URL を取得する
 * @returns {String} サイトの URL
 */
const retrieveSiteUrl = () => {
    let siteUrl = configs.get('conf_SiteUrl');
    // 末尾にスラッシュがある場合、削除
    if (siteUrl.endsWith('/')) {
        siteUrl = siteUrl.slice(0, -1);
    }
    return siteUrl;
};

/**
 * 工程コンフィグからリストアイテム ID を取得する
 * @returns {String} リストアイテム ID
 */
const retrieveListItemId = () => {
    const dataDef = configs.getObject('conf_ListItemId');
    if (dataDef.matchDataType('SELECT_SINGLE')) { // 選択型データ項目の場合
        const select = engine.findData(dataDef);
        if (select === null || select.size() === 0) { // 未選択
            throw new Error('List Item ID is not selected.');
        }
        return select.get(0).getValue();
    }
    // 文字型データ項目の場合
    const value = engine.findData(dataDef);
    if (value === null) {
        throw new Error('List Item ID is blank.');
    }
    return value;
};

/**
 * 工程コンフィグから列の名前、保存先データ項目を取得する
 * 以下の場合はエラー
 * - 名前、保存先データ項目の片方だけが指定されている列がある
 * - 保存先データ項目がひとつも指定されていない
 * - 値を保存するデータ項目が重複して設定されている
 * @returns {Object} result
 * @returns {Array<String>} result.columnNames  列の名前
 * @returns {Array<ProcessDataDefinitionView>} result.columnDefs  列の値の保存先データ項目
 */
const retrieveColumnNamesAndDataDefs = () => {
    const columnNames = [];
    const columnDefs = [];
    const dataItemNumSet = new Set(); // データ項目の重複確認用
    for (let i = 0; i < COLUMN_NUM; i++) {
        const columnName = configs.get(`conf_ColumnName${i + 1}`);
        const columnDef = configs.getObject(`conf_ColumnValue${i + 1}`);
        if (columnName === '' && columnDef === null) {
            continue;
        } else if (columnName !== '' && columnDef !== null) {
            const dataItemNum = columnDef.getNumber();
            if (dataItemNumSet.has(dataItemNum)) { // データ項目番号が重複していればエラー
                throw new Error('The same data item is set multiple times.');
            }
            dataItemNumSet.add(dataItemNum); // データ項目の重複確認用
            columnNames.push(columnName);
            columnDefs.push(columnDef);
        } else {
            throw new Error(`Field name and data item for Column ${i + 1} must be specified at the same time.`);
        }
    }
    if (columnDefs.length === 0) {
        throw new Error('No data item to save the result.');
    }
    return {columnNames, columnDefs};
};

/**
 * サイトのメタデータを取得し、siteId を返す
 * APIの仕様: https://docs.microsoft.com/ja-jp/onedrive/developer/rest-api/api/shares_get?view=odsp-graph-online
 * @param {AuthSettingWrapper} oauth2  OAuth2 設定情報
 * @param {String} siteUrl  SharePoint サイトの URL
 * @returns {String} siteId
 */
const getSiteIdByUrl = (oauth2, siteUrl) => {
    // encoding sharing URL
    const encodedSharingUrl = encodeSharingUrl(siteUrl);

    // preparing for API Request
    const response = httpClient.begin()
        .authSetting(oauth2)
        .queryParam('select', 'id')
        .get(`${GRAPH_URI}shares/${encodedSharingUrl}/site`);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw new Error(`Failed to get site info. status: ${status}`);
    }
    return JSON.parse(responseStr).id;
};

/**
 * 共有URLを unpadded base64url 形式にエンコードする
 * @param {String} sharingUrl  共有URL
 * @returns {String} encodedSharingUrl  エンコードされた共有URL
 */
const encodeSharingUrl = (sharingUrl) => {
    let encodedSharingUrl = base64.encodeToUrlSafeString(sharingUrl);
    while (encodedSharingUrl.slice(-1) === '=') {
        encodedSharingUrl = encodedSharingUrl.slice(0, -1);
    }
    return `u!${encodedSharingUrl}`;
};

/**
 * リストの列のメタデータを取得し、指定した名前の列の存在を確認する
 * リストアイテム取得の API では値が空の列はプロパティ自体が返らないため、事前に列の存在を確認しておく
 * @param {AuthSettingWrapper} oauth2  OAuth2 設定情報
 * @param {String} siteId  SharePoint サイトの ID
 * @param {String} listTitle  リストの名前
 * @param {Array<String>} columnNames  列の名前
 * @param {Array<ProcessDataDefinitionView>} columnDefs  列の値の保存先データ項目
 */
const checkColumns = (oauth2, siteId, listTitle, columnNames, columnDefs) => {
    const url = `${GRAPH_URI}sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listTitle)}/columns`;
    const response = httpClient.begin()
        .authSetting(oauth2)
        .queryParam('$select', 'name')
        // $filter, $search, $top パラメータは効かない
        .get(url);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw new Error(`Failed to get columns. status: ${status}`);
    }
    const columns = JSON.parse(responseStr).value;
    columnNames.forEach(columnName => {
        const column = columns.find((column) => column.name === columnName);
        if (column === undefined) {
            throw new Error(`Column '${columnName}' not found.`);
        }
    });
};

/**
 * リストアイテムを取得し、JSONオブジェクトを返す
 * @param {AuthSettingWrapper} oauth2  OAuth2 設定情報
 * @param {String} siteId  SharePoint サイトの ID
 * @param {String} listTitle  リストの名前
 * @param {String} listItemId  リストアイテム ID
 * @param {Array<String>} columnNames  列の名前
 * @returns {Object} 取得したリストアイテム
 */
const getListItem = (oauth2, siteId, listTitle, listItemId, columnNames) => {
    const url = `${GRAPH_URI}sites/${encodeURIComponent(siteId)}/lists/${encodeURIComponent(listTitle)}/items/${encodeURIComponent(listItemId)}`;
    const response = httpClient.begin()
        .authSetting(oauth2)
        .queryParam('$select', 'id') // 不要なプロパティを除外するために指定
        .queryParam('$expand', `fields($select=${columnNames.join(',')})`)
        .get(url);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw new Error(`Failed to get list item. status: ${status}`);
    }
    const listItem = JSON.parse(responseStr);
    return listItem;
};

/**
 * データ項目への保存
 * @param {Object} listItem リストアイテム
 * @param {Array<String>} columnNames 列の名前
 * @param {Array<ProcessDataDefinitionView>} columnDefs 列の値の保存先データ項目
 */
const saveData = (listItem, columnNames, columnDefs) => {
    columnNames.forEach((columnName, i) => {
        convertAndSetData(columnDefs[i], listItem.fields[columnName], columnName);
    });
};

/**
  * データ項目の型にしたがってデータを変換し、データ項目に保存する
  * 変換できない値の場合はエラーにする
  * @param {ProcessDataDefinitionView} dataDef 保存先データ項目
  * @param {Object} columnValue 列の値
  * @param {String} columnName 列の名前(エラー出力用)
  */
function convertAndSetData(dataDef, columnValue, columnName) {
    if (columnValue === undefined || columnValue === null) {
        engine.setData(dataDef, null);
        return;
    }
    // データ項目の型ごとに、列の値を変換して保存する
    if (dataDef.matchDataType('STRING')) {
        try {
            // TEXTFIELD に改行を含む文字列を保存しようとした場合のエラーは、QBPMS のバリデーションに任せる
            engine.setData(dataDef, stringifyColumnValue(columnValue));
        } catch (e) { // 列の値が解釈できないオブジェクトの場合など
            throw new Error(`Column '${columnName}' cannot be saved to Text type data item. ${e.message}`);
        }
    } else if (dataDef.matchDataType('DECIMAL')) {
        const supportedValueTypes = ['string', 'number'];
        if (!supportedValueTypes.includes(typeof columnValue)) {
            throw new Error(`Column '${columnName}' cannot be saved to Numeric type data item. The returned value is neither a string nor a number.`);
        }
        try {
            engine.setData(dataDef, new java.math.BigDecimal(columnValue));
        } catch (e) {
            throw new Error(`Column '${columnName}' cannot be saved to Numeric type data item. Failed to convert to BigDecimal.`);
        }
    } else if (dataDef.matchDataType('SELECT')) {
        const items = new java.util.ArrayList();
        try {
            if (Array.isArray(columnValue)) { // 複数選択の場合
                convertMultipleValuesToStringArray(columnValue).forEach((value) => {
                    items.add(value);
                });
            } else { // 単一選択の場合
                items.add(convertSingleValueToString(columnValue));
            }
            // 一致する選択肢 ID がない場合、SELECT_SINGLE に複数選択を保存しようとした場合のエラーは、QBPMS のバリデーションに任せる
            engine.setData(dataDef, items);
        } catch (e) {
            throw new Error(`Column '${columnName}' cannot be saved to Select type data item. ${e.message}`);
        }
    } else if (dataDef.matchDataType('DATETIME')) {
        if (typeof columnValue !== 'string') {
            throw new Error(`Column '${columnName}' cannot be saved to Datetime type data item. The returned value is not a string.`);
        }
        try {
            engine.setData(dataDef, dateFormatter.parse("yyyy-MM-dd'T'HH:mm:ssX", columnValue));
        } catch (e) {
            throw new Error(`Column '${columnName}' cannot be saved to Datetime type data item. The returned value is not a datetime-format string.`);
        }
    } else if (dataDef.matchDataType('DATE')) {
        if (typeof columnValue !== 'string') {
            throw new Error(`Column '${columnName}' cannot be saved to Date type data item. The returned value is not a string.`);
        }
        try {
            const millisec = dateFormatter.parse("yyyy-MM-dd'T'HH:mm:ssX", columnValue).getFirstTimeInDate().getTime();
            engine.setData(dataDef, new com.questetra.bpms.util.AddableDate(millisec));
        } catch (e) {
            throw new Error(`Column '${columnName}' cannot be saved to Date type data item. The returned value is not a datetime-format string.`);
        }
    }
}

/**
 * 列の値を文字列に変換する
 * 列の値が配列の場合、改行区切りの文字列に変換する
 * 文字列化に失敗した場合はエラー
 * @param {Object} columnValue 列の値
 * @returns {String} 文字列化した列の値
 */
const stringifyColumnValue = (columnValue) => {
    if (Array.isArray(columnValue)) {
        return convertMultipleValuesToStringArray(columnValue).join('\n');
    }
    return convertSingleValueToString(columnValue);
};

/**
 * 列の値を、文字列の配列に変換する(値が配列の場合)
 * 文字列化に失敗した場合はエラー
 * @param {Array} array 列の値
 * @returns {Array<String>} 文字列化した列の値
 */
const convertMultipleValuesToStringArray = (array) => {
    return array.map(value => {
        return convertSingleValueToString(value);
    });
};

/**
 * 列の値を、文字列に変換する(値が配列でない場合)
 * 文字列化に失敗した場合はエラー
 * @param {Object} value 列の値
 * @returns {String} 文字列化した列の値
 */
const convertSingleValueToString = (value) => {
    const supportedPrimitiveTypes = ['string', 'number', 'boolean'];
    if (supportedPrimitiveTypes.includes(typeof value)) {
        return value.toString();
    }
    // オブジェクトの場合など、解釈できない場合はエラー
    throw new Error('Failed to convert an object to a string.');
};

    
上部へスクロール

Questetra Supportをもっと見る

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

続きを読む