diff --git a/doc/files.md b/doc/files.md index e6759faac..e76bed453 100644 --- a/doc/files.md +++ b/doc/files.md @@ -656,6 +656,9 @@ float floatValue = metadata.getFloat("/price"); // Date metadata fields Date dateValue = metadata.getDate("/deadline"); + +// Multiselect metadata fields +List multiSelectValues = metadata.getMultiSelect("/categories"); ``` [metadata]: http://opensource.box.com/box-java-sdk/javadoc/com/box/sdk/Metadata.html diff --git a/src/main/java/com/box/sdk/Metadata.java b/src/main/java/com/box/sdk/Metadata.java index 22b1c4f90..840e58164 100644 --- a/src/main/java/com/box/sdk/Metadata.java +++ b/src/main/java/com/box/sdk/Metadata.java @@ -163,6 +163,22 @@ public Metadata add(String path, float value) { return this; } + /** + * Adds a new metadata value of array type. + * @param path the path to the field. + * @param values the collection of values. + * @return the metadata object for chaining. + */ + public Metadata add(String path, List values) { + JsonArray arr = new JsonArray(); + for (String value : values) { + arr.add(value); + } + this.values.add(this.pathToProperty(path), arr); + this.addOp("add", path, arr); + return this; + } + /** * Replaces an existing metadata value. * @param path the path that designates the key. Must be prefixed with a "/". @@ -194,7 +210,7 @@ public Metadata replace(String path, float value) { */ public Metadata remove(String path) { this.values.remove(this.pathToProperty(path)); - this.addOp("remove", path, null); + this.addOp("remove", path, (String) null); return this; } @@ -265,6 +281,20 @@ public Date getDate(String path) throws ParseException { return BoxDateFormat.parse(this.getValue(path).asString()); } + /** + * Get a value from a multiselect metadata field. + * @param path the key path in the metadata object. Must be prefixed with a "/". + * @return the list of values set in the field. + */ + public List getMultiSelect(String path) { + List values = new ArrayList(); + for (JsonValue val : this.getValue(path).asArray()) { + values.add(val.asString()); + } + + return values; + } + /** * Returns a list of metadata property paths. * @return the list of metdata property paths. @@ -360,6 +390,24 @@ private void addOp(String op, String path, float value) { .add("value", value)); } + /** + * Adds a new patch operation for array values. + * @param op the operation type. Must be add, replace, remove, or test. + * @param path the path that designates the key. Must be prefixed with a "/". + * @param values the array of values to be set. + */ + private void addOp(String op, String path, JsonArray values) { + + if (this.operations == null) { + this.operations = new JsonArray(); + } + + this.operations.add(new JsonObject() + .add("op", op) + .add("path", path) + .add("value", values)); + } + static String scopeBasedOnType(String typeName) { String scope; if (typeName.equals(DEFAULT_METADATA_TYPE)) { diff --git a/src/main/java/com/box/sdk/MetadataTemplate.java b/src/main/java/com/box/sdk/MetadataTemplate.java index 7161b2882..08fe2dbda 100644 --- a/src/main/java/com/box/sdk/MetadataTemplate.java +++ b/src/main/java/com/box/sdk/MetadataTemplate.java @@ -382,6 +382,17 @@ private static JsonObject getFieldOperationJsonObject(FieldOperation fieldOperat if (enumOptionKey != null) { jsonObject.add("enumOptionKey", enumOptionKey); } + + String multiSelectOptionKey = fieldOperation.getMultiSelectOptionKey(); + if (multiSelectOptionKey != null) { + jsonObject.add("multiSelectOptionKey", multiSelectOptionKey); + } + + List multiSelectOptionKeys = fieldOperation.getMultiSelectOptionKeys(); + if (multiSelectOptionKeys != null) { + jsonObject.add("multiSelectOptionKeys", getJsonArray(multiSelectOptionKeys)); + } + return jsonObject; } @@ -727,6 +738,8 @@ public static class FieldOperation extends BoxJSONObject { private List fieldKeys; private List enumOptionKeys; private String enumOptionKey; + private String multiSelectOptionKey; + private List multiSelectOptionKeys; /** * Constructs an empty FieldOperation. @@ -847,6 +860,38 @@ public void setEnumOptionKey(String enumOptionKey) { this.enumOptionKey = enumOptionKey; } + /** + * Gets the multi-select option key. + * @return the key. + */ + public String getMultiSelectOptionKey() { + return this.multiSelectOptionKey; + } + + /** + * Sets the multi-select option key. + * @param key the key. + */ + public void setMultiSelectOptionKey(String key) { + this.multiSelectOptionKey = key; + } + + /** + * Gets the list of multiselect option keys. + * @return the list of keys. + */ + public List getMultiSelectOptionKeys() { + return this.multiSelectOptionKeys; + } + + /** + * Sets the multi-select option keys. + * @param keys the list of keys. + */ + public void setMultiSelectOptionKeys(List keys) { + this.multiSelectOptionKeys = keys; + } + /** * {@inheritDoc} */ @@ -884,6 +929,13 @@ void parseJSONMember(JsonObject.Member member) { } } else if (memberName.equals("enumOptionKey")) { this.enumOptionKey = value.asString(); + } else if (memberName.equals("multiSelectOptionKey")) { + this.multiSelectOptionKey = value.asString(); + } else if (memberName.equals("multiSelectOptionKeys")) { + this.multiSelectOptionKeys = new ArrayList(); + for (JsonValue key : value.asArray()) { + this.multiSelectOptionKeys.add(key.asString()); + } } } } @@ -936,6 +988,26 @@ public enum Operation { /** * Reorders the field list to match the requested field list. */ - reorderFields + reorderFields, + + /** + * Adds a new option to a multiselect field. + */ + addMultiSelectOption, + + /** + * Edits an existing option in a multiselect field. + */ + editMultiSelectOption, + + /** + * Removes an option from a multiselect field. + */ + removeMultiSelectOption, + + /** + * Changes the display order of options in a multiselect field. + */ + reorderMultiSelectOptions } } diff --git a/src/test/java/com/box/sdk/MetadataTest.java b/src/test/java/com/box/sdk/MetadataTest.java index 8214120a9..b8b42b73e 100644 --- a/src/test/java/com/box/sdk/MetadataTest.java +++ b/src/test/java/com/box/sdk/MetadataTest.java @@ -8,7 +8,10 @@ import com.eclipsesource.json.JsonObject; import java.text.ParseException; +import java.util.ArrayList; +import java.util.Calendar; import java.util.Date; +import java.util.List; public class MetadataTest { @@ -112,6 +115,154 @@ public void testMissingMetaProperties() { Assert.assertEquals(null, m.getParentID()); } + @Test + @Category(IntegrationTest.class) + public void testMultiSelectMetadataCRUD() { + + BoxAPIConnection api = new BoxAPIConnection(TestConfig.getAccessToken()); + + long timestamp = Calendar.getInstance().getTimeInMillis(); + String templateKey = "multiselect" + timestamp; + String fieldKey = "testMultiSelect"; + + // Create new template with multiselect field + List fieldOptions = new ArrayList(); + fieldOptions.add("foo"); + fieldOptions.add("bar"); + fieldOptions.add("baz"); + fieldOptions.add("quux"); + + List fields = new ArrayList(); + MetadataTemplate.Field multiSelectField = new MetadataTemplate.Field(); + multiSelectField.setKey(fieldKey); + multiSelectField.setType("multiSelect"); + multiSelectField.setDisplayName("MultiSelect Field"); + multiSelectField.setOptions(fieldOptions); + fields.add(multiSelectField); + + MetadataTemplate template = MetadataTemplate.createMetadataTemplate(api, "enterprise", + templateKey, "MultiSelect " + timestamp, false, fields); + + Assert.assertEquals("multiSelect", template.getFields().get(0).getType()); + List actualOptions = template.getFields().get(0).getOptions(); + Assert.assertEquals("foo", actualOptions.get(0)); + Assert.assertEquals("bar", actualOptions.get(1)); + Assert.assertEquals("baz", actualOptions.get(2)); + Assert.assertEquals("quux", actualOptions.get(3)); + + // Add template to item + Metadata mdValues = new Metadata(); + List values = new ArrayList(); + values.add("foo"); + values.add("bar"); + mdValues.add("/" + fieldKey, values); + BoxFolder.Info folder = BoxFolder.getRootFolder(api).createFolder("Metadata Test " + timestamp); + Metadata actualMD = folder.getResource().createMetadata(templateKey, mdValues); + + Assert.assertEquals(templateKey, actualMD.getTemplateName()); + List multiSelectValues = actualMD.getMultiSelect("/" + fieldKey); + Assert.assertEquals(2, multiSelectValues.size()); + Assert.assertEquals("foo", multiSelectValues.get(0)); + Assert.assertEquals("bar", multiSelectValues.get(1)); + + // Update template with multiselect operations - change existing field and add another multiselect field + List updates = new ArrayList(); + + MetadataTemplate.Field newOption = new MetadataTemplate.Field(); + newOption.setKey("blargh"); + MetadataTemplate.FieldOperation add = new MetadataTemplate.FieldOperation(); + add.setOp(MetadataTemplate.Operation.addMultiSelectOption); + add.setFieldKey(fieldKey); + add.setData(newOption); + updates.add(add); + + MetadataTemplate.Field updatedField = new MetadataTemplate.Field(); + updatedField.setKey("foooooo"); + MetadataTemplate.FieldOperation edit = new MetadataTemplate.FieldOperation(); + edit.setOp(MetadataTemplate.Operation.editMultiSelectOption); + edit.setFieldKey(fieldKey); + edit.setMultiSelectOptionKey("foo"); + edit.setData(updatedField); + updates.add(edit); + + MetadataTemplate.FieldOperation remove = new MetadataTemplate.FieldOperation(); + remove.setOp(MetadataTemplate.Operation.removeMultiSelectOption); + remove.setFieldKey(fieldKey); + remove.setMultiSelectOptionKey("baz"); + updates.add(remove); + + MetadataTemplate.FieldOperation reorder = new MetadataTemplate.FieldOperation(); + reorder.setOp(MetadataTemplate.Operation.reorderMultiSelectOptions); + reorder.setFieldKey(fieldKey); + List reorderedFields = new ArrayList(); + reorderedFields.add("quux"); + reorderedFields.add("blargh"); + reorderedFields.add("bar"); + reorderedFields.add("foooooo"); + reorder.setMultiSelectOptionKeys(reorderedFields); + updates.add(reorder); + + MetadataTemplate.FieldOperation addField = new MetadataTemplate.FieldOperation(); + MetadataTemplate.Field newField = new MetadataTemplate.Field(); + List opts = new ArrayList(); + opts.add("one"); + opts.add("two"); + newField.setKey("otherMultiSelect"); + newField.setDisplayName("Another MultiSelect"); + newField.setType("multiSelect"); + newField.setOptions(opts); + addField.setOp(MetadataTemplate.Operation.addField); + addField.setData(newField); + updates.add(addField); + + MetadataTemplate updatedTemplate = MetadataTemplate.updateMetadataTemplate(api, "enterprise", + templateKey, updates); + + Assert.assertEquals(2, updatedTemplate.getFields().size()); + for (MetadataTemplate.Field field : updatedTemplate.getFields()) { + + if (field.getKey().equals(fieldKey)) { + Assert.assertEquals("multiSelect", field.getType()); + actualOptions = field.getOptions(); + Assert.assertEquals("quux", actualOptions.get(0)); + Assert.assertEquals("blargh", actualOptions.get(1)); + Assert.assertEquals("bar", actualOptions.get(2)); + Assert.assertEquals("foooooo", actualOptions.get(3)); + } else if (field.getKey().equals("otherMultiSelect")) { + Assert.assertEquals("multiSelect", field.getType()); + actualOptions = field.getOptions(); + Assert.assertEquals("one", actualOptions.get(0)); + Assert.assertEquals("two", actualOptions.get(1)); + } else { + Assert.fail("Incorrect field found on metadata template: " + field.getKey()); + } + } + + // Update instance multiselect field + values = new ArrayList(); + values.add("two"); + values.add("one"); + actualMD.add("/otherMultiSelect", values); + actualMD.test("/" + fieldKey + "/0", "foooooo"); + actualMD.test("/" + fieldKey + "/1", "bar"); + actualMD.remove("/" + fieldKey + "/0"); + actualMD.add("/" + fieldKey + "/-", "blargh"); + Metadata updatedMD = folder.getResource().updateMetadata(actualMD); + + multiSelectValues = updatedMD.getMultiSelect("/" + fieldKey); + Assert.assertEquals(2, multiSelectValues.size()); + Assert.assertEquals("bar", multiSelectValues.get(0)); + Assert.assertEquals("blargh", multiSelectValues.get(1)); + multiSelectValues = updatedMD.getMultiSelect("/otherMultiSelect"); + Assert.assertEquals(2, multiSelectValues.size()); + Assert.assertEquals("two", multiSelectValues.get(0)); + Assert.assertEquals("one", multiSelectValues.get(1)); + + // Delete metadata template and folder + MetadataTemplate.deleteMetadataTemplate(api, "enterprise", template.getTemplateKey()); + folder.getResource().delete(true); + } + @Test @Category(UnitTest.class) public void getValues() {