Skip to content

Commit 948e5c6

Browse files
authored
Add structured metadata APIs and entities (#171)
1 parent 9ecfdc9 commit 948e5c6

File tree

19 files changed

+893
-25
lines changed

19 files changed

+893
-25
lines changed

cloudinary-core/src/main/java/com/cloudinary/Api.java

Lines changed: 106 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import com.cloudinary.api.ApiResponse;
66
import com.cloudinary.api.AuthorizationRequired;
77
import com.cloudinary.api.exceptions.*;
8+
import com.cloudinary.metadata.MetadataField;
9+
import com.cloudinary.metadata.MetadataDataSource;
810
import com.cloudinary.strategies.AbstractApiStrategy;
911
import com.cloudinary.utils.ObjectUtils;
1012
import com.cloudinary.utils.StringUtils;
@@ -15,6 +17,7 @@ public class Api {
1517

1618

1719
public enum HttpMethod {GET, POST, PUT, DELETE;}
20+
1821
public final static Map<Integer, Class<? extends Exception>> CLOUDINARY_API_ERROR_CLASSES = new HashMap<Integer, Class<? extends Exception>>();
1922

2023
static {
@@ -30,6 +33,7 @@ public enum HttpMethod {GET, POST, PUT, DELETE;}
3033
public final Cloudinary cloudinary;
3134

3235
private AbstractApiStrategy strategy;
36+
3337
protected ApiResponse callApi(HttpMethod method, Iterable<String> uri, Map<String, ? extends Object> params, Map options) throws Exception {
3438
return this.strategy.callApi(method, uri, params, options);
3539
}
@@ -78,18 +82,18 @@ public ApiResponse resourcesByTag(String tag, Map options) throws Exception {
7882
}
7983

8084
public ApiResponse resourcesByContext(String key, Map options) throws Exception {
81-
return resourcesByContext(key,null,options);
85+
return resourcesByContext(key, null, options);
8286
}
8387

84-
public ApiResponse resourcesByContext(String key,String value, Map options) throws Exception {
88+
public ApiResponse resourcesByContext(String key, String value, Map options) throws Exception {
8589
if (options == null) options = ObjectUtils.emptyMap();
8690
String resourceType = ObjectUtils.asString(options.get("resource_type"), "image");
8791
Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations");
88-
params.put("key",key);
92+
params.put("key", key);
8993
if (StringUtils.isNotBlank(value)) {
90-
params.put("value",value);
94+
params.put("value", value);
9195
}
92-
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType,"context"), params , options);
96+
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "context"), params, options);
9397
}
9498

