Skip to content

Commit 6a696f9

Browse files
committed
new update method. add listing by moderation kind and status. add moderation status in listing. add moderation flag in upload. add moderation_status in update. add ocr, raw_conversion, categorization, detection, similarity_search and auto_tagging parameters in update and upload. add support for uploading large raw files
1 parent 13b4977 commit 6a696f9

File tree

9 files changed

+424
-34
lines changed

9 files changed

+424
-34
lines changed

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,23 +121,29 @@ public Map resources(Map options) throws Exception {
121121
uri.add(resourceType);
122122
if (type != null)
123123
uri.add(type);
124-
return callApi(HttpMethod.GET, uri, only(options, "next_cursor", "direction", "max_results", "prefix", "tags", "context"), options);
124+
return callApi(HttpMethod.GET, uri, only(options, "next_cursor", "direction", "max_results", "prefix", "tags", "context", "moderations"), options);
125125
}
126-
126+
127127
public Map resourcesByTag(String tag, Map options) throws Exception {
128128
if (options == null) options = Cloudinary.emptyMap();
129129
String resourceType = Cloudinary.asString(options.get("resource_type"), "image");
130-
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "tags", tag), only(options, "next_cursor", "direction", "max_results", "tags", "context"), options);
130+
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "tags", tag), only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"), options);
131131
}
132132

133133
public Map resourcesByIds(Iterable<String> publicIds, Map options) throws Exception {
134134
if (options == null) options = Cloudinary.emptyMap();
135135
String resourceType = Cloudinary.asString(options.get("resource_type"), "image");
136136
String type = Cloudinary.asString(options.get("type"), "upload");
137-
Map params = only(options, "tags", "context");
137+
Map params = only(options, "tags", "context", "moderations");
138138
params.put("public_ids", publicIds);
139139
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type), params, options);
140140
}
141+
142+
public Map resourcesByModeration(String kind, String status, Map options) throws Exception {
143+
if (options == null) options = Cloudinary.emptyMap();
144+
String resourceType = Cloudinary.asString(options.get("resource_type"), "image");
145+
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "moderations", kind, status), only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"), options);
146+
}
141147

142148
public Map resource(String public_id, Map options) throws Exception {
143149
if (options == null) options = Cloudinary.emptyMap();
@@ -146,6 +152,17 @@ public Map resource(String public_id, Map options) throws Exception {
146152
return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type, public_id),
147153
only(options, "exif", "colors", "faces", "image_metadata", "pages", "max_results"), options);
148154
}
155+
156+
public Map update(String public_id, Map options) throws Exception {
157+
if (options == null) options = Cloudinary.emptyMap();
158+
String resourceType = Cloudinary.asString(options.get("resource_type"), "image");
159+
String type = Cloudinary.asString(options.get("type"), "upload");
160+
Map params = new HashMap<String, Object>();
161+
Util.processWriteParameters(options, params);
162+
params.put("moderation_status", options.get("moderation_status"));
163+
return callApi(HttpMethod.POST, Arrays.asList("resources", resourceType, type, public_id),
164+
params, options);
165+
}
149166

150167
public Map deleteResources(Iterable<String> publicIds, Map options) throws Exception {
151168
if (options == null) options = Cloudinary.emptyMap();

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,16 @@ public static Boolean asBoolean(Object value, Boolean defaultValue) {
241241
}
242242
}
243243

