
Box: Add Metadata to File
This item adds metadata to the specified file on Box, using a metadata template defined within your enterprise. An error occurs if the specified metadata template is already added to the file.
Configs: Common
- Step Name
- Note
Configs
- C1: OAuth2 Setting *
- C2: File ID to add metadata to *
- C3: Display Name of Metadata Template *
- C-K1: Display Name of Field 1
- C-V1: Value for Field 1#{EL}
- C-K2: Display Name of Field 2
- C-V2: Value for Field 2#{EL}
- C-K3: Display Name of Field 3
- C-V3: Value for Field 3#{EL}
- C-K4: Display Name of Field 4
- C-V4: Value for Field 4#{EL}
- C-K5: Display Name of Field 5
- C-V5: Value for Field 5#{EL}
- C-K6: Display Name of Field 6
- C-V6: Value for Field 6#{EL}
- C-K7: Display Name of Field 7
- C-V7: Value for Field 7#{EL}
- C-K8: Display Name of Field 8
- C-V8: Value for Field 8#{EL}
Notes
- The refresh token for Box has an expiration date. Use regularly to ensure that it does not exceed the expiration.
- To create a metadata template on Box, you have to be a Box administrator. For more details, see the Box support page.
- Please avoid duplication when naming metadata templates and fields as this item identifies them by their display names.
- Hidden templates and hidden fields are not supported.
- Values are to be set in string. The data format of the string is determined by the field type of the metadata.
- Text: Any string
- Number: Integer or decimal. Decimal point must be a period (.) and no other delimiters are allowed.
- Date: yyyy-MM-dd
- Dropdown – Single Select: An option value
- Dropdown- Multiple Select: An option value (Multiple select is not supported)
Capture

See also
Script (click to open)
- An XML file that contains the code below is available to download
- box-file-metadata-add.xml (C) Questetra, Inc. (MIT License)
- If you are using Professional, you can modify the contents of this file and use it as your own add-on
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}`;
}
}