001package com.box.sdk;
002
003import java.net.URL;
004import java.util.ArrayList;
005import java.util.List;
006
007import com.eclipsesource.json.JsonArray;
008import com.eclipsesource.json.JsonObject;
009import com.eclipsesource.json.JsonValue;
010
011
012/**
013 * The MetadataTemplate class represents the Box metadata template object.
014 * Templates allow the metadata service to provide a multitude of services,
015 * such as pre-defining sets of key:value pairs or schema enforcement on specific fields.
016 *
017 * @see <a href="https://docs.box.com/reference#metadata-templates">Box metadata templates</a>
018 */
019public class MetadataTemplate extends BoxJSONObject {
020
021    /**
022     * @see #getMetadataTemplate(BoxAPIConnection)
023     */
024    public static final URLTemplate METADATA_TEMPLATE_URL_TEMPLATE
025        = new URLTemplate("metadata_templates/%s/%s/schema");
026
027    /**
028     * @see #createMetadataTemplate(BoxAPIConnection, String, String, String, boolean, List)
029     */
030    public static final URLTemplate METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE
031        = new URLTemplate("metadata_templates/schema");
032
033    /**
034     * @see #getEnterpriseMetadataTemplates(String, int, BoxAPIConnection, String...)
035     */
036    public static final URLTemplate ENTERPRISE_METADATA_URL_TEMPLATE = new URLTemplate("metadata_templates/%s");
037
038    /**
039     * Default metadata type to be used in query.
040     */
041    private static final String DEFAULT_METADATA_TYPE = "properties";
042
043    /**
044     * Global metadata scope. Used by default if the metadata type is "properties".
045     */
046    private static final String GLOBAL_METADATA_SCOPE = "global";
047
048    /**
049     * Enterprise metadata scope. Used by default if the metadata type is not "properties".
050     */
051    private static final String ENTERPRISE_METADATA_SCOPE = "enterprise";
052
053    /**
054     * Default number of entries per page.
055     */
056    private static final int DEFAULT_ENTRIES_LIMIT = 100;
057
058    /**
059     * @see #getTemplateKey()
060     */
061    private String templateKey;
062
063    /**
064     * @see #getScope()
065     */
066    private String scope;
067
068    /**
069     * @see #getDisplayName()
070     */
071    private String displayName;
072
073    /**
074     * @see #getIsHidden()
075     */
076    private Boolean isHidden;
077
078    /**
079     * @see #getFields()
080     */
081    private List<Field> fields;
082
083    /**
084     * Constructs an empty metadata template.
085     */
086    public MetadataTemplate() {
087        super();
088    }
089
090    /**
091     * Constructs a metadata template from a JSON string.
092     * @param json the json encoded metadate template.
093     */
094    public MetadataTemplate(String json) {
095        super(json);
096    }
097
098    /**
099     * Constructs a metadate template from a JSON object.
100     * @param jsonObject the json encoded metadate template.
101     */
102    MetadataTemplate(JsonObject jsonObject) {
103        super(jsonObject);
104    }
105
106    /**
107     * Gets the unique template key to identify the metadata template.
108     * @return the unique template key to identify the metadata template.
109     */
110    public String getTemplateKey() {
111        return this.templateKey;
112    }
113
114    /**
115     * Gets the metadata template scope.
116     * @return the metadata template scope.
117     */
118    public String getScope() {
119        return this.scope;
120    }
121
122    /**
123     * Gets the displayed metadata template name.
124     * @return the displayed metadata template name.
125     */
126    public String getDisplayName() {
127        return this.displayName;
128    }
129
130    /**
131     * Gets is the metadata template hidden.
132     * @return is the metadata template hidden.
133     */
134    public Boolean getIsHidden() {
135        return this.isHidden;
136    }
137
138    /**
139     * Gets the iterable with all fields the metadata template contains.
140     * @return the iterable with all fields the metadata template contains.
141     */
142    public List<Field> getFields() {
143        return this.fields;
144    }
145
146    /**
147     * {@inheritDoc}
148     */
149    @Override
150    void parseJSONMember(JsonObject.Member member) {
151        JsonValue value = member.getValue();
152        String memberName = member.getName();
153        if (memberName.equals("templateKey")) {
154            this.templateKey = value.asString();
155        } else if (memberName.equals("scope")) {
156            this.scope = value.asString();
157        } else if (memberName.equals("displayName")) {
158            this.displayName = value.asString();
159        } else if (memberName.equals("hidden")) {
160            this.isHidden = value.asBoolean();
161        } else if (memberName.equals("fields")) {
162            this.fields = new ArrayList<Field>();
163            for (JsonValue field: value.asArray()) {
164                this.fields.add(new Field(field.asObject()));
165            }
166        }
167    }
168
169    /**
170     * Creates new metadata template.
171     * @param api the API connection to be used.
172     * @param scope the scope of the object.
173     * @param templateKey a unique identifier for the template.
174     * @param displayName the display name of the field.
175     * @param hidden whether this template is hidden in the UI.
176     * @param fields the ordered set of fields for the template
177     * @return the metadata template returned from the server.
178     */
179    public static MetadataTemplate createMetadataTemplate(BoxAPIConnection api, String scope, String templateKey,
180            String displayName, boolean hidden, List<Field> fields) {
181
182        JsonObject jsonObject = new JsonObject();
183        jsonObject.add("scope", scope);
184        jsonObject.add("displayName", displayName);
185        jsonObject.add("hidden", hidden);
186
187        if (templateKey != null) {
188            jsonObject.add("templateKey", templateKey);
189        }
190
191        JsonArray fieldsArray = new JsonArray();
192        if (fields != null && !fields.isEmpty()) {
193            for (Field field : fields) {
194                JsonObject fieldObj = getFieldJsonObject(field);
195
196                fieldsArray.add(fieldObj);
197            }
198
199            jsonObject.add("fields", fieldsArray);
200        }
201
202        URL url = METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE.build(api.getBaseURL());
203        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
204        request.setBody(jsonObject.toString());
205
206        BoxJSONResponse response = (BoxJSONResponse) request.send();
207        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
208
209        return new MetadataTemplate(responseJSON);
210    }
211
212    /**
213     * Gets the JsonObject representation of the given field object.
214     * @param field represents a template field
215     * @return the json object
216     */
217    private static JsonObject getFieldJsonObject(Field field) {
218        JsonObject fieldObj = new JsonObject();
219        fieldObj.add("type", field.getType());
220        fieldObj.add("key", field.getKey());
221        fieldObj.add("displayName", field.getDisplayName());
222
223        String fieldDesc = field.getDescription();
224        if (fieldDesc != null) {
225            fieldObj.add("description", field.getDescription());
226        }
227
228        Boolean fieldIsHidden = field.getIsHidden();
229        if (fieldIsHidden != null) {
230            fieldObj.add("hidden", field.getIsHidden());
231        }
232
233        JsonArray array = new JsonArray();
234        List<String> options = field.getOptions();
235        if (options != null && !options.isEmpty()) {
236            for (String option : options) {
237                JsonObject optionObj = new JsonObject();
238                optionObj.add("key", option);
239
240                array.add(optionObj);
241            }
242            fieldObj.add("options", array);
243        }
244
245        return fieldObj;
246    }
247
248    /**
249     * Updates the schema of an existing metadata template.
250     *
251     * @param api the API connection to be used
252     * @param scope the scope of the object
253     * @param template Unique identifier of the template
254     * @param fieldOperations the fields that needs to be updated / added in the template
255     * @return the updated metadata template
256     */
257    public static MetadataTemplate updateMetadataTemplate(BoxAPIConnection api, String scope, String template,
258            List<FieldOperation> fieldOperations) {
259
260        JsonArray array = new JsonArray();
261
262        for (FieldOperation fieldOperation : fieldOperations) {
263            JsonObject jsonObject = getFieldOperationJsonObject(fieldOperation);
264            array.add(jsonObject);
265        }
266
267        QueryStringBuilder builder = new QueryStringBuilder();
268        URL url = METADATA_TEMPLATE_URL_TEMPLATE.build(api.getBaseURL(), scope, template);
269        BoxJSONRequest request = new BoxJSONRequest(api, url, "PUT");
270        request.setBody(array.toString());
271
272        BoxJSONResponse response = (BoxJSONResponse) request.send();
273        JsonObject responseJson = JsonObject.readFrom(response.getJSON());
274
275        return new MetadataTemplate(responseJson);
276    }
277
278    /**
279     * Deletes the schema of an existing metadata template.
280     *
281     * @param api the API connection to be used
282     * @param scope the scope of the object
283     * @param template Unique identifier of the template
284     */
285    public static void deleteMetadataTemplate(BoxAPIConnection api, String scope, String template) {
286
287        URL url = METADATA_TEMPLATE_URL_TEMPLATE.build(api.getBaseURL(), scope, template);
288        BoxJSONRequest request = new BoxJSONRequest(api, url, "DELETE");
289
290        request.send();
291    }
292
293    /**
294     * Gets the JsonObject representation of the Field Operation.
295     * @param fieldOperation represents the template update operation
296     * @return the json object
297     */
298    private static JsonObject getFieldOperationJsonObject(FieldOperation fieldOperation) {
299        JsonObject jsonObject = new JsonObject();
300        jsonObject.add("op", fieldOperation.getOp().toString());
301
302        String fieldKey = fieldOperation.getFieldKey();
303        if (fieldKey != null) {
304            jsonObject.add("fieldKey", fieldKey);
305        }
306
307        Field field = fieldOperation.getData();
308        if (field != null) {
309            JsonObject fieldObj = new JsonObject();
310
311            String type = field.getType();
312            if (type != null) {
313                fieldObj.add("type", type);
314            }
315
316            String key = field.getKey();
317            if (key != null) {
318                fieldObj.add("key", key);
319            }
320
321            String displayName = field.getDisplayName();
322            if (displayName != null) {
323                fieldObj.add("displayName", displayName);
324            }
325
326            String description = field.getDescription();
327            if (description != null) {
328                fieldObj.add("description", description);
329            }
330
331            Boolean hidden = field.getIsHidden();
332            if (hidden != null) {
333                fieldObj.add("hidden", hidden);
334            }
335
336            List<String> options = field.getOptions();
337            if (options != null) {
338                JsonArray array = new JsonArray();
339                for (String option: options) {
340                    JsonObject optionObj = new JsonObject();
341                    optionObj.add("key", option);
342
343                    array.add(optionObj);
344                }
345
346                fieldObj.add("options", array);
347            }
348
349            jsonObject.add("data", fieldObj);
350        }
351
352        List<String> fieldKeys = fieldOperation.getFieldKeys();
353        if (fieldKeys != null) {
354            jsonObject.add("fieldKeys", getJsonArray(fieldKeys));
355        }
356
357        List<String> enumOptionKeys = fieldOperation.getEnumOptionKeys();
358        if (enumOptionKeys != null) {
359            jsonObject.add("enumOptionKeys", getJsonArray(enumOptionKeys));
360        }
361
362        String enumOptionKey = fieldOperation.getEnumOptionKey();
363        if (enumOptionKey != null) {
364            jsonObject.add("enumOptionKey", enumOptionKey);
365        }
366        return jsonObject;
367    }
368
369    /**
370     * Gets the Json Array representation of the given list of strings.
371     * @param keys List of strings
372     * @return the JsonArray represents the list of keys
373     */
374    private static JsonArray getJsonArray(List<String> keys) {
375        JsonArray array = new JsonArray();
376        for (String key : keys) {
377            array.add(key);
378        }
379
380        return array;
381    }
382
383    /**
384     * Gets the metadata template of properties.
385     * @param api the API connection to be used.
386     * @return the metadata template returned from the server.
387     */
388    public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api) {
389        return getMetadataTemplate(api, DEFAULT_METADATA_TYPE);
390    }
391
392    /**
393     * Gets the metadata template of specified template type.
394     * @param api the API connection to be used.
395     * @param templateName the metadata template type name.
396     * @return the metadata template returned from the server.
397     */
398    public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api, String templateName) {
399        String scope = scopeBasedOnType(templateName);
400        return getMetadataTemplate(api, templateName, scope);
401    }
402
403    /**
404     * Gets the metadata template of specified template type.
405     * @param api the API connection to be used.
406     * @param templateName the metadata template type name.
407     * @param scope the metadata template scope (global or enterprise).
408     * @param fields the fields to retrieve.
409     * @return the metadata template returned from the server.
410     */
411    public static MetadataTemplate getMetadataTemplate(
412            BoxAPIConnection api, String templateName, String scope, String ... fields) {
413        QueryStringBuilder builder = new QueryStringBuilder();
414        if (fields.length > 0) {
415            builder.appendParam("fields", fields);
416        }
417        URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildWithQuery(
418                api.getBaseURL(), builder.toString(), scope, templateName);
419        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
420        BoxJSONResponse response = (BoxJSONResponse) request.send();
421        return new MetadataTemplate(response.getJSON());
422    }
423
424    /**
425     * Returns all metadata templates within a user's enterprise.
426     * @param api the API connection to be used.
427     * @param fields the fields to retrieve.
428     * @return the metadata template returned from the server.
429     */
430    public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(BoxAPIConnection api, String ... fields) {
431        return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, api, fields);
432    }
433
434    /**
435     * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported.
436     * @param scope the scope of the metadata templates.
437     * @param api the API connection to be used.
438     * @param fields the fields to retrieve.
439     * @return the metadata template returned from the server.
440     */
441    public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(
442            String scope, BoxAPIConnection api, String ... fields) {
443        return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, DEFAULT_ENTRIES_LIMIT, api, fields);
444    }
445
446    /**
447     * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported.
448     * @param scope the scope of the metadata templates.
449     * @param limit maximum number of entries per response.
450     * @param api the API connection to be used.
451     * @param fields the fields to retrieve.
452     * @return the metadata template returned from the server.
453     */
454    public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(
455            String scope, int limit, BoxAPIConnection api, String ... fields) {
456        QueryStringBuilder builder = new QueryStringBuilder();
457        if (fields.length > 0) {
458            builder.appendParam("fields", fields);
459        }
460        return new BoxResourceIterable<MetadataTemplate>(
461                api, ENTERPRISE_METADATA_URL_TEMPLATE.buildWithQuery(
462                        api.getBaseURL(), builder.toString(), scope), limit) {
463
464            @Override
465            protected MetadataTemplate factory(JsonObject jsonObject) {
466                return new MetadataTemplate(jsonObject);
467            }
468        };
469    }
470
471    /**
472     * Determines the metadata scope based on type.
473     * @param typeName type of the metadata.
474     * @return scope of the metadata.
475     */
476    private static String scopeBasedOnType(String typeName) {
477        return typeName.equals(DEFAULT_METADATA_TYPE) ? GLOBAL_METADATA_SCOPE : ENTERPRISE_METADATA_SCOPE;
478    }
479
480    /**
481     * Class contains information about the metadata template field.
482     */
483    public static class Field extends BoxJSONObject {
484
485        /**
486         * @see #getType()
487         */
488        private String type;
489
490        /**
491         * @see #getKey()
492         */
493        private String key;
494
495        /**
496         * @see #getDisplayName()
497         */
498        private String displayName;
499
500        /**
501         * @see #getIsHidden()
502         */
503        private Boolean isHidden;
504
505        /**
506         * @see #getDescription()
507         */
508        private String description;
509
510        /**
511         * @see #getOptions()
512         */
513        private List<String> options;
514
515        /**
516         * Constructs an empty metadata template.
517         */
518        public Field() {
519            super();
520        }
521
522        /**
523         * Constructs a metadate template field from a JSON string.
524         * @param json the json encoded metadate template field.
525         */
526        public Field(String json) {
527            super(json);
528        }
529
530        /**
531         * Constructs a metadate template field from a JSON object.
532         * @param jsonObject the json encoded metadate template field.
533         */
534        Field(JsonObject jsonObject) {
535            super(jsonObject);
536        }
537
538        /**
539         * Gets the data type of the field's value.
540         * @return the data type of the field's value.
541         */
542        public String getType() {
543            return this.type;
544        }
545
546        /**
547         * Sets the data type of the field's value.
548         * @param type the data type of the field's value.
549         */
550        public void setType(String type) {
551            this.type = type;
552        }
553
554        /**
555         * Gets the key of the field.
556         * @return the key of the field.
557         */
558        public String getKey() {
559            return this.key;
560        }
561
562        /**
563         * Sets the key of the field.
564         * @param key the key of the field.
565         */
566        public void setKey(String key) {
567            this.key = key;
568        }
569
570        /**
571         * Gets the display name of the field.
572         * @return the display name of the field.
573         */
574        public String getDisplayName() {
575            return this.displayName;
576        }
577
578        /**
579         * Sets the display name of the field.
580         * @param displayName the display name of the field.
581         */
582        public void setDisplayName(String displayName) {
583            this.displayName = displayName;
584        }
585
586        /**
587         * Gets is metadata template field hidden.
588         * @return is metadata template field hidden.
589         */
590        public Boolean getIsHidden() {
591            return this.isHidden;
592        }
593
594        /**
595         * Sets is metadata template field hidden.
596         * @param isHidden is metadata template field hidden?
597         */
598        public void setIsHidden(boolean isHidden) {
599            this.isHidden = isHidden;
600        }
601
602        /**
603         * Gets the description of the field.
604         * @return the description of the field.
605         */
606        public String getDescription() {
607            return this.description;
608        }
609
610        /**
611         * Sets the description of the field.
612         * @param description the description of the field.
613         */
614        public void setDescription(String description) {
615            this.description = description;
616        }
617
618        /**
619         * Gets list of possible options for enum type of the field.
620         * @return list of possible options for enum type of the field.
621         */
622        public List<String> getOptions() {
623            return this.options;
624        }
625
626        /**
627         * Sets list of possible options for enum type of the field.
628         * @param options list of possible options for enum type of the field.
629         */
630        public void setOptions(List<String> options) {
631            this.options = options;
632        }
633
634        /**
635         * {@inheritDoc}
636         */
637        @Override
638        void parseJSONMember(JsonObject.Member member) {
639            JsonValue value = member.getValue();
640            String memberName = member.getName();
641            if (memberName.equals("type")) {
642                this.type = value.asString();
643            } else if (memberName.equals("key")) {
644                this.key = value.asString();
645            } else if (memberName.equals("displayName")) {
646                this.displayName = value.asString();
647            } else if (memberName.equals("hidden")) {
648                this.isHidden = value.asBoolean();
649            } else if (memberName.equals("description")) {
650                this.description = value.asString();
651            } else if (memberName.equals("options")) {
652                this.options = new ArrayList<String>();
653                for (JsonValue key: value.asArray()) {
654                    this.options.add(key.asObject().get("key").asString());
655                }
656            }
657        }
658    }
659
660    /**
661     * Posssible operations that can be performed in a Metadata template.
662     *  <ul>
663     *      <li>Add an enum option</li>
664     *      <li>Edit an enum option</li>
665     *      <li>Remove an enum option</li>
666     *      <li>Add a field</li>
667     *      <li>Edit a field</li>
668     *      <li>Remove a field</li>
669     *      <li>Edit template</li>
670     *      <li>Reorder the enum option</li>
671     *      <li>Reorder the field list</li>
672     *  </ul>
673     */
674    public static class FieldOperation extends BoxJSONObject {
675
676        private Operation op;
677        private Field data;
678        private String fieldKey;
679        private List<String> fieldKeys;
680        private List<String> enumOptionKeys;
681        private String enumOptionKey;
682
683        /**
684         * Constructs an empty FieldOperation.
685         */
686        public FieldOperation() {
687            super();
688        }
689
690        /**
691         * Constructs a Field operation from a JSON string.
692         * @param json the json encoded metadate template field.
693         */
694        public FieldOperation(String json) {
695            super(json);
696        }
697
698        /**
699         * Constructs a Field operation from a JSON object.
700         * @param jsonObject the json encoded metadate template field.
701         */
702        FieldOperation(JsonObject jsonObject) {
703            super(jsonObject);
704        }
705
706        /**
707         * Gets the operation.
708         * @return the operation
709         */
710        public Operation getOp() {
711            return this.op;
712        }
713
714        /**
715         * Gets the data associated with the operation.
716         * @return the field object representing the data
717         */
718        public Field getData() {
719            return this.data;
720        }
721
722        /**
723         * Gets the field key.
724         * @return the field key
725         */
726        public String getFieldKey() {
727            return this.fieldKey;
728        }
729
730        /**
731         * Gets the list of field keys.
732         * @return the list of Strings
733         */
734        public List<String> getFieldKeys() {
735            return this.fieldKeys;
736        }
737
738        /**
739         * Gets the list of keys of the Enum options.
740         * @return the list of Strings
741         */
742        public List<String> getEnumOptionKeys() {
743            return this.enumOptionKeys;
744        }
745
746        /**
747         * Sets the operation.
748         * @param op the operation
749         */
750        public void setOp(Operation op) {
751            this.op = op;
752        }
753
754        /**
755         * Sets the data.
756         * @param data the Field object representing the data
757         */
758        public void setData(Field data) {
759            this.data = data;
760        }
761
762        /**
763         * Sets the field key.
764         * @param fieldKey the key of the field
765         */
766        public void setFieldKey(String fieldKey) {
767            this.fieldKey = fieldKey;
768        }
769
770        /**
771         * Sets the list of the field keys.
772         * @param fieldKeys the list of strings
773         */
774        public void setFieldKeys(List<String> fieldKeys) {
775            this.fieldKeys = fieldKeys;
776        }
777
778        /**
779         * Sets the list of the enum option keys.
780         * @param enumOptionKeys the list of Strings
781         */
782        public void setEnumOptionKeys(List<String> enumOptionKeys) {
783            this.enumOptionKeys = enumOptionKeys;
784        }
785
786        /**
787         * Gets the enum option key.
788         * @return the enum option key
789         */
790        public String getEnumOptionKey() {
791            return this.enumOptionKey;
792        }
793
794        /**
795         * Sets the enum option key.
796         * @param enumOptionKey the enum option key
797         */
798        public void setEnumOptionKey(String enumOptionKey) {
799            this.enumOptionKey = enumOptionKey;
800        }
801
802        /**
803         * {@inheritDoc}
804         */
805        @Override
806        void parseJSONMember(JsonObject.Member member) {
807            JsonValue value = member.getValue();
808            String memberName = member.getName();
809            if (memberName.equals("op")) {
810                this.op = Operation.valueOf(value.asString());
811            } else if (memberName.equals("data")) {
812                this.data = new Field(value.asObject());
813            } else if (memberName.equals("fieldKey")) {
814                this.fieldKey = value.asString();
815            } else if (memberName.equals("fieldKeys")) {
816                if (this.fieldKeys == null) {
817                    this.fieldKeys = new ArrayList<String>();
818                } else {
819                    this.fieldKeys.clear();
820                }
821
822                JsonArray array = value.asArray();
823                for (JsonValue jsonValue: array) {
824                    this.fieldKeys.add(jsonValue.asString());
825                }
826            } else if (memberName.equals("enumOptionKeys")) {
827                if (this.enumOptionKeys == null) {
828                    this.enumOptionKeys = new ArrayList<String>();
829                } else {
830                    this.enumOptionKeys.clear();
831                }
832
833                JsonArray array = value.asArray();
834                for (JsonValue jsonValue: array) {
835                    this.enumOptionKeys.add(jsonValue.asString());
836                }
837            } else if (memberName.equals("enumOptionKey")) {
838                this.enumOptionKey = value.asString();
839            }
840        }
841    }
842
843    /**
844     * Possible template operations.
845     */
846    public enum Operation {
847
848        /**
849         * Adds an enum option at the end of the enum option list for the specified field.
850         */
851        addEnumOption,
852
853        /**
854         * Edits the enum option.
855         */
856        editEnumOption,
857
858        /**
859         * Removes the specified enum option from the specified enum field.
860         */
861        removeEnumOption,
862
863        /**
864         * Adds a field at the end of the field list for the template.
865         */
866        addField,
867
868        /**
869         * Edits any number of the base properties of a field: displayName, hidden, description.
870         */
871        editField,
872
873        /**
874         * Removes the specified field from the template.
875         */
876        removeField,
877
878        /**
879         * Edits any number of the base properties of a template: displayName, hidden.
880         */
881        editTemplate,
882
883        /**
884         * Reorders the enum option list to match the requested enum option list.
885         */
886        reorderEnumOptions,
887
888        /**
889         * Reorders the field list to match the requested field list.
890         */
891        reorderFields
892    }
893}