244+
public static Float asFloat(Object value) {
245+
if (value == null) {
246+
return null;
247+
} else if (value instanceof Float) {
248+
return (Float) value;
249+
} else {
250+
return Float.parseFloat(value.toString());
251+
}
252+
}
253+
244254
public static Map asMap(Object...values) {
245255
if (values.length % 2 != 0) throw new RuntimeException("Usage - (key, value, key, value, ...)");
246256
Map result = new HashMap(values.length / 2);

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

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.io.File;
55
import java.io.IOException;
66
import java.io.InputStream;
7+
import java.io.FileInputStream;
8+
import java.io.ByteArrayInputStream;
79
import java.util.ArrayList;
810
import java.util.Arrays;
911
import java.util.Collection;
@@ -57,17 +59,14 @@ public Map<String, Object> buildUploadParams(Map options) {
5759
params.put(attr, value.toString());
5860
}
5961
params.put("eager", buildEager((List<Transformation>) options.get("eager")));
60-
params.put("headers", buildCustomHeaders(options.get("headers")));
6162
params.put("notification_url", (String) options.get("notification_url"));
6263
params.put("eager_notification_url", (String) options.get("eager_notification_url"));
6364
params.put("proxy", (String) options.get("proxy"));
6465
params.put("folder", (String) options.get("folder"));
65-
params.put("tags", StringUtils.join(Cloudinary.asArray(options.get("tags")), ","));
66-
if (options.get("face_coordinates") != null) {
67-
params.put("face_coordinates", options.get("face_coordinates").toString());
68-
}
6966
params.put("allowed_formats", StringUtils.join(Cloudinary.asArray(options.get("allowed_formats")), ","));
70-
params.put("context", Cloudinary.encodeMap(options.get("context")));
67+
params.put("moderation", options.get("moderation"));
68+
69+
Util.processWriteParameters(options, params);
7170
return params;
7271
}
7372

@@ -76,6 +75,61 @@ public Map upload(Object file, Map options) throws IOException {
7675
Map<String, Object> params = buildUploadParams(options);
7776
return callApi("upload", params, options, file);
7877
}
78+
79+
public Map uploadLargeRaw(Object file, Map options) throws IOException {
80+
return uploadLargeRaw(file, options, 20000000);
81+
}
82+
83+
public Map uploadLargeRaw(Object file, Map options, int bufferSize) throws IOException {
84+
InputStream input;
85+
if (file instanceof InputStream) {
86+
input = (InputStream) file;
87+
} else if (file instanceof File) {
88+
input = new FileInputStream((File) file);
89+
} else if (file instanceof byte[]) {
90+
input = new ByteArrayInputStream((byte[]) file);
91+
} else {
92+
input = new FileInputStream(new File(file.toString()));
93+
}
94+
try {
95+
Map result = uploadLargeRawPart(input, buildUploadParams(options), bufferSize);
96+
return result;
97+
} finally {
98+
input.close();
99+
}
100+
}
101+
102+
private Map uploadLargeRawPart(InputStream input, Map params, int bufferSize) throws IOException {
103+
Map nextParams = new HashMap();
104+
Map sentParams = new HashMap();
105+
nextParams.putAll(params);
106+
byte[] buffer = new byte[bufferSize];
107+
Map options = Cloudinary.asMap("resource_type", "raw");
108+
int bytesRead;
109+
int partNumber = 1;
110+
while ((bytesRead = input.read(buffer)) != -1) {
111+
if (bufferSize > bytesRead && bytesRead != -1) {
112+
byte[] shortBuffer = new byte[bytesRead];
113+
System.arraycopy(buffer, 0, shortBuffer, 0, bytesRead);
114+
buffer = shortBuffer;
115+
}
116+
nextParams.put("part_number", Integer.toString(partNumber));
117+
sentParams.clear();
118+
sentParams.putAll(nextParams);
119+
if (partNumber == 1) {
120+
Map response = callApi("upload_large", sentParams, options, buffer);
121+
nextParams.put("public_id", response.get("public_id"));
122+
nextParams.put("upload_id", response.get("upload_id"));
123+
} else {
124+
callApi("upload_large", sentParams, options, buffer);
125+
}
126+
partNumber++;
127+
}
128+
nextParams.put("final", true);
129+
nextParams.put("part_number", Integer.toString(partNumber));
130+
return callApi("upload_large", nextParams, options, new byte[0]);
131+
}
132+
79133

