Box: ファイルにメタデータ追加 (Box: Add Metadata to File)
この工程は、会社内で定義されたメタデータテンプレートを利用して、Box 上のファイルにメタデータを追加します。 指定したメタデータテンプレートがすでにファイルに追加済みの場合は、エラーになります。
Configs:共通設定
  • 工程名
  • メモ
Configs
  • C1: OAuth2 設定 *
  • C2: メタデータを追加するファイル ID *
  • C3: メタデータテンプレートの表示名 *
  • C-K1: フィールド 1 の表示名
  • C-V1: フィールド 1 の値#{EL}
  • C-K2: フィールド 2 の表示名
  • C-V2: フィールド 2 の値#{EL}
  • C-K3: フィールド 3 の表示名
  • C-V3: フィールド 3 の値#{EL}
  • C-K4: フィールド 4 の表示名
  • C-V4: フィールド 4 の値#{EL}
  • C-K5: フィールド 5 の表示名
  • C-V5: フィールド 5 の値#{EL}
  • C-K6: フィールド 6 の表示名
  • C-V6: フィールド 6 の値#{EL}
  • C-K7: フィールド 7 の表示名
  • C-V7: フィールド 7 の値#{EL}
  • C-K8: フィールド 8 の表示名
  • C-V8: フィールド 8 の値#{EL}

Notes

  • Box のリフレッシュトークンには、期限があります。期限を超えないよう、定期的に利用する必要があります。
  • Box にメタデータテンプレートを追加するには、Box の管理者である必要があります。詳細は Box サポートページを参照してください。
    • この工程は、メタデータテンプレートやフィールドを表示名で指定します。メタデータテンプレートやフィールドを追加するさい、表示名が重複しないようにしてください。
  • 非公開のテンプレート、非公開のフィールドには非対応です。
  • 値は文字列で指定します。文字列の書式は、メタデータのフィールド型ごとにきまっています。
    • 文字型: 任意の文字列
    • 数値型: 整数または小数。小数点はピリオド(.)のみ。その他の区切り文字は使用不可
    • 日付型: yyyy-MM-dd
    • 単一選択型: 選択肢のうちいずれかひとつの値
    • 複数選択型: 選択肢のうちいずれかひとつの値(複数選択には非対応です)

Capture

See also

Script (click to open)
  • 下記のスクリプトを記述した XML ファイルをダウンロードできます
    • box-file-metadata-add.xml (C) Questetra, Inc. (MIT License)
    • Professional をご利用であればファイルの内容を改変することでオリジナルのアドオンとして活用できます


const FIELD_NUM = 8; // 扱えるフィールドの数

main();
function main(){
    const oauth2 = configs.get('conf_OAuth2');
    const fileId = decideFileId();
    const templateName = configs.get('conf_TemplateName');
    const metadataMap = retrieveMetadataMap();

    const {templateKey, fields} = searchTemplate(oauth2, templateName);
    const metadataObj = buildMetadataObj(metadataMap, fields);
    addMetadata(oauth2, fileId, templateKey, metadataObj);
}

/**
  * ファイル ID を config から読み出す
  * @return {String} fileId ファイル ID
  */
function decideFileId() {
    const fileId = engine.findData(configs.getObject('conf_FileId'));
    if (fileId === '' || fileId === null) {
        throw 'File ID is blank.';
    }
    return fileId;
}

/**
  * メタデータの情報を config から読み出し、Map に格納する
  * @return {Map<String, String>} metadataMap フィールド名と値の Map
  */
function retrieveMetadataMap() {
    const metadataMap = new Map();
    for (let i = 0; i < FIELD_NUM; i++) {
        const fieldName = configs.get(`conf_FieldName${i+1}`);
        const fieldValue = configs.get(`conf_FieldValue${i+1}`);
        if (fieldName === '' || fieldName === null) { // フィールド名が空
            if (fieldValue === '' || fieldValue === null) { // 値も空
                continue;
            }
            throw `Value for Field ${i+1} is set but its display name is blank.`;
        }
        if (fieldValue === '' || fieldValue === null) { // 値が空
            continue;
        }
        if (metadataMap.has(fieldName)) { // フィールド名の指定が重複
            throw `The Field Name "${fieldName}" is set multiple times.`;
        }
        metadataMap.set(fieldName, fieldValue);
    }
    return metadataMap;
}

/**
  * テンプレートを表示名で検索し、一致した非表示でないテンプレートを返す
  * 同名のテンプレートが複数ある場合はエラー
  * @param {String} oauth OAuth2 設定
  * @param {String} templateName テンプレートの表示名
  * @return {Object} template テンプレートオブジェクト
  */
function searchTemplate(oauth2, templateName) {
    const url = 'https://api.box.com/2.0/metadata_templates/enterprise';
    const response = httpClient.begin()
        .authSetting(oauth2)
        .queryParam('limit', '500') // 現時点で企業内に登録できるテンプレート数は 500 まで
        .get(url);
    const status = response.getStatusCode();
    const responseStr = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseStr);
        throw `Failed to search template. status:${status}`;
    }
    const {entries} = JSON.parse(responseStr);
    // 名前が一致し、かつ hidden パラメータが false のものを検索
    const result = entries.filter(template => {
        return (template.displayName === templateName) && !template.hidden;
    });
    if (result.length === 0) {
        throw `Template with display name "${templateName}" not found.`;
    }
    if (result.length > 1) {
        throw `Multiple templates with display name "${templateName}" found.`;
    }
    return result[0];
}

