Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 106 additions & 22 deletions cloudinary-core/src/main/java/com/cloudinary/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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>
Expand All @@ -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>
Expand All @@ -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
Copy link
Contributor

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?

*/
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistency - sometimes it is called externalId and sometimes fieldExternalId.
I suggest using fieldId (not sure what the external represents)

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the fieldExternalId vs. externalId, got it.

Regarding the external,
I understand that this is what the server is using, but I don't understand why they are using it.
In any case, why do we have to be aligned with the server naming?

Copy link
Contributor Author

@nitzanj nitzanj Aug 7, 2019

Choose a reason for hiding this comment

The 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...

Copy link
Contributor

Choose a reason for hiding this comment

The 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());
}
}
19 changes: 19 additions & 0 deletions cloudinary-core/src/main/java/com/cloudinary/Uploader.java
Original file line number Diff line number Diff line change
Expand Up @@ -516,4 +516,23 @@ public String imageUploadTag(String field, Map options, Map<String, Object> html
public Map deleteByToken(String token) throws Exception {
return callApi("delete_by_token", ObjectUtils.asMap("token", token), ObjectUtils.emptyMap(), null);
}

/**
* Populates metadata fields with the given values. Existing values will be overwritten.
* @param metadata a map of field name and value.
* @param publicIds the public IDs of the resources to update
* @param options additional options passed to the request
* @return a list of public IDs that were updated
* @throws IOException
*/
public Map updateMetadata(Map metadata, String[] publicIds, Map options) throws IOException {
if (options == null)
options = new HashMap();

Map<String, Object> params = new HashMap<String, Object>();
params.put("metadata", Util.encodeContext(metadata));
params.put("public_ids", Arrays.asList(publicIds));

return callApi("metadata", params, options, null);
}
}
2 changes: 2 additions & 0 deletions cloudinary-core/src/main/java/com/cloudinary/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ public static final void processWriteParameters(Map<String, Object> options, Map
params.put("custom_coordinates", Coordinates.parseCoordinates(options.get("custom_coordinates")).toString());
if (options.get("context") != null)
params.put("context", encodeContext(options.get("context")));
if (options.get("metadata") != null)
params.put("metadata", encodeContext(options.get("metadata")));
if (options.get("access_control") != null) {
params.put("access_control", encodeAccessControl(options.get("access_control")));
}
Expand Down
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");
}
}
}
Loading