9599
public ApiResponse resourcesByIds(Iterable<String> publicIds, Map options) throws Exception {
@@ -372,7 +376,8 @@ public ApiResponse createStreamingProfile(String name, String displayName, List<
372376

373377
/**
374378
* Get a streaming profile information
375-
* @param name the name of the profile to fetch
379+
*
380+
* @param name the name of the profile to fetch
376381
* @param options additional options
377382
* @return a streaming profile
378383
* @throws Exception an exception
@@ -395,6 +400,7 @@ public ApiResponse getStreamingProfile(String name) throws Exception {
395400

396401
/**
397402
* List Streaming profiles
403+
*
398404
* @param options additional options
399405
* @return a list of all streaming profiles defined for the current cloud
400406
* @throws Exception an exception
@@ -416,7 +422,8 @@ public ApiResponse listStreamingProfiles() throws Exception {
416422

417423
/**
418424
* Delete a streaming profile information. Predefined profiles are restored to the default setting.
419-
* @param name the name of the profile to delete
425+
*
426+
* @param name the name of the profile to delete
420427
* @param options additional options
421428
* @return a streaming profile
422429
* @throws Exception an exception
@@ -481,11 +488,11 @@ public ApiResponse updateStreamingProfile(String name, String displayName, List<
481488
* @param accessMode The new access mode, "public" or "authenticated"
482489
* @param prefix The prefix by which to filter applicable resources
483490
* @param options additional options
484-
* <ul>
485-
* <li>resource_type - (default "image") - the type of resources to modify</li>
486-
* <li>max_results - optional - the maximum resources to process in a single invocation</li>
487-
* <li>next_cursor - optional - provided by a previous call to the method</li>
488-
* </ul>
491+
* <ul>
492+
* <li>resource_type - (default "image") - the type of resources to modify</li>
493+
* <li>max_results - optional - the maximum resources to process in a single invocation</li>
494+
* <li>next_cursor - optional - provided by a previous call to the method</li>
495+
* </ul>
489496
* @return a map of the returned values
490497
* <ul>
491498
* <li>updated - an array of resources</li>
@@ -503,11 +510,11 @@ public ApiResponse updateResourcesAccessModeByPrefix(String accessMode, String p
503510
* @param accessMode The new access mode, "public" or "authenticated"
504511
* @param tag The tag by which to filter applicable resources
505512
* @param options additional options
506-
* <ul>
507-
* <li>resource_type - (default "image") - the type of resources to modify</li>
508-
* <li>max_results - optional - the maximum resources to process in a single invocation</li>
509-
* <li>next_cursor - optional - provided by a previous call to the method</li>
510-
* </ul>
513+
* <ul>
514+
* <li>resource_type - (default "image") - the type of resources to modify</li>
515+
* <li>max_results - optional - the maximum resources to process in a single invocation</li>
516+
* <li>next_cursor - optional - provided by a previous call to the method</li>
517+
* </ul>
511518
* @return a map of the returned values
512519
* <ul>
513520
* <li>updated - an array of resources</li>
@@ -537,11 +544,11 @@ public ApiResponse deleteFolder(String folder, Map options) throws Exception {
537544
* @param accessMode The new access mode, "public" or "authenticated"
538545
* @param publicIds A list of public ids of resources to be updated
539546
* @param options additional options
540-
* <ul>
541-
* <li>resource_type - (default "image") - the type of resources to modify</li>
542-
* <li>max_results - optional - the maximum resources to process in a single invocation</li>
543-
* <li>next_cursor - optional - provided by a previous call to the method</li>
544-
* </ul>
547+
* <ul>
548+
* <li>resource_type - (default "image") - the type of resources to modify</li>
549+
* <li>max_results - optional - the maximum resources to process in a single invocation</li>
550+
* <li>next_cursor - optional - provided by a previous call to the method</li>
551+
* </ul>
545552
* @return a map of the returned values
546553
* <ul>
547554
* <li>updated - an array of resources</li>
@@ -564,4 +571,81 @@ private ApiResponse updateResourcesAccessMode(String accessMode, String byKey, O
564571
return callApi(HttpMethod.POST, uri, params, options);
565572
}
566573

574+
/**
575+
* Add a new metadata field definition
576+
* @param field The field to add.
577+
* @return A map representing the newlay added field.
578+
* @throws Exception
579+
*/
580+
public ApiResponse addMetadataField(MetadataField field) throws Exception {
581+
return callApi(HttpMethod.POST, Collections.singletonList("metadata_fields"),
582+
ObjectUtils.toMap(field), ObjectUtils.asMap ("content_type", "json"));
583+
}
584+
585+
/**
586+
* List all the metadata field definitions (structure, not values)
587+
* @return A map containing the list of field definitions maps.
588+
* @throws Exception
589+
*/
590+
public ApiResponse listMetadataFields() throws Exception {
591+
return callApi(HttpMethod.GET, Collections.singletonList("metadata_fields"), Collections.<String, Object>emptyMap(), Collections.emptyMap());
592+
}
593+
594+
/**
595+
* Get a metadata field definition by id
596+
* @param fieldExternalId The id of the field to retrieve
597+
* @return The fields definitions.
598+
* @throws Exception
599+
*/
600+
public ApiResponse metadataFieldByFieldId(String fieldExternalId) throws Exception {
601+
return callApi(HttpMethod.GET, Arrays.asList("metadata_fields", fieldExternalId), Collections.<String, Object>emptyMap(), Collections.emptyMap());
602+
}
603+
604+
/**
605+
* Update the definitions of a single metadata field.
606+
* @param fieldExternalId The id of the field to update
607+
* @param field The field definition
608+
* @return The updated fields definition.
609+
* @throws Exception
610+
*/
611+
public ApiResponse updateMetadataField(String fieldExternalId, MetadataField field) throws Exception {
612+
List<String> uri = Arrays.asList("metadata_fields", fieldExternalId);
613+
return callApi(HttpMethod.PUT, uri, ObjectUtils.toMap(field), Collections.singletonMap("content_type", "json"));
614+
}
615+
616+
/**
617+
* Update the datasource entries for a given field
618+
* @param fieldExternalId The id of the field to update
619+
* @param entries A list of datasource entries. Existing entries (according to entry id) will be updated,
620+
* new entries will be added.
621+
* @return The updated field definition.
622+
* @throws Exception
623+
*/
624+
public ApiResponse updateMetadataFieldDatasource(String fieldExternalId, List<MetadataDataSource.Entry> entries) throws Exception {
625+
List<String> uri = Arrays.asList("metadata_fields", fieldExternalId, "datasource");
626+
return callApi(HttpMethod.PUT, uri, Collections.singletonMap("values", entries), Collections.singletonMap("content_type", "json"));
627+
}
628+
629+
/**
630+
* Delete data source entries for a given field
631+
* @param fieldExternalId The id of the field to update
632+
* @param entriesExternalId The ids of all the entries to delete from the data source
633+
* @return The remaining datasource entries.
634+
* @throws Exception
635+
*/
636+
public ApiResponse deleteDatasourceEntries(String fieldExternalId, List<String> entriesExternalId) throws Exception {
637+
List<String> uri = Arrays.asList("metadata_fields", fieldExternalId, "datasource");
638+
return callApi(HttpMethod.DELETE, uri,Collections.singletonMap("external_ids", entriesExternalId) , Collections.emptyMap());
639+
}
640+
641+
/**
642+
* Delete a field definition.
643+
* @param fieldExternalId The id of the field to delete
644+
* @return A map with a "message" key. "ok" value indicates a successful deletion.
645+
* @throws Exception
646+
*/
647+
public ApiResponse deleteMetadataField(String fieldExternalId) throws Exception {
648+
List<String> uri = Arrays.asList("metadata_fields", fieldExternalId);
649+
return callApi(HttpMethod.DELETE, uri, Collections.<String, Object>emptyMap(), Collections.emptyMap());
650+
}
567651
}

cloudinary-core/src/main/java/com/cloudinary/Uploader.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,4 +516,23 @@ public String imageUploadTag(String field, Map options, Map<String, Object> html
516516
public Map deleteByToken(String token) throws Exception {
517517
return callApi("delete_by_token", ObjectUtils.asMap("token", token), ObjectUtils.emptyMap(), null);
518518
}
519+
520+
/**
521+
* Populates metadata fields with the given values. Existing values will be overwritten.
522+
* @param metadata a map of field name and value.
523+
* @param publicIds the public IDs of the resources to update
524+
* @param options additional options passed to the request
525+
* @return a list of public IDs that were updated
526+
* @throws IOException
527+
*/
528+
public Map updateMetadata(Map metadata, String[] publicIds, Map options) throws IOException {
529+
if (options == null)
530+
options = new HashMap();
531+
532+
Map<String, Object> params = new HashMap<String, Object>();
533+
params.put("metadata", Util.encodeContext(metadata));
534+
params.put("public_ids", Arrays.asList(publicIds));
535+
536+
return callApi("metadata", params, options, null);
537+
}
519538
}

cloudinary-core/src/main/java/com/cloudinary/Util.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ public static final void processWriteParameters(Map<String, Object> options, Map
9595
params.put("custom_coordinates", Coordinates.parseCoordinates(options.get("custom_coordinates")).toString());
9696
if (options.get("context") != null)
9797
params.put("context", encodeContext(options.get("context")));
98+
if (options.get("metadata") != null)
99+
params.put("metadata", encodeContext(options.get("metadata")));
98100
if (options.get("access_control") != null) {
99101
params.put("access_control", encodeAccessControl(options.get("access_control")));
100102
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.cloudinary.metadata;
2+
3+
import com.cloudinary.utils.ObjectUtils;
4+
5+
import java.text.ParseException;
6+
import java.util.Date;
7+
8+
/**
9+
* Represents a metadata field with type 'date'
10+
*/
11+
public class DateMetadataField extends MetadataField<Date> {
12+
13+
public DateMetadataField() {
14+
super(MetadataFieldType.DATE);
15+
}
16+
17+
/**
18+
* Sets the default date used for this field.
19+
* @param defaultValue The date to set. Date only without a time component, UTC assumed.
20+
*/
21+
@Override
22+
public void setDefaultValue(Date defaultValue) {
23+
put(DEFAULT_VALUE, ObjectUtils.toISO8601DateOnly(defaultValue));
24+
}
25+
26+
/**
27+
* Get the default value of this date field.
28+
* @return The date only without a time component, UTC.
29+
* @throws ParseException When the underlying value is malformed.
30+
*/
31+
@Override
32+
public Date getDefaultValue() throws ParseException {
33+
Object value = get(DEFAULT_VALUE);
34+
if (value == null) {
35+
return null;
36+
}
37+
38+
return ObjectUtils.fromISO8601DateOnly(value.toString());
39+
}
40+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.cloudinary.metadata;
2+
3+
/**
4+
* Represents a metadata field with 'Enum' type.
5+
*/
6+
public class EnumMetadataField extends MetadataField<String> {
7+
EnumMetadataField() {
8+
super(MetadataFieldType.ENUM);
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.cloudinary.metadata;
2+
3+
/**
4+
* Represents a metadata field with 'Int' type.
5+
*/
6+
public class IntMetadataField extends MetadataField<Integer> {
7+
public IntMetadataField() {
8+
super(MetadataFieldType.INTEGER);
9+
}
10+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.cloudinary.metadata;
2+
3+
import org.cloudinary.json.JSONArray;
4+
import org.cloudinary.json.JSONObject;
5+
6+
import java.util.List;
7+
8+
/**
9+
* Represent a data source for a given field. This is used in both 'Set' and 'Enum' field types.
10+
* The datasource holds a list of the valid values to be used with the corresponding metadata field.
11+
*/
12+
public class MetadataDataSource extends JSONObject {
13+
/**
14+
* Creates a new instance of data source with the given list of entries.
15+
* @param entries
16+
*/
17+
public MetadataDataSource(List<Entry> entries) {
18+
put("values", new JSONArray(entries.toArray()));
19+
}
20+
21+
/**
22+
* Represents a single entry in a datasource definition for a field.
23+
*/
24+
public static class Entry extends JSONObject {
25+
public Entry(String externalId, String value){
26+
setExternalId(externalId);
27+
setValue(value);
28+
}
29+
30+
/**
31+
* Create a new entry with a string value.
32+
* @param value The value to use in the entry.
33+
*/
34+
public Entry(String value){
35+
this(null, value);
36+
}
37+
38+
/**
39+
* Set the id of the entry. Will be auto-generated if left blank.
40+
* @param externalId
41+
*/
42+
public void setExternalId(String externalId) {
43+
put("external_id", externalId);
44+
}
45+
46+
/**
47+
* Get the id of the entry.
48+
* @return
49+
*/
50+
public String getExternalId() {
51+
return optString("external_id");
52+
}
53+
54+
/**
55+
* Set the value of the entry.
56+
* @param value The value to set.
57+
*/
58+
public void setValue(String value) {
59+
put("value", value);
60+
}
61+
62+
/**
63+
* Get the value of the entry.
64+
* @return The value.
65+
*/
66+
public String getValue() {
67+
return optString("value");
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)