/**
  * メタデータオブジェクトを生成する
  * フィールド一覧を表示名で検索し、一致した非表示でないフィールドのキーを使用する
  * 同名のフィールドが複数ある場合はエラー
  * フィールドの型と値の書式が一致しない場合はエラー
  * @param {Map<String, String>} metadataMap フィールド名と値の Map
  * @param {Array<Object>} fields フィールド一覧
  * @return {Object} metadataObj メタデータオブジェクト
  */
function buildMetadataObj(metadataMap, fields) {
    const metadataObj = {};
    metadataMap.forEach((fieldValue, fieldName) => {
        // 名前が一致し、かつ hidden パラメータが false のものを検索
        const result = fields.filter(field => {
            return (field.displayName === fieldName) && !field.hidden;
        });
        if (result.length === 0) {
            throw `Field with display name "${fieldName}" not found.`;
        }
        if (result.length > 1) {
            throw `Multiple fields with display name "${fieldName}" found.`;
        }
        const field = result[0];
        let value = fieldValue;
        // フィールドの型とデータ項目の型の一致を確認し、値を整形する
        switch (field.type) {
            case 'string':
                break;
            case 'float':
                value = checkAndParseFloat(fieldName, value);
                break;
            case 'date':
                value = checkAndParseDate(fieldName, value);
                break;
            case 'enum':
                checkOptions(fieldName, value, field.options);
                break;
            case 'multiSelect': // 1 つだけ選択する場合にのみ対応
                checkOptions(fieldName, value, field.options);
                value = Array.of(value);
                break;
             default: // 現状はありえないが、Box のメタデータのフィールド型が追加された場合に発生
                throw `The type of "${fieldName}" is not supported: ${field.type}`;
        }
        // オブジェクトに追加
        metadataObj[field.key] = value;
    });
    return metadataObj;
}

/**
  * 文字列を数値に変換
  * マイナス記号と小数点以外の文字が含まれる場合はエラー
  * @param {String} fieldName フィールド名(エラー出力用)
  * @param {String} value 入力文字列
  * @return {Number} parsedValue 数値
  */
function checkAndParseFloat(fieldName, value) {
    const regex = /^\-?(\d|[1-9]\d+)(\.\d+)?$/;
    if (!regex.test(value)) {
        throw `The type of "${fieldName}" is float, but the value "${value}" is invalid as float.`;
    }
    // 文字列を float にパース
    return parseFloat(value);
}

/**
  * 文字列を yyyy-MM-dd'T'HH:mm:ssZ 形式の文字列に変換
  * 入力が yyyy-MM-dd 形式の日付でない場合はエラー
  * @param {String} fieldName フィールド名(エラー出力用)
  * @param {String} value 入力文字列
  * @return {String} parsedValue 指定形式の文字列
  */
function checkAndParseDate(fieldName, value) {
    const regex = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
    const matched = value.match(regex);
    if (matched === null) { // yyyy-MM-dd 形式でない
        throw `The type of "${fieldName}" is date, but the value "${value}" is not in the format of "yyyy-MM-dd".`;
    }
    // 日付として不正でないかをチェック
    // Date にパースするだけでは6月31日なども許可されてしまうので、年月日それぞれをチェック
    const y = parseInt(matched[1]);
    const m = parseInt(matched[2]) -1;
    const d  = parseInt(matched[3]);
    const date = new Date(y, m, d);
    if (y !== date.getFullYear() || m !== date.getMonth() || d !== date.getDate()) {
        throw `The type of "${fieldName}" is date, but the value "${value}" is invalid as date.`;
    }
    return `${value}T00:00:00Z`;
}

/**
  * 入力文字列が選択肢として存在するかチェックし、存在しない場合はエラー
  * 選択肢の表示名(キー)が重複することは、Box の仕様としてありえない
  * @param {String} fieldName フィールド名(エラー出力用)
  * @param {String} value 入力文字列
  * @param {Array<Object>} options 選択肢一覧
  */
function checkOptions(fieldName, value, options) {
    if (!options.some(option => option.key === value)) {
        throw `The value "${value}" is not in the options of the field "${fieldName}".`;
    }
}

/**
  * メタデータを追加
  * @param {String} oauth OAuth2 設定
  * @param {String} fileId ファイル ID
  * @param {String} templateKey テンプレートキー
  * @param {Object} metadataObj 追加するメタデータ
  */
function addMetadata(oauth2, fileId, templateKey, metadataObj) {
    const url = `https://api.box.com/2.0/files/${encodeURIComponent(fileId)}/metadata/enterprise/${encodeURIComponent(templateKey)}`;
    const response = httpClient.begin()
        .authSetting(oauth2)
        .body(JSON.stringify(metadataObj), 'application/json; charset=UTF-8')
        .post(url);
    const status = response.getStatusCode();
    if (status !== 201) {
        engine.log(response.getResponseAsString());
        throw `Failed to add metadata. status:${status}`;
    }
}

    
%d人のブロガーが「いいね」をつけました。