80134
public Map destroy(String publicId, Map options) throws IOException {
81135
if (options == null) options = Cloudinary.emptyMap();
@@ -103,7 +157,7 @@ public Map explicit(String publicId, Map options) throws IOException {
103157
params.put("callback", (String) options.get("callback"));
104158
params.put("type", (String) options.get("type"));
105159
params.put("eager", buildEager((List<Transformation>) options.get("eager")));
106-
params.put("headers", buildCustomHeaders(options.get("headers")));
160+
params.put("headers", Util.buildCustomHeaders(options.get("headers")));
107161
params.put("tags", StringUtils.join(Cloudinary.asArray(options.get("tags")), ","));
108162
if (options.get("face_coordinates") != null) {
109163
params.put("face_coordinates", options.get("face_coordinates").toString());
@@ -377,20 +431,4 @@ protected String buildEager(List<? extends Transformation> transformations) {
377431
return StringUtils.join(eager, "|");
378432
}
379433

380-
protected String buildCustomHeaders(Object headers) {
381-
if (headers == null) {
382-
return null;
383-
} else if (headers instanceof String) {
384-
return (String) headers;
385-
} else if (headers instanceof Object[]) {
386-
return StringUtils.join((Object[]) headers, "\n") + "\n";
387-
} else {
388-
Map<String, String> headersMap = (Map<String, String>) headers;
389-
StringBuilder builder = new StringBuilder();
390-
for (Map.Entry<String, String> header : headersMap.entrySet()) {
391-
builder.append(header.getKey()).append(": ").append(header.getValue()).append("\n");
392-
}
393-
return builder.toString();
394-
}
395-
}
396434
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.cloudinary;
2+
3+
import org.apache.commons.lang.StringUtils;
4+
5+
import java.util.Map;
6+
7+
public class Util {
8+
protected static final void processWriteParameters(
9+
Map<String, Object> options, Map<String, Object> params) {
10+
if (options.get("headers") != null)
11+
params.put("headers", buildCustomHeaders(options.get("headers")));
12+
if (options.get("tags") != null)
13+
params.put("tags", StringUtils.join(
14+
Cloudinary.asArray(options.get("tags")), ","));
15+
if (options.get("face_coordinates") != null)
16+
params.put("face_coordinates", options.get("face_coordinates")
17+
.toString());
18+
if (options.get("context") != null)
19+
params.put("context", Cloudinary.encodeMap(options.get("context")));
20+
if (options.get("ocr") != null)
21+
params.put("ocr", options.get("ocr"));
22+
if (options.get("raw_convert") != null)
23+
params.put("raw_convert", options.get("raw_convert"));
24+
if (options.get("categorization") != null)
25+
params.put("categorization", options.get("categorization"));
26+
if (options.get("detection") != null)
27+
params.put("detection", options.get("detection"));
28+
if (options.get("similarity_search") != null)
29+
params.put("similarity_search", options.get("similarity_search"));
30+
if (options.get("auto_tagging") != null)
31+
params.put("auto_tagging",
32+
Cloudinary.asFloat(options.get("auto_tagging")));
33+
}
34+
35+
protected static final String buildCustomHeaders(Object headers) {
36+
if (headers == null) {
37+
return null;
38+
} else if (headers instanceof String) {
39+
return (String) headers;
40+
} else if (headers instanceof Object[]) {
41+
return StringUtils.join((Object[]) headers, "\n") + "\n";
42+
} else {
43+
Map<String, String> headersMap = (Map<String, String>) headers;
44+
StringBuilder builder = new StringBuilder();
45+
for (Map.Entry<String, String> header : headersMap.entrySet()) {
46+
builder.append(header.getKey()).append(": ")
47+
.append(header.getValue()).append("\n");
48+
}
49+
return builder.toString();
50+
}
51+
}
52+
}

cloudinary-core/src/test/java/com/cloudinary/test/ApiTest.java

Lines changed: 128 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static org.junit.Assert.assertEquals;
44
import static org.junit.Assert.assertNotNull;
5+
import static org.junit.Assert.assertNull;
56
import static org.junit.Assert.assertNotSame;
67
import static org.junit.Assert.assertTrue;
78
import static org.junit.Assume.assumeNotNull;
@@ -359,19 +360,140 @@ public void test19Ping() throws Exception {
359360
assertEquals(result.get("status"), "ok");
360361
}
361362

362-
private void assertContains(Object object, Collection list) {
363-
assertTrue(list.contains(object));
364-
}
365-
366363
// This test must be last because it deletes (potentially) all dependent transformations which some tests rely on.
367364
// Add @Test if you really want to test it - This test deletes derived resources!
368365
public void testDeleteAllResources() throws Exception {
369366
// should allow deleting all resources
370367
cloudinary.uploader().upload("src/test/resources/logo.png", Cloudinary.asMap("public_id", "api_test5", "eager", Collections.singletonList(new Transformation().crop("scale").width(2.0))));
371-
Map result = cloudinary.api().resource("api_test5", Cloudinary.emptyMap());
368+
Map result = api.resource("api_test5", Cloudinary.emptyMap());
372369
assertEquals(1, ((org.json.simple.JSONArray) result.get("derived")).size());
373370
api.deleteAllResources(Cloudinary.asMap("keep_original", true));
374-
result = cloudinary.api().resource("api_test5", Cloudinary.emptyMap());
371+
result = api.resource("api_test5", Cloudinary.emptyMap());
375372
//assertEquals(0, ((org.json.simple.JSONArray) result.get("derived")).size());
376373
}
374+
375+
376+
@Test
377+
public void testManualModeration() throws Exception {
378+
// should support setting manual moderation status
379+
Map uploadResult = cloudinary.uploader().upload("src/test/resources/logo.png", Cloudinary.asMap("moderation","manual"));
380+
Map apiResult = api.update((String) uploadResult.get("public_id"), Cloudinary.asMap("moderation_status", "approved"));
381+
assertEquals("approved", ((Map) ((List<Map>) apiResult.get("moderation")).get(0)).get("status"));
382+
}
383+
384+
@Test
385+
public void testOcrUpdate() {
386+
// should support requesting ocr info
387+
try {
388+
Map uploadResult = cloudinary.uploader().upload(
389+
"src/test/resources/logo.png", Cloudinary.emptyMap());
390+
api.update((String) uploadResult.get("public_id"),
391+
Cloudinary.asMap("ocr", "illegal"));
392+
} catch (Exception e) {
393+
assertTrue(e instanceof com.cloudinary.Api.BadRequest);
394+
assertTrue(e.getMessage().matches("^Illegal value(.*)"));
395+
}
396+
}
397+
398+
@Test
399+
public void testRawConvertUpdate() {
400+
// should support requesting raw conversion
401+
try {
402+
Map uploadResult = cloudinary.uploader().upload(
403+
"src/test/resources/logo.png", Cloudinary.emptyMap());
404+
api.update((String) uploadResult.get("public_id"),
405+
Cloudinary.asMap("raw_convert", "illegal"));
406+
} catch (Exception e) {
407+
assertTrue(e instanceof com.cloudinary.Api.BadRequest);
408+
assertTrue(e.getMessage().matches("^Illegal value(.*)"));
409+
}
410+
}
411+
412+
@Test
413+
public void testCategorizationUpdate() {
414+
// should support requesting categorization
415+
try {
416+
Map uploadResult = cloudinary.uploader().upload(
417+
"src/test/resources/logo.png", Cloudinary.emptyMap());
418+
api.update((String) uploadResult.get("public_id"),
419+
Cloudinary.asMap("categorization", "illegal"));
420+
} catch (Exception e) {
421+
assertTrue(e instanceof com.cloudinary.Api.BadRequest);
422+
assertTrue(e.getMessage().matches("^Illegal value(.*)"));
423+
}
424+
}
425+
426+
@Test
427+
public void testDetectionUpdate() {
428+
// should support requesting detection
429+
try {
430+
Map uploadResult = cloudinary.uploader().upload(
431+
"src/test/resources/logo.png", Cloudinary.emptyMap());
432+
api.update((String) uploadResult.get("public_id"),
433+
Cloudinary.asMap("detection", "illegal"));
434+
} catch (Exception e) {
435+
assertTrue(e instanceof com.cloudinary.Api.BadRequest);
436+
assertTrue(e.getMessage().matches("^Illegal value(.*)"));
437+
}
438+
}
439+
440+
@Test
441+
public void testSimilaritySearchUpdate() {
442+
// should support requesting similarity search
443+
try {
444+
Map uploadResult = cloudinary.uploader().upload(
445+
"src/test/resources/logo.png", Cloudinary.emptyMap());
446+
api.update((String) uploadResult.get("public_id"),
447+
Cloudinary.asMap("similarity_search", "illegal"));
448+
} catch (Exception e) {
449+
assertTrue(e instanceof com.cloudinary.Api.BadRequest);
450+
assertTrue(e.getMessage().matches("^Illegal value(.*)"));
451+
}
452+
}
453+
454+
@Test
455+
public void testListByModerationUpdate() throws Exception {
456+
// "should support listing by moderation kind and value
457+
Map result1 = cloudinary.uploader().upload(
458+
"src/test/resources/logo.png",
459+
Cloudinary.asMap("moderation", "manual"));
460+
Map result2 = cloudinary.uploader().upload(
461+
"src/test/resources/logo.png",
462+
Cloudinary.asMap("moderation", "manual"));
463+
Map result3 = cloudinary.uploader().upload(
464+
"src/test/resources/logo.png",
465+
Cloudinary.asMap("moderation", "manual"));
466+
api.update((String) result1.get("public_id"),
467+
Cloudinary.asMap("moderation_status", "approved"));
468+
api.update((String) result2.get("public_id"),
469+
Cloudinary.asMap("moderation_status", "rejected"));
470+
Map approved = api.resourcesByModeration("manual", "approved",
471+
Cloudinary.asMap("max_results", 1000));
472+
Map rejected = api.resourcesByModeration("manual", "rejected",
473+
Cloudinary.asMap("max_results", 1000));
474+
Map pending = api.resourcesByModeration("manual", "pending",
475+
Cloudinary.asMap("max_results", 1000));
476+
assertNotNull(findByAttr((List<Map>) approved.get("resources"),
477+
"public_id", (String) result1.get("public_id")));
478+
assertNull(findByAttr((List<Map>) approved.get("resources"),
479+
"public_id", (String) result2.get("public_id")));
480+
assertNull(findByAttr((List<Map>) approved.get("resources"),
481+
"public_id", (String) result2.get("public_id")));
482+
assertNotNull(findByAttr((List<Map>) rejected.get("resources"),
483+
"public_id", (String) result2.get("public_id")));
484+
assertNull(findByAttr((List<Map>) rejected.get("resources"),
485+
"public_id", (String) result1.get("public_id")));
486+
assertNull(findByAttr((List<Map>) rejected.get("resources"),
487+
"public_id", (String) result3.get("public_id")));
488+
assertNotNull(findByAttr((List<Map>) pending.get("resources"),
489+
"public_id", (String) result3.get("public_id")));
490+
assertNull(findByAttr((List<Map>) pending.get("resources"),
491+
"public_id", (String) result1.get("public_id")));
492+
assertNull(findByAttr((List<Map>) pending.get("resources"),
493+
"public_id", (String) result2.get("public_id")));
494+
}
495+
496+
private void assertContains(Object object, Collection list) {
497+
assertTrue(list.contains(object));
498+
}
377499
}

0 commit comments

Comments
 (0)