-
Notifications
You must be signed in to change notification settings - Fork 112
Feature/structured metadata #171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
95dc2b4
b7a3e92
ed656b5
342c92f
fdf8c8f
4167172
542c1a9
be62150
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,8 @@ | |
| import com.cloudinary.api.ApiResponse; | ||
| import com.cloudinary.api.AuthorizationRequired; | ||
| import com.cloudinary.api.exceptions.*; | ||
| import com.cloudinary.metadata.MetadataField; | ||
| import com.cloudinary.metadata.MetadataDataSource; | ||
| import com.cloudinary.strategies.AbstractApiStrategy; | ||
| import com.cloudinary.utils.ObjectUtils; | ||
| import com.cloudinary.utils.StringUtils; | ||
|
|
@@ -15,6 +17,7 @@ public class Api { | |
|
|
||
|
|
||
| public enum HttpMethod {GET, POST, PUT, DELETE;} | ||
|
|
||
| public final static Map<Integer, Class<? extends Exception>> CLOUDINARY_API_ERROR_CLASSES = new HashMap<Integer, Class<? extends Exception>>(); | ||
|
|
||
| static { | ||
|
|
@@ -30,6 +33,7 @@ public enum HttpMethod {GET, POST, PUT, DELETE;} | |
| public final Cloudinary cloudinary; | ||
|
|
||
| private AbstractApiStrategy strategy; | ||
|
|
||
| protected ApiResponse callApi(HttpMethod method, Iterable<String> uri, Map<String, ? extends Object> params, Map options) throws Exception { | ||
| return this.strategy.callApi(method, uri, params, options); | ||
| } | ||
|
|
@@ -78,18 +82,18 @@ public ApiResponse resourcesByTag(String tag, Map options) throws Exception { | |
| } | ||
|
|
||
| public ApiResponse resourcesByContext(String key, Map options) throws Exception { | ||
| return resourcesByContext(key,null,options); | ||
| return resourcesByContext(key, null, options); | ||
| } | ||
|
|
||
| public ApiResponse resourcesByContext(String key,String value, Map options) throws Exception { | ||
| public ApiResponse resourcesByContext(String key, String value, Map options) throws Exception { | ||
| if (options == null) options = ObjectUtils.emptyMap(); | ||
| String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); | ||
| Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"); | ||
| params.put("key",key); | ||
| params.put("key", key); | ||
| if (StringUtils.isNotBlank(value)) { | ||
| params.put("value",value); | ||
| params.put("value", value); | ||
| } | ||
| return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType,"context"), params , options); | ||
| return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "context"), params, options); | ||
| } | ||
|
|
||
| public ApiResponse resourcesByIds(Iterable<String> publicIds, Map options) throws Exception { | ||
|
|
@@ -372,7 +376,8 @@ public ApiResponse createStreamingProfile(String name, String displayName, List< | |
|
|
||
| /** | ||
| * Get a streaming profile information | ||
| * @param name the name of the profile to fetch | ||
| * | ||
| * @param name the name of the profile to fetch | ||
| * @param options additional options | ||
| * @return a streaming profile | ||
| * @throws Exception an exception | ||
|
|
@@ -395,6 +400,7 @@ public ApiResponse getStreamingProfile(String name) throws Exception { | |
|
|
||
| /** | ||
| * List Streaming profiles | ||
| * | ||
| * @param options additional options | ||
| * @return a list of all streaming profiles defined for the current cloud | ||
| * @throws Exception an exception | ||
|
|
@@ -416,7 +422,8 @@ public ApiResponse listStreamingProfiles() throws Exception { | |
|
|
||
| /** | ||
| * Delete a streaming profile information. Predefined profiles are restored to the default setting. | ||
| * @param name the name of the profile to delete | ||
| * | ||
| * @param name the name of the profile to delete | ||
| * @param options additional options | ||
| * @return a streaming profile | ||
| * @throws Exception an exception | ||
|
|
@@ -481,11 +488,11 @@ public ApiResponse updateStreamingProfile(String name, String displayName, List< | |
| * @param accessMode The new access mode, "public" or "authenticated" | ||
| * @param prefix The prefix by which to filter applicable resources | ||
| * @param options additional options | ||
| * <ul> | ||
| * <li>resource_type - (default "image") - the type of resources to modify</li> | ||
| * <li>max_results - optional - the maximum resources to process in a single invocation</li> | ||
| * <li>next_cursor - optional - provided by a previous call to the method</li> | ||
| * </ul> | ||
| * <ul> | ||
| * <li>resource_type - (default "image") - the type of resources to modify</li> | ||
| * <li>max_results - optional - the maximum resources to process in a single invocation</li> | ||
| * <li>next_cursor - optional - provided by a previous call to the method</li> | ||
| * </ul> | ||
| * @return a map of the returned values | ||
| * <ul> | ||
| * <li>updated - an array of resources</li> | ||
|
|
@@ -503,11 +510,11 @@ public ApiResponse updateResourcesAccessModeByPrefix(String accessMode, String p | |
| * @param accessMode The new access mode, "public" or "authenticated" | ||
| * @param tag The tag by which to filter applicable resources | ||
| * @param options additional options | ||
| * <ul> | ||
| * <li>resource_type - (default "image") - the type of resources to modify</li> | ||
| * <li>max_results - optional - the maximum resources to process in a single invocation</li> | ||
| * <li>next_cursor - optional - provided by a previous call to the method</li> | ||
| * </ul> | ||
| * <ul> | ||
| * <li>resource_type - (default "image") - the type of resources to modify</li> | ||
| * <li>max_results - optional - the maximum resources to process in a single invocation</li> | ||
| * <li>next_cursor - optional - provided by a previous call to the method</li> | ||
| * </ul> | ||
| * @return a map of the returned values | ||
| * <ul> | ||
| * <li>updated - an array of resources</li> | ||
|
|
@@ -525,11 +532,11 @@ public ApiResponse updateResourcesAccessModeByTag(String accessMode, String tag, | |
| * @param accessMode The new access mode, "public" or "authenticated" | ||
| * @param publicIds A list of public ids of resources to be updated | ||
| * @param options additional options | ||
| * <ul> | ||
| * <li>resource_type - (default "image") - the type of resources to modify</li> | ||
| * <li>max_results - optional - the maximum resources to process in a single invocation</li> | ||
| * <li>next_cursor - optional - provided by a previous call to the method</li> | ||
| * </ul> | ||
| * <ul> | ||
| * <li>resource_type - (default "image") - the type of resources to modify</li> | ||
| * <li>max_results - optional - the maximum resources to process in a single invocation</li> | ||
| * <li>next_cursor - optional - provided by a previous call to the method</li> | ||
| * </ul> | ||
| * @return a map of the returned values | ||
| * <ul> | ||
| * <li>updated - an array of resources</li> | ||
|
|
@@ -552,4 +559,81 @@ private ApiResponse updateResourcesAccessMode(String accessMode, String byKey, O | |
| return callApi(HttpMethod.POST, uri, params, options); | ||
| } | ||
|
|
||
| /** | ||
| * Add a new metadata field definition | ||
| * @param field The field to add. | ||
| * @return A map representing the newlay added field. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse addMetadataField(MetadataField field) throws Exception { | ||
| return callApi(HttpMethod.POST, Collections.singletonList("metadata_fields"), | ||
| ObjectUtils.toMap(field), ObjectUtils.asMap ("content_type", "json")); | ||
| } | ||
|
|
||
| /** | ||
| * List all the metadata field definitions (structure, not values) | ||
| * @return A map containing the list of field definitions maps. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse listMetadataFields() throws Exception { | ||
| return callApi(HttpMethod.GET, Collections.singletonList("metadata_fields"), Collections.<String, Object>emptyMap(), Collections.emptyMap()); | ||
| } | ||
|
|
||
| /** | ||
| * Get a metadata field definition by id | ||
| * @param fieldExternalId The id of the field to retrieve | ||
| * @return The fields definitions. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse metadataFieldByFieldId(String fieldExternalId) throws Exception { | ||
| return callApi(HttpMethod.GET, Arrays.asList("metadata_fields", fieldExternalId), Collections.<String, Object>emptyMap(), Collections.emptyMap()); | ||
| } | ||
|
|
||
| /** | ||
| * Update the definitions of a single metadata field. | ||
| * @param fieldExternalId The id of the field to update | ||
| * @param field The field definition | ||
| * @return The updated fields definition. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse updateMetadataField(String fieldExternalId, MetadataField field) throws Exception { | ||
| List<String> uri = Arrays.asList("metadata_fields", fieldExternalId); | ||
| return callApi(HttpMethod.PUT, uri, ObjectUtils.toMap(field), Collections.singletonMap("content_type", "json")); | ||
| } | ||
|
|
||
| /** | ||
| * Update the datasource entries for a given field | ||
| * @param fieldExternalId The id of the field to update | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistency - sometimes it is called externalId and sometimes fieldExternalId.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When you send an ID to a function about a field you an omit the 'field' for brevity. When you need to provide an id for a field in the context of another API (e.g. datasource, that has it's own id() you must include the 'field' in the parameter name for clarity. I can use 'fieldExternalId' everywhere for consistency. The word external is part of the spec, that's the key used in all the requests and responses, we have to use it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding the fieldExternalId vs. externalId, got it. Regarding the external,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a long discussion about it with docs, for them it's real bad if the API docs use different names than the SDK docs so we're using the same names. We can open it up tomorrow to if you want, for us it's a quick easy fix...
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool. let's talk about it |
||
| * @param entries A list of datasource entries. Existing entries (according to entry id) will be updated, | ||
| * new entries will be added. | ||
| * @return The updated field definition. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse updateMetadataFieldDatasource(String fieldExternalId, List<MetadataDataSource.Entry> entries) throws Exception { | ||
| List<String> uri = Arrays.asList("metadata_fields", fieldExternalId, "datasource"); | ||
| return callApi(HttpMethod.PUT, uri, Collections.singletonMap("values", entries), Collections.singletonMap("content_type", "json")); | ||
| } | ||
|
|
||
| /** | ||
| * Delete data source entries for a given field | ||
| * @param fieldExternalId The id of the field to update | ||
| * @param entriesExternalId The ids of all the entries to delete from the data source | ||
| * @return The remaining datasource entries. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse deleteDatasourceEntries(String fieldExternalId, List<String> entriesExternalId) throws Exception { | ||
| List<String> uri = Arrays.asList("metadata_fields", fieldExternalId, "datasource"); | ||
| return callApi(HttpMethod.DELETE, uri,Collections.singletonMap("external_ids", entriesExternalId) , Collections.emptyMap()); | ||
| } | ||
|
|
||
| /** | ||
| * Delete a field definition. | ||
| * @param fieldExternalId The id of the field to delete | ||
| * @return A map with a "message" key. "ok" value indicates a successful deletion. | ||
| * @throws Exception | ||
| */ | ||
| public ApiResponse deleteMetadataField(String fieldExternalId) throws Exception { | ||
| List<String> uri = Arrays.asList("metadata_fields", fieldExternalId); | ||
| return callApi(HttpMethod.DELETE, uri, Collections.<String, Object>emptyMap(), Collections.emptyMap()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| package com.cloudinary.metadata; | ||
|
|
||
| import com.cloudinary.utils.ObjectUtils; | ||
|
|
||
| import java.text.ParseException; | ||
| import java.util.Date; | ||
|
|
||
| /** | ||
| * Represents a metadata field with type 'date' | ||
| */ | ||
| public class DateMetadataField extends MetadataField<Date> { | ||
|
|
||
| public DateMetadataField() { | ||
| super(MetadataFieldType.DATE); | ||
| } | ||
|
|
||
| /** | ||
| * Sets the default date used for this field. | ||
| * @param defaultValue The date to set. Date only without a time component, UTC assumed. | ||
| */ | ||
| @Override | ||
| public void setDefaultValue(Date defaultValue) { | ||
| put(DEFAULT_VALUE, ObjectUtils.toISO8601DateOnly(defaultValue)); | ||
| } | ||
|
|
||
| /** | ||
| * Get the default value of this date field. | ||
| * @return The date only without a time component, UTC. | ||
| * @throws ParseException When the underlying value is malformed. | ||
| */ | ||
| @Override | ||
| public Date getDefaultValue() throws ParseException { | ||
| Object value = get(DEFAULT_VALUE); | ||
| if (value == null) { | ||
| return null; | ||
| } | ||
|
|
||
| return ObjectUtils.fromISO8601DateOnly(value.toString()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.cloudinary.metadata; | ||
|
|
||
| /** | ||
| * Represents a metadata field with 'Enum' type. | ||
| */ | ||
| public class EnumMetadataField extends MetadataField<String> { | ||
| EnumMetadataField() { | ||
| super(MetadataFieldType.ENUM); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.cloudinary.metadata; | ||
|
|
||
| /** | ||
| * Represents a metadata field with 'Int' type. | ||
| */ | ||
| public class IntMetadataField extends MetadataField<Integer> { | ||
| public IntMetadataField() { | ||
| super(MetadataFieldType.INTEGER); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| package com.cloudinary.metadata; | ||
|
|
||
| import org.cloudinary.json.JSONArray; | ||
| import org.cloudinary.json.JSONObject; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Represent a data source for a given field. This is used in both 'Set' and 'Enum' field types. | ||
| * The datasource holds a list of the valid values to be used with the corresponding metadata field. | ||
| */ | ||
| public class MetadataDataSource extends JSONObject { | ||
| /** | ||
| * Creates a new instance of data source with the given list of entries. | ||
| * @param entries | ||
| */ | ||
| public MetadataDataSource(List<Entry> entries) { | ||
| put("values", new JSONArray(entries.toArray())); | ||
| } | ||
|
|
||
| /** | ||
| * Represents a single entry in a datasource definition for a field. | ||
| */ | ||
| public static class Entry extends JSONObject { | ||
| public Entry(String externalId, String value){ | ||
| setExternalId(externalId); | ||
| setValue(value); | ||
| } | ||
|
|
||
| /** | ||
| * Create a new entry with a string value. | ||
| * @param value The value to use in the entry. | ||
| */ | ||
| public Entry(String value){ | ||
| this(null, value); | ||
| } | ||
|
|
||
| /** | ||
| * Set the id of the entry. Will be auto-generated if left blank. | ||
| * @param externalId | ||
| */ | ||
| public void setExternalId(String externalId) { | ||
| put("external_id", externalId); | ||
| } | ||
|
|
||
| /** | ||
| * Get the id of the entry. | ||
| * @return | ||
| */ | ||
| public String getExternalId() { | ||
| return optString("external_id"); | ||
| } | ||
|
|
||
| /** | ||
| * Set the value of the entry. | ||
| * @param value The value to set. | ||
| */ | ||
| public void setValue(String value) { | ||
| put("value", value); | ||
| } | ||
|
|
||
| /** | ||
| * Get the value of the entry. | ||
| * @return The value. | ||
| */ | ||
| public String getValue() { | ||
| return optString("value"); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What kind of error should I expect to get here?